C++ AWT Project Stages and Reminders
1. Implement a generic Component class. Components need methods that allow the programmer to specify their sizes, positions, and text contents. They should be capable of drawing themselves when required so to do.
2. Implement a Window class. A window should have constructors and/or methods that allow the programmer to specify its size, and to add components to it. The first time a window is drawn, a real window should be created. Every time a window is drawn, all the components within it should also be drawn in their sizes and correct positions.
3. Every time something happens that changes the size or position of a component, the whole window containing it, and all its co-contents will have to be redrawn: the resizing may occlude or reveal other components.
Just as Windows have to record which Components are inside them, you’ll find that components have to record which window they are inside.
4. Create some less generic sub-classes of the Component class, representing Labels, Buttons, Test Fields, and what-have-you.
5. Make your components work out their own sizes based on their contents. Of course, the user should still be allowed to override the automatic size with a SetSize method or something like that, but automatic sizing should be the default.
Remember that changing the contents of a component may (not necessarily will) make the component’s size change.
6. Positioning of a lot of components inside a window will become quite cumbersome; some grouping construct is required. A Panel is a special kind of component: it is usually invisible itself, but contains other components just like a window does. When a Panel is drawn, all the components within it are drawn in their correct positions relative to the position of the panel.
Thus, a group of related components may be positioned correctly within a Panel, then the panel can be correctly positioned within the window (or perhaps within another panel), carrying all the contained components with it.
Implement a Panel class, avoiding unnecessarily repeated code by realising that a Window is really a special kind of Panel that isn’t contained inside anything else.
7. Make your components react appropriately to mouse clicks within their borders. The best method is to make the window itself responsible for catching mouse events, then finding out which of their contained components’ borders the mouse position falls within, and giving the signal to the appropriate component. Remember, some components are not supposed to react to the mouse.
8. Make your components react appropriately to keyboard keypresses. The usual idea is that the last component to have received a mouse-click has the “keyboard focus”. All keypresses are sent to whichever component has the focus at the time. Some components do not react to keyboard events, but others do, in different ways.
If enter is pressed when a button has the focus, it is traditionally accepted as equivalent to a mouse-click on that button. If a Text Field that has user input enabled receives a keypress, the character typed becomes part of its displayed text content.
9. Allow the programmer to specify an action that should be taken when a keypress or mouse click is received. Perhaps by providing “call-back” functions or objects, or perhaps by a means of your own devising.
10. Working out the exact positions that make components look good within their window can be very annoyingly time-consuming. The process can be automated by inventing a kind of Panel that automatically positions any component added to it.
Perhaps one setting for a panel makes it place each component to the right of the previous one (like a FlowLayout in java), with a little spacing that can be set by the programmer. Another might place each component vertically below the previous one. Another might line up all its contents in neat rows and columns (like a GridLayout in java).
Think of layout schemes that would be helpful in producing a good-looking display; don’t just follow my suggestions.
11. Decide what should happen when one or more of the components within an auto-formatting panel changes its size. It seems that all its friends and neighbours might have to move to new automatic positions, and maybe even get resized. Decide on a reasonable policy and make it happen.
12. It is also possible that the user will change the size of the whole window by mouse-dragging a corner or edge. That may need to have a significant effect on the components inside the window, depending upon what kinds of panels they are inside.
13. Make the whole thing into a conveniently usable library of classes. At any time in the future if you want to write an official-looking windows application you should be able to include your object library and use it without any hassles or loud swearing. In other words, not really very much like java at all!
14. Try to make it look good. Fake 3-D shading and all-round professional-looking components are quite easy if you put a little design effort into it. Perhaps it would be worth looking at an enlarged picture of a real GUI’s buttons.
Mouse and Keyboard and Other Events
Look at the subsection headed “Events: mouse, keyboard, window, timer” in the library documentation file:
http://rabbit.eng.miami.edu/class/library/win/graphics.html
you will almost certainly find that the functions CheckKeyPressed, CheckInputReady, and so on in the following section are not flexible enough. Catching the event notifications is the way to go.
Graphic Images
If you want components that contain graphics instead of (or as
well as) text, look at “Support for .BMP files”. I’m hoping to find time to
add support for .GIF
files and the other more popular formats before too long, but don’t hold your
breath.
Accurate Text Rendering
Look at the subsection headed “Displaying Text”, it will
tell you how to measure text and see how many pixels high and wide it will be
when rendered, and how to change fonts and things like that.
Background Processing
It is very annoying that a program has to spend all its time
waiting for keyboard and mouse events; that leaves no time for useful
computations. To overcome this limitation of the “Event Loop”
programming style, you can perform all the event processing in a background
sub-process, or more probably a background Thread. To find out how, read
the section headed “Threads”, and make absolutely sure you also read the
following section on “Semaphores”; if you don’t use semaphores in a
threaded program all sorts of surprising things go wrong.
Multiple Windows
If you create an object of type XFrame, a new window will appear. All the
standard graphics functions (MoveTo, DrawLine, etc) also exist as methods of
the XFrame
class. The constructor for an XFrame
has 5 useful parameters: (int
x, int y, char *label, int w, int h); x,y are the windows position on the
screen, label is what appears in
its drag bar, and w,h are its
size. You can look inside library.h
for details. I do not recommend you waste any time looking inside library.cpp.
Minor Note
When using library.h,
the way for a program to stop itself voluntarily is with the Exit function, not
the usual exit
function. That isn’t a typo, I’m saying that Exit should be typed with a capital E, which is not the
normal C way. Exit
takes an optional int
parameter to specify the exit status code, but it is ignored.