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 • 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 The final GUI design Does it live in the water? Enter your question here: Program by David Matuszek Yes No 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 Preliminary class design GUI uses Model uses Binary Tree • 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: 1. Rename the original file to be a backup file 2. Write out the new file with the original name 3. 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 The last question Does it live in the water? no yes I know! Is your animal a frog? yes See? People should work, computers should think! Would you like to play again? no So guess = last question Oh, well. What animal were you thinking of ? This is where we have to start doing something different 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.... Final class design Old: GUI New: GUI uses uses Model Model uses Binary Tree uses Binary Tree • 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 The End