[<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]
You've seen two versions of a browse application, largely
introduced as finished programs and explained "after the
design". It's time to do things "the right way around":
starting with the design and ending with the code.
In one sense, the opposite of browsing is data input, so let's
develop a data entry application. It's a simple example, to
avoid getting bogged down in the details, but let's start with
the MDI case - removing code to make an SDI version is trivial.
Even though it's a simple example, the thought-processes
involved in OOA/D are explored in a lot of detail. You won't
need so much detail once you're familiar with what's involved,
but here it's going to be stressed in the hope that you can
refer to it if/when you hit problems during future designs. A
number of the steps produce very much the same results (e.g.
candidate classes), but sometimes you find some new detail
that justifies the repetition. By way of an example, some of
the steps below omit things they should include, which are
identified in other steps (see if you can spot them). This
reflects the actual results obtained.
Here's a simple requirements specification: Produce an MDI
application to maintain the "Departmental 'Phone File"
(USERS.DBF) which is shipped with Clip-4-Win.
There's more than one way you can proceed. Here are two paths
(A and B) which are often performed in parallel.
Path A
======
You may find it helpful to identify the inputs, outputs,
physical/conceptual things, responses, and services used and
provided.
Inputs: the USERS.DBF file, user menu choices (by mouse,
keyboard, or even pen), user data entry.
Outputs: updates to the USERS file.
Physical/conceptual things: application, main window, menus,
USERS file, the form.
Responses: the user interface: the main window, menu changes
as the user chooses, the data entry form(s). Note: you could
list these under Outputs.
Services used: none identified so far (unspecified parts of
the Clip-4-Win Application Classes).
Services provided: none identified so far.
Path B
======
A bit of thought, drawing diagrams, etc., should get you
something like this:
(a) The application is a kind of MDI application.
(b) The application has a main window.
(c) The main window has a (bar) menu.
(d) The bar menu consists of popup menus and menu items.
(e) The menu contains an item to allow a data entry form for
the USERS file to be started, as well as standard items
expected of Windows applications.
(f) The main window has a status (message) bar. (Optional.)
(g) More than one form can be active at a time.
(h) The form contains input fields for the fields in the USERS file.
In practice, to allow for input errors you don't want to
update the file immediately data is entered, so some buffering
will be needed. (In DOS Clipper applications you've no doubt
done this many times, using LOCAL or STATIC variables.)
To reduce the amount of repetitive code, this example only
deals with editing existing records, but in a real application
you'd want to add/delete records as well. Also, to keep this
example reasonably simple, you can only move through the file
using Next/Previous buttons.
Item (h) had better change to:
(h) The form contains:
- input fields for the fields in the USERS file
- buttons for Ok / Cancel
- buttons for Next / Previous / Save
Here are possible names for classes involved with the above
items:
(a) UsersApp
(b) UsersWindow (or MainWindow)
(c), (d), (e) The Clip-4-Win menu classes; (e) also refers to
UsersForm
(f) WStatusBar
(g) UsersForm
(h) UsersForm, maybe a class for each field, a class for the
file (UsersTable), maybe classes for the buttons
You can identify some responsibilities:
- something (S1) has to perform input validation
- something (S2) has to read the USERS file
- something (S3) has to update the USERS file
- one or more somethings (S4n) have to co-ordinate the
form's/file's fields
- several somethings (S5n) have to respond to button pushes
Let's re-visit services used and provided.
Services used: the app uses the main window; the main window
uses the menu, status bar, and form; the form uses the input
fields and buttons; one or more things use the USERS file.
Services provided: convenient, encapsulated access to:
windows; menus; status bar; the form; input fields; data
validation; buttons; the USERS file.
To pin down the "somethings" (S1, ..., S5n) above, you need to
know about handling forms in general.
Forms are usually implemented using dialogs, for a number of
reasons: they can be designed easily using a resource editor
(such as the one contained in the Clip-4-Win Toolkit); they
provide convenient behaviour with which users are familiar;
they automatically size themselves based on screen resolution.
Clip-4-Win provides many dialog-related features for these
reasons.
Dialogs are actually windows with extra behaviour, so you can
use functions relating to windows on dialogs as well. Because
of the relationship between windows and dialogs, Clip-4-Win's
WDialog class is derived from a window class (WWindowBase).
At first sight, the following fact is a problem: a few of the
functions that work on dialogs can also be used on non-dialog
windows. However, the real problem is that the functions have
been misnamed! They were clearly implemented for use with
dialogs and were named because of that, even though they are
more general purpose.
Dialogs and other windows can contain controls, which are
themselves kinds of windows. Controls include text, (push)
buttons, radio buttons, check boxes, list boxes, and so on.
You have two fundamental choices, which can be summarised as:
"dumb forms with smart controls"
or
"smart forms with dumb controls".
Arguably, Windows uses "smart forms with dumb controls";
certainly, Clip-4-Win does. One result is that any
complications become part of the form, allowing them to be
centralised nicely in many cases. Centralised code is usually
easier to write, understand, and maintain, so this is a useful
benefit, whereas having smart controls too often means
scattered logic. Naturally, the form can make use of any
intelligence the controls possess - the form can just delegate
its responsibility.
Validation can be a problem in a GUI environment, because
users are allowed to complete a form in almost any order.
Your best defence is to do only simple validation on each
field as it's entered, leaving full validation until the user
indicates the form is supposed to be complete.
Based on the above, you might reasonably decide to do the
following:
S1 (input validation): a picture per input field, full
validation done by the form
S2 (read the USERS file): requested by the form
S3 (update the USERS file): requested by the form
S4n (co-ordinate the form's/file's fields): done by the form
S5n (respond to button pushes): done by the form
The provisional list of classes so far is UsersApp,
UsersWindow, menus, UsersForm, WStatusBar, data input
class(es), UsersTable, and buttons. Are they all good
classes? You may not be too sure as yet whether they have
well-defined boundaries. Each class is going to be used in
the guise of one or more objects, so you have to check that
each object would have both permanence and identity. Nothing
looks clearly wrong, so let's continue by going into more
detail:
UsersApp:
uses (owns) the UsersWindow object
creates the UsersWindow object
UsersWindow:
owns the WStatusBar object
creates the WStatusBar object
owns the bar menu object
creates the bar menu object
owns the UserForm object(s)
creates the UsersForm object(s)
bar menu:
has zero or more menu item objects
has zero or more popup menu objects
popup menu:
has zero or more menu item objects
has zero or more popup menu objects
menu item:
has zero or one method name to invoke if chosen
has zero or one code block to run if chosen
has zero or one help object
UsersForm:
owns the UsersTable object
creates the UsersTable object
reads data using the UsersTable object
writes data using the UsersTable object
moves from record to record using the UsersTable object
has data input field objects
creates data input field objects
gets data from data input field objects (to write using
UsersTable)
changes data in data input field objects (on moving records)
has buttons for Ok, Cancel, Next, Previous, Save
has methods for the buttons: Ok, Cancel, Next, Previous, Save
WStatusBar:
has status text
displays the status text
data input field:
has data
has a picture
has methods to get, set and update the data
UsersTable:
has a file name
has a work area number
has an alias
selects a unique (new) work area
opens the file in the work area
button:
informs the UsersForm if pushed (clicked)
This is just the sort of information designed to be put on CRC
cards, which is why they're so useful.
Now you've got a simple model of the application, but does it
work? Check its life-cycle, its inputs, outputs and
responses:
Initialisation:
the UsersApp object needs to be created
UsersApp creates the UsersWindow object
UsersWindow creates its menu object
UsersWindow creates its status bar object
UsersApp starts processing user inputs
User chooses the menu item to edit a record:
the menu item invokes a method in the UsersWindow object
UsersWindow creates a UsersForm object
UsersForm creates a UsersTable object
UsersTable finds an unused work area
UsersTable creates a unique alias
UsersTable opens the USERS file
UsersForm creates and initialises the data input field objects
UsersForm creates the buttons
UsersForm displays itself
UsersForm starts processing user inputs
User pushes (clicks on) the Save button:
the button informs UsersForm
UsersForm performs validation
if valid, UsersForm uses UsersTable to update the USERS file
User pushes (clicks on) the Ok button:
the button informs UsersForm
UsersForm tells the UsersTable object to terminate
UsersForm terminates itself
User pushes (clicks on) the Cancel button:
same as the Ok button
User pushes (clicks on) the Next button:
the button informs UsersForm
UsersForm uses UsersTable to move to the next record
UsersForm updates the data input field objects for the new record
User pushes (clicks on) the Previous button:
like the Next button, but in the opposite direction
User wants to exit:
UsersWindow tells any UsersForm objects to terminate
UsersForm objects tell their UsersTable objects to terminate
UsersWindow tells the UsersApp object to terminate
UsersApp cleans up
UsersApp exits to the operating system
You would need to add anything in the above that wasn't already
on your CRC cards.
Turning to Clip-4-Win's Application Classes, what is there that
can help? You might tentatively suggest:
UsersApp: is a kind of MDI application
inherits WMDIApp
UsersWindow: is a kind of MDI main window
inherits WMDIFrame
menus: use the menuing commands
could inherit WMenu, but can use it as it is
could inherit WPopup, but can use it as it is
could inherit WMenuItem, but can use it as it is
UsersForm: is a kind of form (dialog)
inherits WDialog
status bar:
could inherit WStatusBar, but can use it as it is
data input field:
could inherit WGet, but can use it as it is
UsersTable:
could inherit WTable, but can use it as it is
button:
could inherit WPushButton, but can use it as it is
Yet again, you could update your CRC cards.
You can now readily check that these are good classes: they
have well-defined boundaries and any objects have permanence
and identity.
With the detail above, writing the code is mostly very
straightforward. Rather than list it all here, two versions
are shipped with Clip-4-Win. There are two so that you have
one that works if you don't have a resource compiler and one
that takes advantage of resources. The files are under the
SOURCE\OO directory as USERS\USERSMDI.PRG and
USERSRES\USERSMDI.PRG. Explanations of the most important
pieces follow, but first some general information.
Online resources provided by: http://www.ClipX.Net --- NG 2 HTML conversion by Dave Pearson