Version 5 of the Hello World application shows you how to add the following:
The main window for version 5 of the Hello World application looks like this:
The following files contain the code used to create version 5:
File | Type of Code | |
---|---|---|
ahellow5.cpp | Source code for main procedure and AHelloWindow class | |
ahellow5.hpp | Class header file for AHelloWindow | |
ahellow5.h | Symbolic definitions file shared by all source files | |
adialog5.cpp | Source code for the ATextDialog class | |
adialog5.hpp | Class header file for ATextDialog | |
aearthw5.cpp | Source code for the AEarthWindow class | |
aearthw5.hpp | Class header file for AEarthWindow | |
ahellow5.rc | Resource file source | |
ahellow5.ico | Icon file | |
ahellow6.rtf and ahello6.hpj | Help source files for Windows help | |
ahello6.ipf | IPF help source files |
The ahellow5.cpp file contains the source code for the main procedure and AHelloWindow class functions. The tasks performed by this code are described in the following sections.
The AHelloWindow Class Header File
The ahellow5.hpp file contains the class definition and interface specifications for the AHelloWindow class, with a few modifications for version 5.
The ahellow5.h file contains the symbolic definitions for this application. These symbols and their definitions provide the IDs for the application window components.
The adialog5.cpp file contains the source code for the ATextDialog class, modified for help in version 5.
The adialog5.hpp file contains the class definition and interface specifications for the ATextDialog class. The adialog5.hpp file is the same as the adialog4.cpp file.
The aearthw5.cpp file contains the source code for the Earth window graphic that is drawn using native-system graphics calls.
The aearthw5.hpp file contains the class definition and interface specifications for the AEarthWindow class.
Version 5 of the Hello World application provides a resource file, ahellow5.rc, which contains all the resources from version 4, as well as additional resources, including a help table.
The ahellow5.ico file is used as the icon that displays when the application is minimized. This icon is the same as for
The ahellow5.ipf file contains the text and IPF or RTF tags used to produce the help information for the Hello World application. IPF uses a tag language to format the text that appears in a help window. For example, :p. is the paragraph tag, which you use to start a new paragraph.
The OS/2 makefiles provided with Hello World version 5 use the
IPFC compiler, provided by the OS/2 Developer's Toolkit, to
compile the help file.
Refer to the OS/2 Information Presentation Facility Guide and Reference or the IPF Information Presentation Facility User and Programmer's Guide for descriptions of other tags used in the help source file.
The makefiles provided with Hello World version 5 use the
native Windows help compiler, by default, which uses Rich Text
Format (RTF). You can also use IPFC/X compiler to compile the
help file by specifying nmake USE_IPF=1 for the
makefile.
A sample file, ahellow5.rtf is provided with the Hello World version 5. The following code is taken from the ahellow5.rtf file:
{\rtf1\ansi \deff2 {\fonttbl{\f0\froman Tms Rmn;}{\f1\fdecor Symbol;}{\f2\fswiss Helv;}{\f3\fmodern pica;}{\f4\fmodern Courier;}{\f5\fswiss Univers (WN);}} {\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0; \red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue127;\red0\green127\blue127;\red0\green127\blue0;\red127\green0\blue127;\red127\green0\blue0;\red127\green127\blue0;\red127\green127\blue127; \red192\green192\blue192;} \sectd \pard \f2 \fs20 ${\footnote Table of Contents} #{\footnote IPFToRTFContents}\par \b {\fs28 Table of Contents:}\b0 \par \ri90\qr{\uldb Index}{\v IPFToRTFIndex}\par \ri0\ql \par\li360\fi-180 {\uldb C++ Hello World - Application Help} \par\li720\fi-180 {\uldb C++ Hello World - Main Window Help}{\v 100} \page \li0 ${\footnote C++ Hello World - Application Help}\par \pard \cf1 \f2 \fs28 \tx0 \b C++ Hello World - Application Help\b0 \par \pard \fs20 \par \pard \li0 \fi0 \tx0 This file contains the help for the C++ Hello World Application. \par \pard \page \li0 ${\footnote C++ Hello World - Main Window Help} #{\footnote 100}\par \pard \cf1 \f2 \fs28 \tx0 \b C++ Hello World - Main Window Help\b0 \par \pard \fs20 {K{\footnote ;main window help}}\par \pard \li0 \fi0 \tx0 This is the help panel for the main window. The main window contains the following areas: \par \pard \par \li270 \fi-270 {\f1 \'B7} The title bar icon, which provides access to the system menu \par \par \li270 \fi-270 {\f1 \'B7} The window title, which displays the title of the window \par \par \li270 \fi-270 {\f1 \'B7} The menu bar, which allows the user to select specific actions \par \par \li270 \fi-270 {\f1 \'B7} A status line, which contains the current alignment \par \par \li270 \fi-270 {\f1 \'B7} A client area, which is divided into three areas:
You also need a project file (.HPJ) which is used by the Windows Help Compiler (HCW or HC31) to create the .HLP file.
The following sections describe each of the tasks performed by version 5 of the Hello World application that were not described for previous versions.
In previous versions of the Hello World application, the client window contained a simple static text window. Version 5 provides an sample of a client window with three visible windows:
The two new windows are described in detail in later sections of this chapter.
Use the ICanvas class for a common and easy-to-use method for placing multiple windows into a client window. Version 5 places the two static text windows into a horizontal split canvas, called helloCanvas, and then places helloCanvas and the list box into a vertical canvas called clientWindow. It also places windows in a split canvas by identifying the canvas as the control window's parent. For example, the split canvases in the client area of the Hello World main window are initialized in the AHelloWindow constructor in the ahellow5.cpp file, as follows:
,clientWindow(WND_CANVAS, this, this) ,helloCanvas(WND_HCANVAS, &clientWindow, &clientWindow, IRectangle(), IWindow::visible | ISplitCanvas::horizontal) ,hello(WND_HELLO, &helloCanvas, &helloCanvas) ,statusLine(WND_STATUS, this, this) ,earthWindow(WND_EARTH, &helloCanvas) ,listBox(WND_LISTBOX, &clientWindow, &clientWindow, IRectangle(), IListBox::defaultStyle() | IWindow::tabStop | IListBox::noAdjustPosition)
The order in which you place your child windows into a split canvas determines the order in which they will be seen. For example, the AHelloWindow::hello static text window appears above the earthWindow static text window because it is created as the first child of the helloCanvas window. Likewise, the helloCanvas window appears to the left of the list box because it is created before the list box.
After initializing the canvases, the following statements from the ahellow5.cpp file set the client window and the proportions for its child windows in the vertical split canvas.
setClient(&clientWindow); clientWindow.setSplitWindowPercentage(&helloCanvas, 60); clientWindow.setSplitWindowPercentage(&listBox, 40);
Hello World version 5 provides you with the ability to change the Hello World text by selecting different language versions of the phrase "Hello World" from a list box. The IListBox object in Hello World version 5 is called listBox and is initialized in the AHelloWindow constructor in ahellow5.cpp as follows:
,listBox(WND_LISTBOX, &clientWindow, &clientWindow, IRectangle(), IListBox::defaultStyle() | IWindow::tabStop | IListBox::noAdjustPosition)
The inherited tabStop style indicates that you can tab to the list box. The noAdjustPosition style prevents the list box from being automatically resized when an item in the list does not fit inside the current window.
One way you can populate the newly created list box is to use IListBox::addAscending. This function adds a text string to the list box in ascending alphabetical order. For example, Hello World version 5 uses the addAscending function to load a variable number of strings from the resource file into the list box as follows:
for (int i=0;i<HI_COUNT;i++ ) listBox.addAscending(HI_WORLD+i);
The strings are defined in the resource file, ahellow5.rc, as follows:
// Change HI_COUNT in ahellow5.h to change number of HIs used. HI_WORLD, "Hello, World!" //English HI_WORLD+1, "Hi, World!" //American HI_WORLD+2, "Howdy, World!" //Southern American HI_WORLD+3, "Alo, Mundo!" //Portuguese HI_WORLD+4, "Ola, Mondo!" //Spanish HI_WORLD+5, "Hallo wereld!" //Dutch HI_WORLD+6, "Hallo Welt!" //German HI_WORLD+7, "Bonjour le monde!" //French HI_WORLD+8, "Put your language here!" //Add more items, too!
HI_WORLD is a symbolic definition for the constant string ID of the first string. HI_COUNT is the symbolic definition for the constant number of strings to load. In this sample, HI_COUNT is defined as 8. Therefore, only HI_WORLD through HI_WORLD+7 are loaded. You can add another item to the list by changing the HI_WORLD constant in the symbolic definition file, ahellow5.h, and adding your strings to the HI_WORLD list.
Once you create the list box and fill it with items, define a select handler for processing list box selections. Hello World version 5 provides a select handler class, called ASelectHandler. (It is similar to the command handler added in Hello World version 3.)
The three differences are as follows:
The ASelectHandler is defined in the AHelloWindow class header file, ahellow5.hpp, using the following class definition:
class ASelectHandler : public ISelectHandler { public: /*------------------------------ Constructor -----------------------------| | Construct the object with: | | 1) A pointer to the main frame window | -------------------------------------------------------------------------*/ ASelectHandler(AHelloWindow *helloFrame); /*------------------------------ Destructor ------------------------------| | Destruct the object with: | | 1) No parameters | -------------------------------------------------------------------------*/ virtual ~ASelectHandler() { } protected: /*------------------------ Override Selected Function --------------------| | The selected() function is called to handle list box selection events. | |------------------------------------------------------------------------*/ virtual bool selected(IControlEvent& ctlEvent); private: AHelloWindow *frame; };
The ASelectHandler::selected function and the AHelloWindow::setTextFromListBox function provide the selection event handling for version 5. These functions are listed below and can be found in the ahellow5.cpp file:
AHelloWindow & AHelloWindow :: setTextFromListBox() { /*------------------------------------------------------------------------| | Create a cursor to the list box. Using the default filter for a | | list box cursor, selectedItems, causes the setToFirst() function | | to position the cursor to the first selected item. | | Set the hello IStaticText control text value. | |------------------------------------------------------------------------*/ IListBox::Cursor lbCursor(listBox); lbCursor.setToFirst(); hello.setText(listBox.elementAt(lbCursor)); return (*this); //Return a reference to the frame }; /* end AHelloWindow :: setTextFromListBox() */ : : bool ASelectHandler :: selected(IControlEvent & evt) { /*------------------------------------------------------------------------| | Call the AHelloWindow::setTextFromListBox function for the frame used | | to construct this select handler. | |------------------------------------------------------------------------*/ frame->setTextFromListBox(); return (true); //Event is always processed } /* end ASelectHandler :: selected(...) */
The setTextFromListBox function introduces a new Open Class Library class, IListBox::Cursor. Use a list box cursor to scan through the items in a list box. The constructor used in Hello World version 5 for creating the lbCursor object contains only one argument, the list box object to be scanned. You can also specify an additional argument, called a filter, to specify if you want to scan all the items in the list or only the items that are selected. Because the setTextFromListBox function looks for the first item selected, the default filter type, selected, is used.
The IListBox::Cursor::setToFirst function positions the cursor to the first selected item. Then, the IListBox::elementAt function uses the cursor to locate and return the text string identified by the first selected item. Hello World version 5 uses the string value to set the Hello World text.
Like the command handler in Hello World version 3, the ASelectHandler::selected function is not called until you attach the handler to the proper window. In this case, you attach the select handler to the list box using the ASelectHandler inherited IHandler function, handleEventsFor. This causes the ASelectHandler::selected function to be called each time you select a list box item.
To stop handling selection events, use the stopHandlingEventsFor function, again specifying the list box.
The aearthw5.hpp and aearthw5.cpp files contain the class header and implementation for the AEarthWindow class. Refer to the comments and code in these files for examples of the following:
Use the following steps to create IPF help information for your application:
Create the source text that displays in your application's help window using the IPF format (.ipf file) for the OS/2 operating system and the IPF/X format (.ipf file) for the Windows and Motif environments. Compile your file into a help file (.hlp file) using the IPFC compiler.
Refer to the Information Presentation Facility documentation for descriptions of the tags you use to create the source .ipf file.
For an example of a .ipf source file, see the Hello World version 5 ahellow5.ipf file.
STR_HTITLE, "C++ Hello World - Help Window" //Help window title string POPUP "&Help" , MI_HELP , RIGHTJUSTIFY BEGIN MENUITEM "&General help..." , SC_HELPEXTENDED /*MIS_SYSCOMMAND*/ MENUITEM "&Keys help..." , SC_HELPKEYS /*MIS_SYSCOMMAND*/ MENUITEM "Help &index..." , SC_HELPINDEX /*MIS_SYSCOMMAND*/ END
The OS/2 .rc file appears as follows:
STR_HTITLE, "C++ Hello World - Help Window" //Help window title string SUBMENU "~Help", MI_HELP, MIS_HELP //Help submenu BEGIN MENUITEM "~General help...", SC_HELPEXTENDED, MIS_SYSCOMMAND MENUITEM "~Keys help...", SC_HELPKEYS, MIS_SYSCOMMAND MENUITEM "Help ~index...", SC_HELPINDEX, MIS_SYSCOMMAND END
MI_HELP is the help menu ID.
Normally, you specify MIS_HELP for a menu item to cause a help event, rather than a command event, to be posted when the menu item is selected.
When you specify MIS_HELP (OS/2) or RIGHTJUSTIFY
(Windows) for a submenu item, Motif automatically
positions the item to the far right of the menu bar. OS/2
PM ignores MIS_HELP specified on submenu items. Windows
NT 3.51 ignores RIGHTJUSTIFY specified on
submenu items.
When MIS_SYSCOMMAND is specified with the predefined
SC_HELP* IDs, a system command event is generated. The
default system command handler recognizes the predefined
IDs and shows the appropriate help panel, except for
SC_HELPKEYS, which by default does nothing. SC_HELP* IDs
are defined in the <icconst.h> file.
You can override this
default processing for SC_HELPKEYS, using an
IHelpHandler, which is described in a later step.
The help table defines the relationship between the window ID and the general or contextual panel ID that is defined in the .ipf file. The following help table is defined in the resource file, ahellow5.rc, for Hello World version 5:
HELPTABLE HELP_TABLE BEGIN HELPITEM WND_MAIN, SUBTABLE_MAIN, 100 HELPITEM WND_TEXTDIALOG, SUBTABLE_DIALOG, 200 END HELPSUBTABLE SUBTABLE_MAIN //Main window help subtable BEGIN // HELPSUBITEM WND_HELLO, 100 //Hello static text help ID HELPSUBITEM WND_LISTBOX,102 //List box help ID HELPSUBITEM MI_EDIT, 110 //Edit menu item help ID HELPSUBITEM MI_ALIGNMENT, 111 //Alignment menu item help ID HELPSUBITEM MI_LEFT, 112 //Left command help ID HELPSUBITEM MI_CENTER, 113 //Center command help ID HELPSUBITEM MI_RIGHT, 114 //Right command help ID HELPSUBITEM MI_TEXT, 199 //Text command help ID END // HELPSUBTABLE SUBTABLE_DIALOG //Text dialog help subtable BEGIN // HELPSUBITEM DID_ENTRY, 201 //Entry field help ID HELPSUBITEM DID_OK, 202 //OK command help ID HELPSUBITEM DID_CANCEL, 203 //Cancel command help ID END //
WND_HELLO and WND_LISTBOX are control IDs, MI_* are menu item IDs, and the DID_* are push button IDs. Each window ID is related to a help panel ID. In the preceding example, WND_MAIN and WND_HELLO both correspond to help panel ID 100. That is, pressing the F1 key in the main window area displays the same help panel as selecting General help... from the Help submenu.
Use
the IHelpWindow class to associate help information with
an application window. Hello World version 5 defines the
private data member, helpWindow, as
an IHelpWindow object. It is initialized in the
AHelloWindow constructor in ahellow5.cpp using the
following statement:
,helpWindow(HELP_TABLE,this)
The first parameter identifies the help table defined in the resource file. The second parameter identifies the application window for which the help is being provided.
Use the IHelpWindow::addLibraries member function to associate a help file with a help window. The AHelloWindow constructor in Hello World version 5 provides an example:
helpWindow.addLibraries("ahellow5.hlp");
You can set the title of the help window by using the IHelpWindow::setTitle member function. The following code sets the title from a string defined in the resource file:
helpWindow.setTitle(STR_HTITLE);
A help handler processes help events. Create your own help handler class derived from IHelpHandler to provide help event processing that is unique to your application. Hello World version 5 uses a help handler only to display the keys help panel describing accelerator key definitions.
To override keys help processing, do the following:
class AHelpHandler : public IHelpHandler { protected: virtual bool keysHelpId(IEvent& evt); };
bool AHelpHandler :: keysHelpId(IEvent& evt) { evt.setResult(1000); //1000=keys help ID in // ahellow5.ipf file return (true); //Event is always processed } /* end AHelpHandler :: keysHelpId(...) */
In the preceding code, the help panel ID for the Hello World version 5 keys help is set in the event result.
Your help handler, previously described, does not begin handling help events until you use the handleEventsFor member function. For example, the following code causes the helpHandler to begin processing help events for this frame window:
helpHandler.handleEventsFor(this);
Typically, you include this statement in the constructor for the frame window.
Note that the window that handles help events must be an associated window. That is, you should identify the window as the associated window on the IHelpWindow constructor or explicitly identify the window as an associated window using the IHelpWindow::setAssociatedWindow function.
When you want to stop handling help events, for example, when you close your frame window, use the stopHandlingEventsFor member function, as follows:
helpHandler.stopHandlingEventsFor(this);
You typically include this statement in the destructor for the frame window.
class ChildFrameHelpHandler : public IHandler { typedef IHandler Inherited; /******************************************************************************* * This handler enables the OS/2 Help Manager to use help tables to display * * contextual help for a child frame window (one whose parent window is not * * the desktop). This handler should only be attached to child frame windows. * *******************************************************************************/ public: virtual ChildFrameHelpHandler &handleEventsFor ( IFrameWindow* frame ), &stopHandlingEventsFor ( IFrameWindow* frame ); protected: virtual bool dispatchHandlerEvent ( IEvent& evt ); ChildFrameHelpHandler &setActiveWindow ( IEvent& evt, bool active = true ); private: virtual IHandler &handleEventsFor ( IWindow* window ), &stopHandlingEventsFor ( IWindow* window ); }; bool ChildFrameHelpHandler :: dispatchHandlerEvent ( IEvent& evt ) { switch ( evt.eventId() ) { case WM_ACTIVATE: setActiveWindow(evt, evt.parameter1().number1()); break; case WM_HELP: setActiveWindow(evt, true); break; default: break; } /* endswitch */ return false; // Never stop processing of event } ChildFrameHelpHandler& ChildFrameHelpHandler :: setActiveWindow ( IEvent& evt, bool active ) { IHelpWindow* help = IHelpWindow::helpWindow(evt.window()); if (help) { IFrameWindow* frame = 0; if (active) { frame = (IFrameWindow*)evt.window(); } help->setActiveWindow(frame, frame); } return *this; } ChildFrameHelpHandler& ChildFrameHelpHandler :: handleEventsFor ( IFrameWindow* frame ) { IASSERTPARM(frame != 0); Inherited::handleEventsFor(frame); return *this; } ChildFrameHelpHandler& ChildFrameHelpHandler :: stopHandlingEventsFor ( IFrameWindow* frame ) { IASSERTPARM(frame != 0); Inherited::stopHandlingEventsFor(frame); return *this; } IHandler& ChildFrameHelpHandler :: handleEventsFor ( IWindow* window ) { // private to hide version in IHandler ITHROWLIBRARYERROR(IC_MEMBER_ACCESS_ERROR, IErrorInfo::invalidRequest, IException::recoverable); return *this; } IHandler& ChildFrameHelpHandler :: stopHandlingEventsFor ( IWindow* window ) { // private to hide version in IHandler ITHROWLIBRARYERROR(IC_MEMBER_ACCESS_ERROR, IErrorInfo::invalidRequest, IException::recoverable); return *this; }
You can assign helpIDs directly to windows by using IWindow::setHelpId( unsigned long topicId ); while maintaining portability. When F1 is pressed, the window with focus is then be queried for its context helpID and if one is found, it is used to identify the help panel to display. If one is not found and there is a help table, it is searched for the appropriate helpID to use.
If you are not using a help table, the helpId of the active frame is used as the general help panel.
By default, IHelpWindow uses the native help for the platform to handle help requests using a .hlp file that was created from RTF or IPF source. This allows the code you write to be portable while giving your users native look-and-feel. IPF help files are also portable between the various platforms. RTF help files are not portable. In addition, some functions provided by IPF are not available when using Windows native help (RTF). The major differences are as follows:
Events and Event Handlers
Canvas Controls
Resources
Converting Application Resources
Adding Menus to your Application
Layout Using Canvas Controls
Creating and Using Text Controls
Using List and Slider Controls
IEvent
ICanvas
ICommandHandler
IHandler
IHelpWindow
IHelpHandler
IListBox
IMenu
IMenuBar