Building Graphical User Interfaces (GUIs)
Using the Microsoft Foundation Classes (MFC)
You must use Microsoft Visual C++ 2010 or 2012 for this exercise.
VS 2017 no longer contains an MFC project.
Exercise 3: A dialog based application
Dialog windows may be of two types. The first is modal meaning it must be closed before
you can do anything else in the application. The best known examples of modal dialog boxes are
the Open and Save file dialog boxes. The second type of dialog is Non-modal or Modeless
which can stay open even if you shift focus to another window of the application.
In this exercise you will build a dialog based application in which the main window is a non-modal
dialog box. The main window is an instance of a CDialog which is derived from CWnd.
If you have not already created the MFCDlgProject project then click
back on your browser and click the link Creating Projects in Visual Studio
for GUI applications and follow the instructions for creating the project
for exercise 4.
The Files Visual Studio Created
Take a look at the files created automatically for you when you created the MFC project. The
image below shows the listing of those files from the demonstration program shown in class.
The Application File – projectname.cpp
Open this file and take a look at these items:
-
The Message Map macros BEGIN_MESSAGE_MAP and END_MESSAGE_MAP
These enclose all of the message handlers for the application. Visual Studio will add
to these as you add handlers. The arguments passed to BEGIN_MESSAGE_MAP are the
name of the application class and it’s super class. Note that the application class
name has been created from: 'C' + ProjectName + "App".
BEGIN_MESSAGE_MAP(CDemo03MFC_DialogApp, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
-
The Constructor. Normally you would initialize class variables, etc. here, however,
just before the dialog window is displayed there is a call to the InitInstance() function
where you should do most of your major initializations.
CDemo03MFC_DialogApp::CDemo03MFC_DialogApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
-
The app instance. This is a static instance of your dialog application.
// The one and only CDemo03MFC_DialogApp object
CDemo03MFC_DialogApp theApp;
-
InitInstance() - In this function you perform any major initializations needed.
The Dialog File – projectnameDlg.cpp
Open this file and take a look at these items:
-
The about dialog – The first section defines the class for the About dialog box if you
select the "About" option from a help menu.
-
The main application dialog class is defined next.
-
The Message Map (see detailed description above) uses macros to create the same functionality
as the WndProc function in the API examples. After you build the GUI come back and look at
this.
-
OnInitDialog() – This is where you can do any initializations of the dialog widgets,
such as adding items to combo boxes or list boxes.
-
OnSysCommand() – Handles the WM_COMMAND message.
-
OnPaint() – Handles the WM_PAINT command to repaint the screen.
-
As you add event handlers for each of the widgets in the GUI the callback
functions will be automatically created here. You will need to add the
appropriate code to handle each of these events.
Building the GUI
If the resource editor is not already open showing the dialog window, open it by
expanding the applicationName item in the Resource View pane. Expand
the Dialog folder and double click the IDD_APPLICATION_NAME_DIALOG
resource. If the Resource View is not visible make it so by selecting
View->Other Windows->Resource View.
Look at the left or right edge of the Visual Studio window and find where the Toolbox tab
is located. When you click this it expands to display all the widgets you can add to the dialog
box. There are a number of catagories of widgets. You want to expand the Dialog Editor
widgets.
You can now build your GUI by clicking a widget in the list then clicking in the dialog box
where you would like to creat the widget. Below you will find notes on how to create the
demonstration dialog box shown in this image. You may copy it or feel free to experiment
with your own layout and design.
OK and Cancel Buttons
By default the resource editor adds an OK and Cancel button to the dialog. You can
edit or delete either of these. Both automatically close the dialog box when you
create an event handler for them.
-
Delete the cancel button. Click it in the resource editor and then press
the Delete key.
-
Change the text on the OK button to Exit.
-
Right click the button and select Properties from the drop down
menu. (The Properties can also be found as a tab in the margin
of the main Visual Studio window.)
-
Locate the Caption property and change it to Exit.
-
Double click the button to automatically add the code for an event handler function.
Look at the bottom of the ApplicationNameDlg.cpp file and you should
see a function: void ApplicationNameDlg::OnBnClickedOk(). If this function
does not already have the code in it to terminate the application (some versions of Visual
Studio do not automatically add it) then add the single line of code OnOK();.
Radio Button Groups
-
Create a Group Box widget first.
-
Create the radio buttons inside the group. (If you create the buttons first you can select
all of them, press ctrl-X to cut them, then select the group box, finally press ctrl-V to paste
the radio buttons inside the group box. Note: this does not move the location of the radio buttons
it just links them to each other via the group box. This also does not group the widgets so they
can be moved as a unit in the visual editor.)
-
To set the automatic selection feature, select the first button in the group and set its
Group property to True. Set the Group property of all others buttons to False.
-
Right click the first radio button and select Add Variable.
-
In the dialog box give the variable a name, like m_RadioButton1 and click OK. If you see a check
box labeled "Control Variable" make sure it is checked so you can create a variable of type CButton.
-
Look at the code in the ApplicationNameDlg.cpp file in the function
doDataExchange(). You will see that it has added a line like:
DDX_Control(pDX, IDC_RADIO1, m_RadioButton1);
-
In the OnInitDialog() function initialize the radio button to selected with
m_RadioButton1.SetCheck(1);
-
Double click each radiobutton widget to create an event handler for it.
Checkbox widget
-
Create a check box widget.
-
Right click the check box widget and select Add Variable.
-
In the dialog box give the variable a name, like m_CheckBox and click OK
-
Look at the code in the ApplicationNameDlg.cpp file in the function
doDataExchange(). You will see that it has added a line like:
DDX_Control(pDX, IDC_CHECK1, m_CheckBox);
-
You can now use the variable to get the state with:
int state = m_CheckBox.GetCheck();
If this returns 1 the check box is checked, if it returns 0 it is unchecked.
-
Double click the check box widget to create an event handler.
Text Button
-
Create a button. Set its text string in the properties pane to something like
"My Text Button".
-
Double click the button widget to create an event handler.
Icon Button
-
Create an icon resource as you did in Exercise 2 and note it’s ID.
-
Go to the downloads page and click the link to display the DukeBrush.bmp image.
Use this link to the downloads page:
http://www.cs.uah.edu/~rcoleman/CS307/downloads/index.html
-
If the image opens in your browswer right click the image and select Copy. If it is
automatically downloaded to your Downloads folder then double click the DukeBrush.bmp image
then when it opens in Photo Viewer right click and select Copy.
-
In the visual editor for the icon resource select the 32x32 bit icon.
-
Select the teal background with the eyedropper tool.
-
Paint over all of the icon to make it a uniform background color.
-
Paste the copied DukeBrush.bmp into the icon. It will be much too large to fit
but you can use the handles (the tiny squares at the corners and center of each side)
and drag to resize the image to fit. Be careful that you do not unselect the icon
before resizing it as you cannot re-select the entire image then.
-
Save the icon.
-
Back in the dialog box visual editor
create a square button. Set its Caption property in the properties pane to an empty string.
-
Set its Icon property in the properties pane to true.
-
Right click the button and select Add Variable.
-
In the dialog box give the variable a name, like m_IconButton and click OK
-
In the OnInitDialog () function initialize the icon for the button with:
if (m_IconButton.GetIcon() == NULL)
m_IconButton.SetIcon(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONDUKE)));
You will substitute your icon ID for "IDI_ICONDUKE".
-
Double click the button widget to create an event handler.
Note: If the correct icon does not appear on the button it is because Visual Studio
selected another size icon to display. To fix this open the icon resource in the visual
editor. Except for the icon you want to use, right-click each of the icon sizes shown in
the listing on the left and select from the pop-up menu "Delete Image Type". This will
delete that icon size. With just the icon size you want to use left in the icon resource
this will be the only one Visual Studio can select to use on the button.
Slider widget with text display
-
Add a slider widget.
-
Right click the slider and select Properties.
-
If your version of Visual Studio lets you set the minimum and
maximum values set these to 0 and 100 respectively.
-
If your version of Visual Studio lets you set the tick interval
set this to 10.
-
If your version of Visual Studio has Tick Marks as
a property for the slider, set this to true.
-
Add an Edit Control text box next to the slider.
-
Right click the text box widget and select Add Variable.
-
In the dialog box give the variable a name, like m_SliderState and click OK.
-
Look at the code in the ApplicationNameDlg.cpp file at function
doDataExchange(). You will see that it has added a line like:
DDX_Control(pDX, IDC_EDIT1, m_SliderState);
-
Right click the slider widget and select Add Variable.
-
In the dialog box give the variable a name, like m_Slider and click OK.
-
Look at the code in the ApplicationNameDlg.cpp file at function
doDataExchange(). You will see that it has added a line like:
DDX_Control(pDX, IDC_SLIDER1, m_Slider);
-
Double click the slider widget to create an event handler function in
ApplicationNameDlg.cpp.
-
Look for the function OnNMCustomdrawSlider1(). Each time the slider
changes you can display its reading with:
int x = m_Slider.GetPos(); // Get current position
char str[32];
sprintf(str, "%d", x); // Create the string
this->m_SliderState.SetWindowText(str); // Set the text box
Don't forget to add #include <string> at the top of this file so you
can use sprintf.
-
To initialize the slider object add the following code to the OnInitDialog()
function in ApplicationNameDlg.cpp:
// Init the range for the slider
m_Slider.SetRange(0, 100);
// Set tic marks at an interval of 10
for(int i=0; i<=90; i+=10)
m_Slider.SetTic(i);
Listbox widget
-
Add a list box widget.
-
Right click list box and select Add Variable
-
In the dialog box give the variable a name, like m_ListBox and click OK.
-
Look at the code in the ApplicationNameDlg.cpp file at function
doDataExchange(). You will see that it has added a line like:
DDX_Control(pDX, IDC_LIST1, m_ListBox);
-
Using the variable add several items to the list box in OnInitDialog().
For example:
m_ListBox.AddString("List item 01");
m_ListBox.AddString("List item 02");
m_ListBox.AddString("List item 03");
m_ListBox.AddString("List item 04");
m_ListBox.AddString("List item 05");
m_ListBox.AddString("List item 06");
m_ListBox.AddString("List item 07");
m_ListBox.AddString("List item 08");
m_ListBox.AddString("List item 08");
m_ListBox.AddString("List item 10");
-
Double click the list box widget to create an event handler.
-
In the event handler get the current selected string with:
char str[32];
m_ListBox.GetText(m_ListBox.GetCurSel(), str);
Combobox widget
-
Add a combo box widget.
-
Left click the drop down button of the combobox. Use the gray handle that
appears in the center bottom of the combobox to set the size of the drop down
display box. This is important or you won’t see anything.
-
Right click the combo box and select Add Variable.
-
In the dialog box give the variable a name, like m_ComboBox and click OK.
-
Look at the code in the ApplicationNameDlg.cpp file at function
doDataExchange(). You will see that it has added a line like:
DDX_Control(pDX, IDC_COMBO1, m_ComboBox);
Using the variable add several items to the combo box in OnInitDialog().
For example:
m_ComboBox.AddString("ComboBox item 1");
m_ComboBox.AddString("ComboBox item 2");
m_ComboBox.AddString("ComboBox item 3");
m_ComboBox.AddString("ComboBox item 4");
m_ComboBox.AddString("ComboBox item 5");
-
Set the initial selection in the combobox with:
m_ComboBox.SetCurSel(0);
-
Double click the combo box widget to create an event handler.
-
In the event handler get the current selected string with:
char str[32];
m_ComboBox.GetLBText(m_ComboBox.GetCurSel(), str);
-
In the visual editor click the down arrow on the right side of the combobox.
The selection handles will change. The handle in the middle bottom will be
solid black. Use this handle to stretch the limits of the combobox. This
will set the size of the combobox when it is clicked to open it when the
application is running. If you do not set this it will be difficult to
select anything. If the limit you set is not enough to display all the options
in the combobox then a scroll bar will automatically appear on the right
side of the combobox when it is dropped down.
Status text widget
-
Add an Edit Control text box at the bottom of the dialog box.
-
Right click the text box widget and select Add Variable.
-
In the dialog box give the variable a name, like m_StatusTextBox and click OK.
-
Look at the code in the ApplicationNameDlg.cpp file at function
doDataExchange(). You will see that it has added a line like:
DDX_Control(pDX, IDC_EDIT2, m_StatusTextBox);
-
You can now use the variable to access the text box and set and get
the text in any of the handler functions with:
m_StatusTextBox.SetWindowText("some text");
// OR
char str[64];
m_StatusTextBox.GetWindowText(str, 63);
m_StatusTextBox.SetWindowText(str);
-
Go through each of the other handler functions and have them print
in the m_StatusTextBox the action that has just occurred. For example,
have the icon button handler print "Icon button clicked."
Set Window Title
-
In the ApplicationNameDlg.cpp locate the function OnInitDialog()
-
After all your other initializations and before the return true; line
add the following, changing Demo03-MFC_dialog to the name of your
application and John Doe to your name:
// Set window title
this->SetWindowTextA("Demo03-MFC_Dialog-John Doe");
Compile and run your application. Play with the widgets to see how they work.
Try adding and experimenting with the other widgets
For more information on any of the widgets try doing a Google search
on the widget name +MFC.
|