Creating a GUI using WTL

UW Bothell, CSS

Chris Traina

August 2004

 

Pre-requisites:

 

1)      Visual Studio .NET 7.1

 

2)      WTL 7.1 -- you can download it here: http://www.microsoft.com/downloads/details.aspx?FamilyId=1BE1EB52-AA96-4685-99A5-4256737781C5&displaylang=en)

You will need to add the path to the WTL 7.1 include directory to your project’s “Additional include directories” property (both for C/C++ and Resources, once the latter exists).

 

3)      Here is the source code this tutorial references.

 

 

WtlFrame:

 

1)      This project demonstrates how to create the basic framework for a WTL window.  This creates the main window framework that additional resources/controls are added to.

 

2)      stdafx.h:  this file contains all the WTL (WTL is simply an extension of ATL, so all the files names start with atl) header files as well as the CAppModule variable required for all WTL applications.

 

3)      WtlFrame.h:  this is where the CWtlFrame class is declared

a.       CWtlFrame inherits from CFrameWindowImpl, a WTL base class.

b.       IDR_MAINFRAME is a resource ID that would normally go in resource.h.  Because we don’t have any resources that Visual Studio recognizes, we will not have the resource.h header until later (see WtlWindow below).

c.       The section between BEGIN_MSG_MAP(CWtlFrame) and END_MSG_MAP() maps all the Windows message/control handlers for this class.  For example, OnCreate is called when the class is instantiated and can be used for initialization purposes.

4)      WtlFrame.cpp:  this is where the CWtlFrame class methods are implemented.

a.       OnCreate creates a simple status bar and calls the GetMessageLoop function to register itself to receive certain Windows messages.

b.       OnFileExit posts a message telling Windows to close the window.

 

5)      main.cpp:  this is where the CWtlFrame class is instantiated and the function that creates the window (Create) is called.

 

6)      Once you have properly installed WTL 7.1 and modifed the project to include the WTL include directory, you should be able to compile and run this project.  When it is run, it will display a plain window frame.  The next step is to add a window to the frame.

 

WtlWindow:

 

1)      WtlFrame.h:  two modifications have been made to this file:

a.       A CWindowView member variable has been added to the class for creation of the “child” window.

b.       An additional line has been added to PreTranslateMessage so that, if the frame class cannot process a message, the message is passed to the child window.

 

2)      WtlFrame.cpp:  a crucial line is added to this file to call the function (Create) that creates the child window.

 

3)      WtlWindow.h:  this is where the child window class is declared

a.       Note that IDD_WTL_VIEW is a resource ID that is stored in resource.h.  Because we have added resources (as you will soon see), Visual Studio has automatically created the resource.h file for us and populated it with the resource IDs.  We had to manually re-locate the IDR_MAINFRAME #define to this file.

b.       A message handler (OnShow) has been added to handle any intialization of the child window.

 

4)      WtlWindow.cpp:  this is where the child window class methods are implemented

 

5)      If you change from the “Solution Explorer” tab to the “Resource View” tab (or double-click on WtlTutorial.rc), you will see that a dialog resource called IDD_WTL_VIEW has been added.  This resource is linked to the CWtlWindow class and is created/displayed when the class is created by the CWtlFrame class.  We will use the Resource View more when we add additional controls.

 

6)      You should now be able to compile and run this project.  Now, instead of displaying an empty framework, it displays the CWtlWindow (IDD_WTL_VIEW) form within the the CWtlFrame.

 

7)      Notes on Resources: 

a.       Adding the first resource to the previous WtlFrame project is fairly simple.  Simply go to the Resource View tab, right-click the root entity of the tree view, select Add, and select “Add Resource…”.  Expand “Dialog” and select IDD_FORMVIEW.  The default ID (IDD_FORMVIEW) was changed to IDD_WTL_VIEW in the tutorial.

b.       How is resource ID linked to class?  In the WtlWindow.h file, you will see that the class sets its internal IDD value to IDD_WTL_VIEW.  This links the FORMVIEW resource that was just created to the CWtlWindow class.  Thus, when you instantiate a CWtlWindow object (as WtlFrame does when it is created), a FORMVIEW object is created with it.

c.       Resource IDs are the way you get a handle to any control.  If you want a handle to a button with the ID IDC_BN_MYBUTTON, you can do this:

 

CButton bnButton = GetDlgItem(IDC_BN_MYBUTTON);

 

WtlWindowWithControls:

 

1)      WtlWindow.h:

a.       You will see that several new message handlers have been added, using a slightly different macro (COMMAND_HANDLER).  These are handlers for controls that have been added to the window.  For example, OnBnClickedModify has been added as the command handler for when the IDD_BN_MODIFY button is clicked.  The BN_CLICKED parameter is a notification code that specifies what type of control event the handler will deal with.  Other possible parameters (e.g. BN_PUSHED, BN_DISABLED, BN_SETFOCUS, etc.) can be found in winuser.h.  Other options are available for different control types.  For example, LBN_SELCHANGE is the notification code when the selected value in a list box changes and CBN_DBLCLK is the code for when a combo box is double-clicked.

b.       A new map has also been added:

 

BEGIN_DDX_MAP(CWtlWindow)

                              DDX_TEXT(IDC_STATIC_MSG, m_StaticMsg)

END_DDX_MAP()

 

The DDX stands for Do Data eXchange and this code maps the contents of m_StaticMsg to the text for the IDC_STATIC_MSG control.  This makes it possible to load the controls current text value into m_StaticMsg, using DoDataExchange(true, IDC_STATIC_MSG), or to modify m_StaticMsg and update the controls text value with the new m_StaticMsg value, using DoDataExchange(false, IDC_STATIC_MSG).  NOTE:  if you want to update all the controls for which data exchanges are mapped, simply omit the control ID, e.g. DoDataExchange(false).

c.       You can now compile and run the project.  You can see how the combination of command handlers and data exchange mappings allow you to, among many other things, update a button’s text, count the number of button clicks, update a static text control, read data out of an edit box, and start and monitor a timer.

2)      Creating your own control:

a.       Go to the Resource View, select the IDD_WTL_VIEW control, and drag a new button from the Toolbox onto the form.

b.       With the new button selected, change the ID (in the Properties window) to IDD_BN_CLOSE and the Caption to Close.

c.       In the resource.h file, you will see that there is an automatically created #define for IDD_BN_CLOSE.

d.       In WtlWindow.h, add a COMMAND_HANDLER for the BN_CLICKED event for your new Close button.

e.       In the implementation of your command handler, add the following code:  

GetParent().PostMessage(WM_CLOSE);

f.        Compile and run your updated program.  Now, the Close button will close the window.