 Keyboard Handling within Child Dialogs of an OWL MDI application

 Description of a method to enable keyboard handling within Child 
 Dialogs of MDI Child Windows from an OWL MDI application. 


     Keyboard Handling within child dIALOGS in an OWL mdi App.
     ========================================================


    ObjectWindows ( OWL ) simplifies the building of Windows
applications by encapsulating the basic and common behaviour for
window management and message processing. As with all Frameworks,
however, the default behaviour may not always satisfy every
design requirement.  A case in point is when DIALOGS are inserted
into mdi Child Windows ( i.e. A TDialog is a child of a TWindow
which is a child of a TMDIClient ).


    OWL automates Windows-Message processing ( via DDVTs ) by
calling the appropriate function ( e.g. IsDialogMessage(),
TranslateMDISysAccel() etc. ) from the ProcessAppMsg() function (
Member of TApplication ).  The default processing for mdi
applications, however, may result in the lost of keyboard
handling within Modeless dIALOGS inserted into mdi Child Windows.  


    The following example illustrates a method to allow the
default processing of messages within an mdi application while
enabling keyboard handling for child DIALOGS.  The required steps
are:

- Process WM_MDIACTIVATE sent to mdi Child Window to 
activate keyboard handling [ via SetBKHandler() ] and set
Focus to child DIALOG.

- Process WM_SETFOCUS sent to mdi Child Window and post a
WM_MDIACTIVATE message to the mdi Child Window.

- Process WM_SETFOCUS sent to Child dIALOG and activate
keyboard handling [ via SetKBHandbler() ]


    To allow the default processing of messages pertinent to mdi
Applications, the proper base or default function must be called
( or chained to ) from the function responding to the above
mentioned messages.   For example, the mdi Child Window's
WMMDIActivate() function must call TWindow's WMMDIActivate()
function [ NOTE: The mdi Child Window is presumably derived from
TWindow ].


    The following example demonstrates the method described
above.  To keep the code simple, the implementation of some
desired behaviour ( eg. Handling mdi Child Window/Child dIALOG
size discrepancies or Closing of mdi Child Window when Child
dIALOG is concluded ) have been left out.



// ---------- //
// MDIDLG.CPP //
// ---------- //

#include <owl.h>
#include <dialog.h>
#include <bwcc.h>
#include <mdi.h>


_CLASSDEF( TMyMDIApp )
_CLASSDEF( TMyMDIFrame )
_CLASSDEF( TMyMDIChild )
_CLASSDEF( TMyDialog )


class TMDIApp : public TApplication
{
    public:
        TMDIApp( LPSTR name,
                 HANDLE hInstance,
                 HANDLE hPrevInstance,
                 LPSTR lpCmd,
                 int nCmdShow ) :
        TApplication( name, hInstance, 
                      hPrevInstance, lpCmd, nCmdShow )
        {};
        virtual void InitMainWindow();
};



class TMyMDIFrame : public TMDIFrame
{
    public:
        TMyMDIFrame( LPSTR ATitle, LPSTR MenuName ) :
        TMDIFrame( ATitle, MenuName )
        {}
        virtual PTWindowsObject InitChild();
};



class TMyMDIChild : public TWindow
{
    private:
        PTMyDialog  pDialog;       // Pointer to Child dIALOG

    public:
        TMyMDIChild( PTWindowsObject AParent,
                     LPSTR ChildName,
                     PTModule AModule );
        virtual void WMMDIActivate( RTMessage Msg ) =
                       [ WM_FIRST + WM_MDIACTIVATE ];
        virtual void WMSetFocus( RTMessage Msg ) =
                       [ WM_FIRST + WM_SETFOCUS    ];
        virtual void SetupWindow();
};



void TMyMDIChild::WMMDIActivate( RTMessage Msg )
{
    TWindow::WMMDIActivate( Msg );

    if ( Msg.WParam == TRUE )    // Only if we're being activated
    {
        GetApplication()->SetKBHandler( this );
        if ( pDialog != NULL )
            SetFocus((( PTDialog )pDialog)->HWindow );
    }
}



void TMyMDIChild::WMSetFocus( RTMessage Msg )
{
    PostMessage( HWindow, WM_MDIACTIVATE, TRUE, 0L );
    DefWndProc( Msg );
}



class TMyDialog : public TDialog
{
    public:
        TMyDialog( PTWindowsObject AParent,
                   LPSTR AName,
                   PTModule AModule = NULL ) :
        TDialog(AParent, AName, AModule)
        {}
        TMyDialog( PTWindowsObject AParent,
                   int ResourceId,
                   PTModule AModule = NULL ) :
        TDialog( AParent, ResourceId, AModule )
        {}
        virtual void WMSetFocus( RTMessage Msg ) =
                      [ WM_FIRST + WM_SETFOCUS  ];
};



void TMyDialog::WMSetFocus( RTMessage Msg )
{
    GetApplication()->SetKBHandler( this );
    DefWndProc( Msg );
}



void TMyMDIChild::SetupWindow()
{
    TWindow::SetupWindow();

    pDialog = new TMyDialog( this, ( LPSTR )"MDIDIALOG" );
    if ( pDialog )
    {
        GetApplication()->MakeWindow( pDialog );
        SetFocus( pDialog->HWindow );
    }
}



PTWindowsObject TMyMDIFrame::InitChild()
{
    return( new TMyMDIChild( this, "MDI-Child", NULL ));
}



TMyMDIChild::TMyMDIChild( PTWindowsObject AParent,
                          LPSTR ChildName,
                          PTModule AModule ) :
TWindow( AParent, ChildName, AModule )
{
    pDialog = NULL;
    GetApplication()->SetKBHandler( this );
    SetFlags( WB_KBHANDLER, FALSE );
}



void TMDIApp::InitMainWindow()
{
    MainWindow = new TMyMDIFrame( "mdi App.", "MDIMenu");
}



int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance,
                    LPSTR lpszCmdLine, int nCmdShow )
{
    BWCCGetVersion();
    TMDIApp MDIApp ( "mdi App.",
                      hInstance,
                      hPrevInstance,
                      lpszCmdLine,
                      nCmdShow );
    MDIApp.Run();
    return ( MDIApp.Status );
}




// ---------- //
// MDIDLG.RC  //
// ---------- //
#include <windows.h>
#include <bwcc.h>
#include <owlrc.h>


MDIDIALOG dialog 0, 0, 240, 186
CAPTION "Edit Name"
FONT 10, "Courier"
CLASS "BorDlg"
STYLE WS_CHILD | WS_VISIBLE
BEGIN
        CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | 
WS_VISIBLE |
WS_GROUP | WS_TABSTOP, 40, 157, 49, 19
        PUSHBUTTON "Cancel", IDCANCEL, 152, 157, 49, 19, WS_CHILD | 
WS_VISIBLE |
WS_TABSTOP
        CTEXT "Sample dIALOG Box", -1, 41, 24, 158, 24, WS_CHILD | 
WS_VISIBLE |
WS_GROUP
        CONTROL "Option 1", 102, "BorRadio", BS_AUTORADIOBUTTON | WS_CHILD |
WS_VISIBLE | WS_GROUP | WS_TABSTOP, 41, 72, 45, 10
        CONTROL "Option 2", 102, "BorRadio", BS_AUTORADIOBUTTON | WS_CHILD |
WS_VISIBLE, 41, 84, 46, 6
        CONTROL "Option 3", 102, "BorRadio", BS_AUTORADIOBUTTON | WS_CHILD |
WS_VISIBLE, 41, 92, 45, 10
        CONTROL "Item 1", 104, "BorCheck", BS_AUTOCHECKBOX | WS_CHILD | 
WS_VISIBLE
| WS_GROUP | WS_TABSTOP, 167, 72, 39, 10
        CONTROL "Item 2", 104, "BorCheck", BS_AUTOCHECKBOX | WS_CHILD | 
WS_VISIBLE,
167, 82, 38, 10
        CONTROL "Item 3", 104, "BorCheck", BS_AUTOCHECKBOX | WS_CHILD | 
WS_VISIBLE,
167, 92, 38, 10
        EDITTEXT 105, 30, 122, 61, 12, ES_LEFT | WS_CHILD | WS_VISIBLE | 
WS_BORDER
| WS_GROUP | WS_TABSTOP
        EDITTEXT 105, 155, 121, 61, 12
        CONTROL "", 103, "BorShade", 1 | WS_CHILD | WS_VISIBLE, 30, 66, 61, 
41
        CONTROL "", 103, "BorShade", 1 | WS_CHILD | WS_VISIBLE, 155, 66, 
61, 41
END

MDIMENU MENU 
BEGIN
        POPUP "&File"
        BEGIN
                MENUITEM "&New mdi Child", CM_CREATECHILD
                MENUITEM "&Tile", CM_TILECHILDREN
                MENUITEM "&Cascade", CM_CASCADECHILDREN
        END

END

