![]() |
Introduction to PM ProgrammingWritten by Larry Salomon, Jr. |
IntroductionThe purpose of this column is to provide the readers out there who are not familiar with PM application development the information necessary to satisfy their curiosity, educate themselves, and give them an advantage over the documentation supplied by IBM. Of course, much of this stuff could probably be found in one of the many books out there, but the problem with books in general is that they don't answer the questions you have after you read the book the first time through. I will gladly entertain feedback from the readers about what was "glossed
over" or what was detailed well, what tangential topics need to be covered
and what superfluous crap should have been removed. This feedback is
essential in guaranteeing that you get what you pay for. It should be said that you must not depend solely on this column to teach
you how to develop PM applications; instead, this should be viewed as a
supplement to your other information storehouses (books, the network
conferences, etc.). Because this column must take a general approach,
there will be some topics that you would like to see discussed that really
do not belong here. Specific questions can be directed to me via email and
I will do my best to answer them in a timely fashion.
Last month we began looking at the menu control, which we will continue
with this month.
Before we may continue, we should take a brief look at the typical use of a
menu control, from the programmer's perspective. This involves the
definitions of the manifest constants, the menu template definition, the
"loading" of the menu (you'll see why "loading" is in quotes in a minute),
and the processing of the user's actions. We're taking this different
approach to looking at the window class because - as we stated last month -
the menu provides the most widely used functionality of any of the window
classes; as such, you'll need to know how to use it because you'll be
writing this code more times than any other.
Manifest constants - a.k.a. #define's - are a convenient language element
which allow us to use a "name" in place of something else. For menus, the
"something else" is a number which represents an identifier unique to that
menu template. You'll find that in larger applications that the file
containing these constants can grow quite large, so it would be helpful if,
at a glance, you could determine the use of the constant from looking at
its name. To accomplish this, I defined a naming convention. You can use
this one or your own - it doesn't matter. What does matter is that you
spend less time trying to find out how a constant is used and more time on
actually using the constant. For menus, I use the following:
The constants that are used for resource definitions I keep in a separate
file to allow me to make the file a dependancy of all files that use
resources. This is simply a suggestion.
Under Windows, there is App Studio which allows you to define and maintain
all of your resources. How come there isn't something like this for OS/2?
Regardless, you have to design your menus "blind," meaning that you can't
see the result until you actually use the menu you've built.
As it is with writing applications, designing your menu layout should be
the most important action; a confusing or deep (i.e. many pullrights) menu
structure will often confuse the user and turn them away from using your
application. Group the items in submenus in a logical fashion so that the
user can "take a guess" at where to look when trying to execute a
particular action.
IBM's "Common User Access" (CUA) guidelines define a number of pulldown
menus and a (non-inclusive) list of what they should contain. I've
included a brief list of these (since I cannot find my CUA book Another important CUA note is the use of the ellipsis and bang punctuation
marks on text. An ellipsis should be appended to menu item text when
selecting the menu item results in a dialog being displayed. A bang should
be appended to text belonging to items on the action bar (note that this
therefore excludes pullrights and any popup menu items) when selecting them
does not display a pulldown menu (i.e. when it is a leaf-node). These are
used as feedback indicators to the user to alert them about the behavior of
the application without having them find out "the hard way."
Loading a menu usually involves the setting of a flag only. No explicit
loading is usually performed by the application code. (Popup menus are the
exception to this rule, since the current CUA specification eliminates
action bars.) In the call to WinCreateStdWindow(), simply include FCF_MENU
on the set of flags passed (by reference) as the third parameter.
It has been stated before in this column (I hope) that, when using
FCF_MENU, FCF_ICON, or FCF_ACCELTABLE that the eighth parameter must
specify the resource identifier of the resources corresponding to these
flags. Since we specified FCF_MENU, we should have a menu template defined
that begins with:
If we do not have this defined, the WinCreateStdWindow() function will
fail. A useful note here is that, as each component of the window
specified in ulCreate is successfully created, the corresponding bit in
ulCreate is set to 0. So, the components that were not created successfully
can be determined by examining ulCreate after the function fails.
Now we learn how to utilize the menu in our application code. There are
usually two messages that we will be interested in when coding our
application: WM_INITMENU and WM_COMMAND. Note that, if any MENUITEMs have
the MIS_SYSCOMMAND or MIS_HELP style, we will need to add the WM_SYSCOMMAND
and WM_HELP messages to this list, but for the moment we'll assume that we
have none with these menu item styles.
WM_INITMENU is sent to the client window whenever a menu or submenu is
about to be used by the user, e.g. when the user presses F10 to get to the
action bar, when the user clicks on a pulldown menu to display the
pulldown, etc. Intercepting this message allows us to dynamically enable
or disable menu items according to the state of our application. For
example, if the user selects the "Print" menuitem, you might want to
disable the "Exit" menuitem until printing is completed. We will see later
how to change menuitem attributes.
SHORT1FROMMP(mpParm1) specifies the identifier of the menu. If the
actionbar is the cause of the message, this will be FID_MENU; otherwise, it
will be the identifier you specified on the SUBMENU statement in the menu
template.
HWNDFROMMP(mpParm2) is the handle of the window corresponding to the
identifier. You should know that pulldown and pullright menus are actually
separate windows which belong to something called an "object" window when
not in use. When you click on a pulldown, the appropriate window is
retrieved from the object window and displayed on the desktop. This window
handle is needed to send messages to the menu.
WM_COMMAND, WM_SYSCOMMAND, and WM_HELP are all sent whenever the user
selects a menuitem with the corresponding style. This is your indicator
that the user wants something done and that you are to process this
request.
SHORT1FROMMP(mpParm1) specifies the identifier of the menuitem selected.
SHORT1FROMMP(mpParm2) specifies the source of the message and will always
be CMDSRC_MENU when this message is sent via a menu control.
SHORT2FROMMP(mpParm2) is TRUE if this message was sent as the result of a
mouse action or FALSE if sent as the result of a keyboard action.
Next month we'll start to look at a sample application that uses the menu
control, and we'll begin to look at the MM_ message family which allows you
to interact with the menu control. As always, feedback will be enjoyed
immensely; send any comments, suggestions, etc. to os2man@panix.com.
|