300 likes | 464 Views
Designing the Animals! Game. Designing the GUI. I like to start with the design of the GUI In an important sense, what the user sees is what the program does
E N D
Designing the GUI • I like to start with the design of the GUI • In an important sense, what the user sees is what the program does • If you write the model (the “working part”) of the program first, it’s hard to keep from contaminating the user interface with implementation details • For example, your model may need to be “reset” to start guessing another animal • There is absolutely no reason the user should see a Reset button
What the GUI should do • Here’s what I think the GUI should do: • Present a welcome message when the program starts • Ask the user yes/no questions about the animal • I think there should be Yes and No buttons--why make the user type in these words? • Make a guess and ask for confirmation • If yes, print a “brag” message • If no, ask the user to type in a question, and ask for the yes/no answer to that question; then print a “thanks” message • Ask if the user wants to play again (Yes or No) • Oh, yes--the GUI should display my name
What the GUI needs • It needs to display my name--a Label is the obvious choice for this • It needs a text area to display its questions • The user should not be able to edit this area (why?) • It needs Yes and No buttons • It needs a text area for the user to type in a new question • The user should not be able to edit this area except when asked to type in a question (why?) • Similarly, the Yes and No buttons should be disabled when the user is typing in a question (why?)
TextArea or TextField? • The user might want to type in a fairly long question • TextFields are bad for this--you might have to scroll sideways, and that’s always unpleasant • If we use a TextArea for letting the user enter the question, we should also use one for displaying the question later • If we use a TextArea, should we display all questions (and answers), or just the current question? • The former might be interesting, but • The latter is less confusing • OK, maybe not much less--but I still like it better
GUI arrangement • My name should be discreet and out of the way • Top or bottom is good; I think I prefer the bottom, and maybe in a smaller font • Yes/No buttons should be immediately after the question, with nothing in between • On the other hand, it would be nice if the user text area were also immediately after the request for a question • Maybe we can put these side-by-side • If we stack the Yes/No buttons vertically, that gives more room for the user to enter a question • But I don’t like that--it doesn’t seem as natural
Does it live in the water? Enter your question here: Yes No Program by David Matuszek The final GUI design
Entering questions • The obvious (and easy) thing to do is to consider a question completed when the user hits Enter • However, some users will automatically hit Enter when they reach the right edge of the text area • This gives an incomplete question with no way to recover--very frustrating for the user! • Should we have a “Try again” button? • A better solution: listen for Enter and then look for a question mark • But some users will forget to type a question mark • However, if we see Enter with no question mark, we can remind them
Quitting I • The only way to quit is to answer “No” to “Would you like to play again?” • This doesn’t seem friendly • A Quit button would clutter up the interface and get in the way, and would probably never be used • A Quit menu item would be out of the way, and seems like the best solution • However, games are short, and having two separate ways to quit may make the user think they do something different • I decided not to have a second way to quit
Quitting II • Two problems: • The user has been clicking Yes and No all along, and suddenly No means something different--it means “Quit” • Solution: temporarily change the label on the button to read “Quit” • When the user clicks “Quit,” the program vanishes • This isn’t friendly--it ought to say goodbye • Solution: Display a goodbye message, and pause briefly (2 or 3 seconds?) before actually quitting
User friendliness • Did you think of all these issues? • Did I miss anything? • Probably. The best answer to this: user testing! • The Macintosh is renowned for its user friendliness • UNIX is renowned for its user unfriendliness • Linux with Gnome is a good start in the right direction • Windows is somewhere in between • In my opinion: • It’s amazing what people will learn to put up with!
Choosing classes • It’s part of the assignment requirements that we have a binary tree class (or classes) • Binary trees should be strictly independent of the rest of the program; we only use them • They should be very general and not have special features for this particular assignment • How about the model (the part that does the work) and the GUI? • There is no reason the model should know about the GUI--it should supply an API useable by any interface • The GUI does need to know about the model • It does not need to know about binary trees
GUI Model BinaryTree uses uses Preliminary class design • We might decide, as we program this, that we need some small “helper” classes • This, however, is the main design
The Model API • We need to be able to: • Tell the model to initialize itself--in particular, it may need to read in a data file • Tell the model to start with a new animal • Get a question from the model • Give an answer to the model • Get a guess from the model • Give a new question to the model • Tell the model to finish up • Notice that none of this mentions a binary tree--that’s in the implementation of the model
Initializing • To keep from asking the user pointless questions, the program should keep its data in a known location--a file animals.dat in the same directory • The program should start by reading in this file • What if the file isn’t there? • Best solution: create one; should be very minimal • Easy way to do this: create a default binary tree, with one animal, or with one question and two animals • The file will not actually be created until the program quits and writes out the new binary tree (which it has to do anyway)
Finishing up • We need to replace the old file with the new one • There is a simple way to safely replace a file: • Rename the original file to be a backup file • Write out the new file with the original name • If desired, delete the backup file • Even if the power goes out halfway through, you always have at least the old file • We won’t bother with this, because our data is hardly critical • Apparently, the people who programmed Forté felt the same way about your program files
Getting questions • We repeatedly get a question from the model, and give the model a yes or no answer • Problem: when are we done? • We need to know because: • We may need to allow a new animal to be entered • We may need to allow a new question to be entered • We may want to change the No button to a Quit button • We need to get both a text message and a flag • But a method can only return one value • That value could be a new class with two fields • That’s ugly!
Getting questions II • An alternative to getting two pieces of information from one method is to call two separate methods • This seemed very awkward • While I was struggling to make this less awkward, I suddenly realized: • This is like an iterator! • So here are my methods: • boolean hasMoreQuestions() • String nextQuestion() • However, playing around with this, I realized that it isn’t obvious which question is the last one
no yes I know! Is your animal a frog? So guess = last question yes no See? People should work,computers should think!Would you like to playagain? Oh, well. What animal were you thinking of ? This is where we have to start doing something different The last question Does it live in the water?
Learning a new animal • The model should supply the questions--that’s not the job of the GUI • Therefore, • The GUI asks the model for the question about the name of the animal • The GUI tells the model the answer • The GUI asks the model for the question that asks the user to enter a question • The GUI tells the model the answer • The GUI asks the model for the question about which is the right answer for this animal • The GUI tells the model the answer • Is there any way to clean up this sequence?
Learning a new animal • The final sequence--either asking for a new game, or asking about a new animal--should really be under the control of the model, not the GUI • I haven’t set it up that way • Putting the computer in control, rather than the user? That’s old style programming! • Well...Animals! is an old program....
Refactoring • Refactoring is redoing the design of existing code when you see a better design • Refactoring almost always: • Is more work in the short run • Saves a lot of time and trouble in the long run • In short, refactoring is almost always worth the trouble • In this case, I haven’t even begun to write the code!
A 180° turn • With the model in charge: • Create the GUI • Ask the user if s/he wants to play, get back a boolean • Ask the user a question, get back a boolean • These could be combined, except for changing the label on the No/Quit button • But that could easily be a parameter • Ask the user for a new animal, get back a String • Ask the user for a new question, get back a String • These can certainly be combined into a single method
The GUI API new Gui() boolean yesOrNo(String question, String label) String getText(String question) • Now this is simple! • The GUI design doesn’t have to change • What do we have to give up? • Well, I had this really cool idea about an iterator....
Old: GUI Model BinaryTree uses uses GUI Model BinaryTree uses uses New: Final class design • Instead of GUI uses Model, we now have Model uses GUI
A little problem.... • With this design, the model sends a question to the GUI, and gets back an answer from the user • I suddenly realized.... • I have no idea how to do this! • Java GUIs are designed around an event loop, which puts the user, not the program, in control • This is so fundamental that I’ve never done it the old way around in Java • So what are my alternatives? • Go back to my original, less desirable design, or • Figure out how to do this in Java
A bit about Threads • A Thread is an independent sequence of execution • I knew that the GUI runs in a separate Thread • If I could make the model’s Thread wait for a response from the GUI’s Thread, I could make this work • I found a wait() method, but using it gave me an IllegalMonitorStateException • A quick web search (on java thread tutorial) brought me to Sun’s Thread trail, and in half an hour I had it figured out (and tested in another half an hour)
A short sermon • Unfortunately, I can’t teach you everything you need to know • I don’t know everything you need to know • I haven’t had time to teach you about Threads • You don’t need to know about Threads in order to do this assignment • This is a field where you can never stop learning • Knowing how to find out things is at least as important as knowing things • I’ve had a link to Sun’s “trails” posted on my web page ever since the semester began--ever look at it?
Design of the model • The model is the part of the program that does the “actual work” • In this program, there is almost nothing to design--the conversational structure tells it all • Walk the binary tree • Ask yes/no questions • If at a leaf, make a guess • If the guess is wrong, go through a conversational sequence to add a question and a new leaf to the tree • Repeat as needed • I’ll probably do this in a single method