Hello World Version 5: Adding Canvases, a List Box, Native System Functions, and Help

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:


Listing the Hello World Version 5 Files

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 Primary Source Code File

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 Symbolic Definitions File

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 Text Dialog Source Code File

The adialog5.cpp file contains the source code for the ATextDialog class, modified for help in version 5.

The ATextDialog Class Header File

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 Earth Window Source File

The aearthw5.cpp file contains the source code for the Earth window graphic that is drawn using native-system graphics calls.

The AEarthWindow Class Header File

The aearthw5.hpp file contains the class definition and interface specifications for the AEarthWindow class.

The Resource File

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 Icon File

The ahellow5.ico file is used as the icon that displays when the application is minimized. This icon is the same as for

The Help Window Source Files

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.


Exploring Hello World Version 5

The following sections describe each of the tasks performed by version 5 of the Hello World application that were not described for previous versions.

Constructing the Client Window with Split Canvases

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);                      

Creating and Using a List Box

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.

Using Native System Functions and Graphics

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:

Setting Up the Help Area

Use the following steps to create IPF help information for your application:

  1. Create a file containing the help information.

    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.

  2. Define the help window title and the help submenu in your resource file. defined in the Windows ahellow5.rc file, as follows:
    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.

  3. Define a help table in the resource file.

    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.

  4. Create a help window object for your application window.

    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);                                             
    
    
  5. Create a help handler by creating an IHelpHandler derived class.

    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:

    1. Define a new class that is derived from IHelpHandler, as shown in the Hello World version 5 class definition file, ahellow5.hpp.
      class AHelpHandler : public IHelpHandler {                                     
      
      protected:                                                                     
      virtual bool                                                                
           keysHelpId(IEvent& evt);                                                  
      };
      
      
    2. Provide the overridden virtual function keysHelpId, which is called when keys help is requested. The following code, from the Hello World version 5 ahellow5.cpp file, shows how to implement this function.
      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.

    3. Start and stop help events processing.

      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.

    4. Associate secondary frame windows with the parent window's help window.
    5. Attach the following special handler to child frame windows in your application. This handler is needed so that help processes correctly for these windows.
      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;
      }
      


Assigning Help IDs to Windows

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.

Using Native Windows Help Files with IHelpWindow

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