VC++ Workshop
Session 6
R. Eckert

DIALOG BOXES

Dialog box--
     Popup child window created by Windows
     Used for special-purpose input 
          Beyond what can be easily managed with a menu
     Contains several child window controls
     Layout & what it does is are predefined (template--a resource)
     How it does it is determined by a "Dialog box procedure"
     Destroyed immediately after use

Programmer must:
1.      Set up the template in the resources (.rc file)
               Specifies controls used, their style/layout
               Can be prepared "visually" w/ Dev Studio dialog box editor
               Or "manually" with a text editor
2.      Write the dialog box procedure
               Code to carry out dialog box's tasks
               Placed in .cpp file
               Provides message-processing capability
                    Msgs from controls inside go to this procedure
               A callback function like main window procedure
               But not the same
                     Part of callback inside Windows
                     It interprets some keystrokes (tab)
                     It calls our procedure
                    

Rule of thumb--
     Dialog box: for simple popup windows using normal window controls    
     Popup/child windows: extensive painting or nonstandard behavior needed 

Main advantage of dialog boxes--
     Ease of construction with the dialog box editor


Types of dialog boxes: 

Modal--
     While visible, user can't switch back to parent window
          (can change to other apps)
     User must explicitly end dialog box 
          Typically by clicking "OK" or "CANCEL" buttons inside
     Most common type of dialog box
     Example: "About" box available with most Windows apps

System Modal--
     A variety of modal dialog box
     With these user can't switch to other apps while dialog box is active

Modeless--
     User can switch between dialog box and the parent window
     More like popup windows 
     Used when dialog box must be visible while user interacts w/ parent    
     Example: dialog box resulting from "Find" or "Replace" menu item
                    of many Windows apps

Steps in Designing, Creating, Using a Modal Dialog Box--

     1. Determine child window controls needed inside
     2. Design dialog box template (easiest with dialog box editor)
     3. Write message-processing function
     4. Activate dialog box by calling DialogBox()
          (Typically in response to menu item selection in WndProc()
     5. Resulting dialog box stays on screen until call to EndDialog()
          (from inside dialog box function)

DLG1: A Simple Example--

User Clicks "Dialog Box" on  program's main menu
          Modal dialog box ("FIRSTDIALOG") appears
          Contains: a static text control (IDC_STATIC)
                         an icon (IDC_ICON1)
                         an "OK" button (IDC_OK)
                         a "Not OK" button (IDC_NOTOK)
     User clicks "OK" buttonback to parent window
     User clicks "Not OK" buttonbeep 

Using Developer Studio to Design DLG1's Resources (.rc file)--

Resources:
     The dialog box ("FIRSTDIALOG")
     An icon ("DIALG1") 
     A menu ("MYMENU") with items:
           "&Dialog Box" (IDM_DIALOG)
           "&Quit" (IDM_QUIT

Steps to Follow:

Get into Developer Studio, open new DLG1 workspace

Enter or copy DLG1.CPP source file, add to project
     Must declare WndProc() and DialogProc() callback functions
     Must #include "resource.h" file

"Insert | Resource", "Icon | New" to bring up Icon Editor
     Draw icon, and hit <Enter>
     Fill in resulting dialog box 
          ID: "DIALG1"
          File name: dialg1.ico
     Iconify or close Icon Editor

Resources will look like:  
     Script1
            Icon  "DIALG1"

"Insert | Resource", "Menu | New" to bring up Menu Editor
     Generate menu items: 
          &Dialog Box (ID = IDM_DIALOG) 
          &Quit (ID = IDM_QUIT)
     Iconify the Menu Editor

Resource script will now look like:
     Script1
            Icon  "DIALG1"
            Menu  IDR_MENU1

Right click on IDR_MENU1, select Properties
Change ID to "MYMENU"

The script will now look like:
Script1
       Icon  "DIALG1"
       Menu  "MYMENU"

"Insert | Resource", "Dialog | New" to bring up dialog box editor
Use righthand tool bar to modify and fill lefthand dialog box template 
At any time, double click unoccupied point inside dialog box template
     A "Dialog Properties" dialog box 
     Can be used to change many parameters associated with dialog box

Click on "Cancel" button in dialog box template area
Press <Delete> from the keyboard (Don't want that button) 

Drag "OK" button to lower righthand corner of template area
Double click and change ID to IDC_OK
Leave default caption "OK" as is

Drag Button Tool (little rectangle on tool bar) to area below "OK" button
Double click "button1" button that appears
Set its ID to IDC_NOTOK 
Set its caption to "Not OK"

Drag Static Text Control Tool (Aa) to top, righthand area of template area 
Click and drag edge or corner of resulting rectangle to widen it
Double click, set ID to IDC_STATIC (default) and caption to "Static Control"

Drag Picture tool (box w/ tiny pictures) underneath & left of  static control 
Double click border of rectangle that appears
Choose "General" tab (if it doesn't appear)
Set ID to IDC_ICON1
Choose "Icon" from frame list box
Set Image: to "DIALG1"

Iconify Dialog box editor

Resource script should now look like:
     Script1
            Dialog  IDD_DIALG1
            Icon  "DIALG1"
            Menu  "MYMENU"

Right click IDD_DIALG1 and choose Properties
Change the ID to "FIRSTDIALOG"

"File | Save As"
Enter the File name: dlg1
Make sure the file type is .rc

"Project | Add to Project" and "Files" | dlg1.rc

Resource script should now look like:
     dlg1.rc
            Dialog  "FIRSTDIALOG"
            Icon  "DIALG1"
            Menu  "MYMENU"

Build the project

Dialog Box Editor has tools to create:
     list boxes, combo boxes, edit controls, many others

Dialog Box Template Formats (used in .rc file)--

Syntax:

ResourceNameID  DIALOG   x, y, w, h
[Options--e.g., STYLE, CAPTION...]
BEGIN
     Dialog Box Item specifications (of window controls inside)
END

ResourceNameID--
     String used in call to DialogBox() 
          Function that creates the dialog box

x,y,w,h--
     Position, size of dialog box
          Relative to upperleft corner of parent window
          Dialog "base units" used 
               x,w in units of 1/4 average character width
               y,h in units of 1/8 average character height)
                    Look of dialog box same regardless of video display, font 
                    (Default system font x-axis, y-axis units about the same)

Options--
     STYLE is the most important one
          All WS_*** and DS_*** constants can be used
     CAPTION also important

Example:

FIRSTDIALOG DIALOG 10,10,200,200
CAPTION "Dialog"
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
BEGIN
     /* Dialog Box Item Specifications go here */
END

Dialog Box Item Specifications (for controls inside): General Syntax--

     CONTROL_ITEM_NAME [item-dependent stuff], id, x, y, w, h, [style]

Some Examples:

CTEXT "Centered Text", DLI_STATIC, 10, 10, 100, 8
DEFPUSHBUTTON "Cancel", IDC_CANCEL, 40, 10, 40, 15, WS_TABSTOP
EDITTEXT IDC_EDIT, 10, 20, 30, 40, WS_HSCROLL
LISTBOX IDC_LIST, 10, 10, 50, 100, LBS_NOTIFY | WS_VSCROLL | WS_BORDER
SCROLLBAR DLI_SCROLL, 50, 20, 10, 50, SBS_VERT

DLG1.CPP Example Source Program--



WinMain()--
No extra window classes defined (not needed with dialog boxes)

WndProc()--

User clicks "Dialog Box" on menu (WM_COMMAND, IDM_DIALOG)      
     Pgm calls DialogBox()  
          Creates modal dialog box from app's dialog box template resources
          Displays dialog box
          Switches msg-processing to dialog box 
          Control returned when msg-processing function terminates dialog box 
                with a call to EndDialog()

DialogBox() parameters:
     1. App's instance handle
     2. Dialog box ID name 
          Specified in dialog box template when .rc file created
     3. Handle of dialog box's parent window
     4. Address of dialog box function that will process its messages
          A callback function (as with timer)
          Under Windows 95/NT, use name of callback function
          If C++ compiler used, must be type cast to DLGPROC

Example (name of dialog box function is: DialogProc)--

HINSTANCE hInstance;
hInstance = (HINSTANCE)GetWindowLong (hWnd,         
                      GWL_HINSTANCE);
DialogBox(hInstance, "FIRSTDIALOG", hWnd,  
                     (DLGPROC)DialogProc);

Dialog box message-processing function (DialogProc() in DLG1.CPP)--

A callback function called by Windows
Takes same parameters as the app's WndProc()
Returns a Boolean (TRUE or FALSE)  to Windows 
     TRUE should be returned if the message was processed by dialog proc     
     FALSE if not
          Messages not passed to DefWindowProc() if not processed
          Returning FALSE lets Windows know message wasn't processed
          Then default message processing will happen automatically
     Should always return TRUE after WM_INITDIALOG message
     WM_INITDIALOG message:
          Like ordinary an window's WM_CREATE message
          Processed before window (dialog box) is made visible
          Good place to put initialization code

EndDialog() 
     Destroys dialog box
     Returns control to function that called DialogBox()
     Parameters:
          1. window handle passed to dialog box function (hDlg)
          2. integer value returned by DialogBox() 
              Way of getting info from dialog box function to calling program

A dialog box can be used like any other window--
     Use hDlg to get a DC for painting on the dialog box 
          Could be used to create another dialog box (nested dialogs)
 
User Interaction with Dialog Box Controls
     WM_COMMAND message 
          LOWORD(wParam) contains control ID (as usual)
          If dialog box has menu, WM_COMMAND messages from it
          lParam, wParam contain message data (as usual)

DLG1 Dialog Box Message Processing--

Dialog box is created (WM_INITDIALOG)
     Not action taken, no initialization in this dialog box

User clicks "OK" button in dialog box (WM_COMMAND, IDC_OK)
     DialogProc() calls EndDialog()
          Causes destruction of dialog box
          Control transferred back to main window's WndProc()

User clicks on the "Not OK" button (WM_COMMAND, IDC_NOTOK)     
     DialogProc() calls MessageBeep()  beep
     Dialog box continues to be displayed

Exchanging Data with a Dialog Box--

Problems in using dialog boxes that do something:

1. Exchanging data between dialog box function and controls inside

2. Exchanging data between dialog box function and app's WndProc()

(1) SendMessage() could be used to send message to control inside, BUT:
     Need to know control's handle
     Not known since Windows creates them
     IDs are known--specified in resource template

     Use GetDlgItem() to get control's handle:
 
          hControl = GetDlgItem(hDlg, controlID);

     Then SendMessage() can be used to send msg to control:

          SendMessage(hControl, Msg, wParam, lParam);

     Functions can be combined using SendDlgItemMessage(): 

     SendDlgItemMessage(hDlg, controlID, Msg, wParam, lParam);

     Sends message Msg to control whose ID is controlID

(2) Easiest way to exchange info between dialog box ftn and WndProc()--
     Use global variables
     (Only way prior to Windows 3.0)

     Alternative--
          Start dialog box with DialogBoxParam(), not DialogBox():

            DialogBoxParam(hInst,resource_name,hParent,dlgproc,lParamInit);

          First four parameters same as those used in DialogBox()
          Last parameter passed in lParam of dialog box function 
               Received in lParam of WM_INITDIALOG message
          App usually makes it a pointer to some sort of structure
               Complex data can be passed

DLG2: Dialog Box That Actually Does Something--

User clicks "Get Info" main menu item
     Modal dialog box appears, contains:
         Edit control for entering a person's name
         List box containing four salary ranges. 
     User enters name, selects salary range, click dialog box's "OK" button
         Dialog box disappears 
     Main window's client area displays:
          Name entered by user
          String indicating salary level

Situation after user entered name/salary range in dialog box:




Situation after user hits dialog box "OK" button:



     User clicks dialog box's "Cancel" button
          Main window's client area displays:
               "No Response!"

Creating the DLG2 Dialog Box Template --

Procedure similar to that used for DLG1 

Dialog box:

Static controls:
     Used as labels for the edit control and the listbox
     Captions: "Name:" and "Salary:"
     ID: IDC_STATIC for both

Single-line edit control 
     Edit Control Creation Tool: has "ab|" icon
     ID: IDC_EDITNAME

Listbox control 
     Creation Tool:  icon w/ tiny list on left side, scroll arrows on right side
     ID: IDC_LISTSALARY
     "ListBox Properties": Change default "sort" style--
          Select "Style" tab, Click "Sort" check button to remove check mark

Default "OK" and "Cancel" buttons
     Leave with default IDs (IDOK, IDCANCEL)

Give dialog box the name: "INFODLG" 
                              Caption: Information

Menu:

Menu Name: "MYMENU"
Menu Items:   &Get Info, ID=IDM_GET
              &Quit, ID=IDM_QUIT

DLG2.CPP Source File--

A. Global variables and Function Declarations:
     To exchange info between WndProc() & dialog box function
     name[]: Name entered by the user
     nCurSel: position in list  box (0, 1, 2, or 3) of salary range selected
 
     WndProc() declared as main window procedure
     InfoDlgProc() declared as dialog box function

[Possible alternative: 
     Set up a structure with these members
     Use DialogBoxParam() (instead of DialogBox()) to invoke dialog box
          Last parameter: pointer to structure

B. The WndProc()--

User clicks "Get Info" menu item (IDM_GET)
 WndProc(): calls DialogBox() to invoke dialog box
          Dialog box procedure name: InfoDlgProc 
          Return value saved in variable nRetVal
          InfoDlgProc() will return 1 if  user hits "OK", 0 if "Cancel" 
     Gets a DC, draw an empty rectangle to erase display area
     If  nRetVal is 1:
          switch/case statement on nCurSel (set in InfoDlgProc()) 
               Determines which list box position was selected
          Copies appropriate salary message into string cBuf w/ lstrcpy() 
          Calls TextOut() to display name & appropriate salary message
     If  nRetVal is 0:
          Calls TextOut() to display "No Response!" string

C. The InfoDlgProc() dialog box procedure--

Dialog box created by WndProc()'s call to DialogBox() 
 WM_INITDIALOG message to dialog box window
  InfoDlgProc():
     Calls SendDlgItemMessage() to send following messages:
          RESETCONTENT to IDC_LISTSALARY listbox
               Assures it's empty initially
               lParam and the wParam both 0
          four LB_ADDSTRING messages to listbox
          lParam = each of four strings in a salary[][] array
          Will be items appearing in listbox when dialog box appears

User clicks dialog box "OK" button
 WM_COMMAND message, ID=IDOK to dialog box
  Want to get contents of edit control and list box item selected:
   InfoDlgProc():
     Calls SendDlgItemMessage() to send message:
          EM_GETLINE to IDC_EDITNAME edit control
               (Gets text from edit control & copies into local cBuf)
     Calls lstrcpy() to copy it into name[] global variable
     Calls SendDlgItemMessage() to send message:
          LB_GETCURSEL to IDC_LISTSALARY list box
          (Returns position of currently-selected list box item)
     Stores value in nCurSel global variable
     Calls EndDialog()
          Second parameter = 1, returned to WndProc()
          Terminates and destroys dialog box 

User clicks dialog box "Cancel" button
 WM_COMMAND message, IDCANCEL to dialog box
  InfoDlgProc() calls EndDialog()
     Second parameter = 0, returned to WndProc()
     Terminates and destroys dialog box 

List box and edit control data: purely strings
To store non-string data--must format it:
     Can use wsprintf()

Example: value of n to edit control IDC_EDIT in dialog box w/ handle hDlg-- 

int  n=95;
char cBuf[]="       ";        // A temporary string buffer
wsprintf(cBuf,"%3d",n);       // Format n as a string in cBuf
SendDlgItemMessage(hDlg, IDC_EDIT, WM_SETTEXT,
                                    0, (LPARAM)cBuf);   //send it

wsprintf() can't format floating point or double precision variables
     Use C library function sprintf()

Example: Edit control IDC_EDIT in dialog box w/ handle hDlg-- 
     Supposedly contains a "decimal integer" (e.g., a test grade) 
Want to extract contents of edit control & store as integer (grade)--

int grade;
char cBuf="       ";
SendDlgItemMessage(hDlg, DLI_EDIT, EM_GETLINE,
                                   0, (LPARAM)cBuf);      // get string
sscanf(cBuf,"%3d",&grade);                          // convert to integer


MODELESS DIALOG BOXES--

Popup windows that remain on screen for extended periods
Allow user to switch to other windows
Frequently used for small "tool" windows, movable on screen

Defined in a resource template (like modal dialog box)
     (No special style)
Use different functions to create dialog box and make it visible on screen:
     CreateDialog() instead of DialogBox()
     CreateDialogParam() instead of DialogBoxParam()

Messages for modeless dialog boxes sent to the parent window
Modify main program's msg loop to divert messages to dialog box function
     (if the message is intended for the dialog box)

IsDialogMessage(hDlg, &msg) does diverting
     Determines if  message is intended for specified dialog box
     If so, dispatches it to dialog box's message-processing function
     Returns TRUE if message was processed by dialog box function
          Message should not be dispatched to the main window's WndProc()    
     So main message loop should be modified--

HWND hModeless=NULL;    /* modeless dialog box window handle */
while (GetMessage(&msg, NULL, 0, 0))
   if (hModeless == NULL || !IsDialogMessage(hModeless, &msg))
      {
      TranslateMessage(&msg);
      DispatchMessage (&msg);
      }

To remove a modeless dialog box--
     Use DestroyWindow() instead of EndDialog() 

Modeless dialog boxes should contain a system menu button
     User can close by double clicking that button
           Sends a WM_CLOSE message to dialog box function
To make the modeless dialog vanish:
     Call DestroyWindow()--

case WM_CLOSE:
   DestroyWindow(hDlg);
   hModeless = NULL;
   return(TRUE);


COMMON DIALOG BOXES--

Standard dialog boxes in Windows that do things like:
     Opening/saving files
     Searching/replacing text
     Choosing colors
     Choosing fonts
     Getting/changing information on printers 

Windows contains a library of functions that invoke these dialog boxes

To display a common dialog box:
     Call single function from library 
          Don't have to set up a .rc template
          Don't have to write a dialog box procedure

COMMDLG.DLL provides:
     Standard dialog box template 
     Default dialog box procedure 
          Processes messages from the dialog box controls

COMMDLG.H header file must be included
     Defines the common dialog box functions
     Structures necessary to use dialog boxes

Steps in Setting Up and Using a Common Dialog box--

(All common dialog box library functions used in the same way)

-Initialize fields of a structure with data needed by dialog box
-Set up pointer to structure in library function
-Call library function, passing it the pointer
-Library function creates/displays dialog box
-User interacts with dialog box and causes it to be removed
-Library function returns control to application
-Application retrieves information returned in structure

Some Common Dialog Box functions (check online help for details):

ChooseColor(CHOOSECOLOR* cc)--
     Displays dialog box with palette of available colors
     Allows user to choose one and/or create a new one
     rgbResult member of cc will contain the RGB values of color selected

ChooseFont(CHOOSEFONT* cf)--
     Displays dialog box with lists of available fonts, point sizes
     User selects font, sample text is displayed
     Member variables of cf will contain information on font selected

GetOpenFileName(OPENFILENAME* ofn) / GetSaveFileName(OPENFILENAME* ofn)--
     Each displays dialog box with list of file names, directories, drives
     (in familiar Windows "Open"/"Save" format)
     User indicates which file to open/save
     lpstrFile member of ofn will contain:
          drive designator, path, filename, extension of selected file
    (Example later)

FindText(FINDREPLACE* ft)--
     Displays dialog box with an edit control
     User can use it to search for (and optionally replace) a string

See the Petzold COLORS3.C for simple example of using ChooseColor common dialog box