Project #4 Strategy

Intro

In "real world" code, it's more likely that you will have to work with pre-existing code. That means, you must spend time understanding how other people's code works. If the organization is good (i.e., they are experienced writing software), then the documentation for the code will be good. If you're working at some place that's, say, more research oriented, you may be working with some home-baked code, that's not documented at all, although you can ask the person how they wrote their code.

This should make you appreciate why people tell you to comment code. Notice that the code you've been provided is only lightly commented. That probably makes your life very tough. What should you do? Should you think "if they don't tell me how it works, then I shouldn't be forced to learn it"? Unfortunately, that's not the attitude that will lead you to a successful career.

To help you understand the idea, there once was a student (who's grades were OK, not spectacular, not bad) who was taking CMSC 424. The TA gave directions on how to install a server for a database. He was following the directions, and was unable to get it to work. So, what did he do? Did he email the TA and say "your stupid directions were wrong"? No.

Instead, he knew that other students had gotten it to work, so he began to investigate. He knew it wasn't completely broken, because a few things seemed to work. He tried to determine what was and what was not working. He ran some experiments, so that if he sent information to the TA, he could indicate what was going right and what wasn't.

He also read the files that were in the directory when the server was set up, to see if they had any meaningful information. He finally restarted the server on a different machine, and that worked.

This story is great because it shows the need for programmers to be resourceful, even when things aren't going so well. Have you ever seen students who seem to know what to do, and you're struggling? How do they do that? Some of that is just this kind of resourcefulness. Being able to learn how to make progress, even when you're confused is a very useful skill.

In this project, you were given code, with all sorts of strange things going on. Event driven programming? Listeners? Buttons? What are you supposed to do with all that? Yet, you were provided files, and those files are simply in C++. Worse gets to worse, you read the code, and you begin to trace.

You had input files, you had a project description. Try to follow what the code is doing. This means running it. This means putting your tracing skills to work. Add debugging statements, and see what happens. It may be weird, but when you're given little information, that's what you need to do.

One surprising thing you'll discover. It's unnecessary to know how everything works to write code. However, it does help to know a big picture of what's going on. This is not such a surprising idea. After all, do you have any idea how the input goes from the screen into your code? Do you have any idea how "cin" reads and parses your input? You may know exactly how it's implemented, but you do know what it's supposed to do, and that's good enough for you to begin programming.

Understanding Event Driven Programming

We're posting hints just in case you haven't had a chance to read the code and understand what's going on.

Basically, the idea for the project comes from two sources. First, is www.livejournal.com, which is a website where users can store and update "blogs" (weblogs) which are online journals or diaries.

The second, which is completely unrelated to the first, is Java graphical user interfaces. We're going to concentrate on the second.

In a GUI (graphical user interface), there are GUI components. These components are often called widgets. Examples of widgets include buttons, menu options, radio buttons, text fields, scrollbards, slider bars, etc. Anything you interact with in a GUI is considered a widget.

When you interact with a widget (for example, pressing a button) an "event" is generated. The "event" is handled by code that's called an "event handler". In Java, these event handlers are called listeners. We will emulate such listeners in C++.

While graphical libraries have been written for C++ (Visual C++ libraries, OpenGL, X Windows, etc), none of them are considered part of the language in the same way that Java's graphical libraries are considered part of Java. Also, X Windows is quite a bit more complicated than Java, even though it gives a lot of power too.

In any case, we couldn't easily grade a real GUI project even if we had such libraries. With a class this size, and with only a small number of graders, it would take too much time to get the project adequately graded.

Instead, we emulate GUI programming using text input (this is where you look at the simple text input provided in the posting account).

To make your life simple (and ours), there's only two widgets you work with: buttons and text fields. A button is something you "press". A text field is something you enter text in.

All of this is already taken care of by main() (although you may need to modify main() to produce the printed output required)

Here are the three commands in the input file.

The typical input file consists of a "user" inputting text using SET_TEXT and then pressing a button.

The input file is read in via main(). When SET_TEXT is read in, main() finds the "text field" object (see setText() in main()) and places the text in the widget. Setting text does not generate an event.

When QUIT is read in, the program exits.

When PRESS_BUTTON is read in (see pressButton()) the name of the button is passed to the event manager object by the method "generateAction()". This in turn calls runListeners() on the button object itself. Each button stores 0 or more listener objects. All listeners associated with the button have their action() method "run".

Each listener is an object with the method action(). So, runListeners() calls action on each listener object associated with the button. To associate a listener with a button, you must add the listener to the button (see later on for details).

Gui

Gui is where most of the stuff you write happens.

This class contains text fields and buttons. Right now, it only contains two Button pointers and one TextField pointer. All of these are just "test" buttons and text fields. You should replace them with the text fields and buttons specified elsewhere in the project.

The constructor for Gui is called early on in main(). In a real GUI application for Java, you would derive a class from Frame add Panels to the Frame and place various widgets in the panels. You would then add listeners to objects that produce events.

Similarly, in Gui you create the widgets in the constructor (see the Gui() constructor for an example). There are two kinds of widgets to create.

There are three ways to create a listener object.

ActionListener and Gui

The problem with a class derived from ActionListener is that you need information from the data members of Gui. You don't have that information in ActionListener. So how do you get that information to ActionListner? Pass a Gui object to it when you construct the action listener (there's an example, in the Gui constructor).

Here's how the constructor might look, with a parameter for passing Gui.

MyActionListener::MyActionListener( Gui * ptr )
{
   gui = ptr ; // gui is a data member of type Gui
}
Realize that Gui will need to have enough methods so that the action listener can update the Gui.

Adding your own objects to Gui

So far, all we've done is talk about the user interface. There are buttons and text fields and listeners. Given this, you could implement many different projects. What about the project you have to do?

You should add information in one of two ways. Either add data members to Gui, or create a DataManager and put your data members there (then put an instance in Gui). The first may be easier since there are limited data members.

What Classes to Write

Some of you are sitting down and wondering "what classes should I write"? You may be discovering that developing your own classes is not all that easy. The project is set up so that you don't need that many classes.

There are two main reasons why some of you may be afraid of writing classes. First, you just don't know how to start and what should happen. Second, you are afraid of making the wrong choices. The first reason is, of course, a big problem. If you don't know what's going on, it's hard to make progress. The second is less of a problem. Sure, everyone would like to save time by making the perfect decision the first time around. Everyone would like to avoid writing a class, and deciding that it was a bad way to write the class, so the entire work has to be scrapped and rewritten. Yet, that's one of the few ways you learn how to write code---by making mistakes. It's time consuming, it's frustrating, but it saves time later on (must later on, alas).

Here's a hint. First, you are writing journals and MP3s. What do they have in common? Date. So that should go into AbstractEntry. You should define relational operators for Date to compare them.

Second, you may want to have a Person. The person stores their name, alias, a list of AbstractEntry * objects (journals and MP3s), a list of friends, and their status (GOLD, SILVER, BRONZE).

Third, since there can be more than one person, you may wish to have some list (array list, sorted list, etc) in the Gui object as a data member.

That's all you really need.

But what strategy should you use, if you hadn't been given those hints? Suppose you had to do a different project altogether? For example, you want to do "instant messaging"?

The answer is to sit down and think about what actions are performed. What buttons will be pressed by the user? Pick a button, and decide what will happen when that button gets pressed. Ask the following questions:

Try to detail out the steps of what will happen. This may help you decide what objects to create.

Designing Classes

A common mistake made by beginners who design classes is to try to make their lives easy. This means doing things like: As you are designing classes, a good exercise is to think about "actors" and "actions". What are the "actors" and what actions do they perform? So, in this case, we have a person, who wishes to add journal entries. Where are the journal entries stored? How are they stored?

This forces you to think about what data structure to use. You may think "I don't know", then pick something simple like an array, and work from there. What information should go in a "journal" object? Put the minimum you need now, and add more later.

When you look at the class you've written, start to ask yourself, "Could I use this class in a different situation? If I gave this class and had to "sell" it, would anyone buy it?". For example, is it important to have relational operators? How about print methods? How about input methods?

Here's a good example. Suppose you are writing a string class. The current project says you need to determine whether a string is a palindrome. Should the string class have an isPalindrome() method. You might say "yes" because the project needs it, but in general, does anyone need that method? You might say "yes, it's possible they will need it". However, if you add every possible method a user might need, you will have thousands of methods, which makes the class very difficult to use.

Instead, you should leave out this function, and if you REALLY need it, use inheritance, and add a isPalindrome method there, for special purpose uses.

Restrictions

Do not use STL in the project (except for strings). Since this is a culmination of previous work, just use ArrayList, SortedList, BstSortedList and any old code you may have written or that was provided to you by the instructors.

Web Accessibility