Animals!

advertisement
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
Download