Выбрать главу

Now we have the list of controls to create on the dialog

DEFPUSHBUTTON "&OK",IDOK,174,18,50,14

Here's the line for the OK button. The & in this case like with menus underlines the next letter "O", so that by pressing Alt+O the user can activate this control (part of the default processing I mentioned). IDOK is the control identifier. IDOK is pre-defined so we don't need to #define

it ourselves. The four numbers at the end are the left, top, width and height, all in dialog units.

This information should be purely academic, as you almost always use a resource editor to create dialogs, but knowing how to do it from text is sometimes necessary, expecially if you have no visual editor.

Two of the controls have an ID of IDC_STATIC (which is –1), this is used to indicate we never need to access them, so they have no need of an identifier. However it doesn't hurt to give them an ID and your resource editor might do so automatically.

The "\r\n" in the text of the static control is a CR-LF pair, the way windows represents a new line.

So! Having added that to your .rc file we need to write a Dialog Procedure to process message for this box. Don't worry this is nothing new, it's practicly the same as our main Window Procedure (but not exactly).

BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {

 switch(Message) {

 case WM_INITDIALOG:

  return TRUE;

 case WM_COMMAND:

  switch (LOWORD(wParam)) {

  case IDOK:

   EndDialog(hwnd, IDOK);

   break;

  case IDCANCEL:

   EndDialog(hwnd, IDCANCEL);

   break;

  }

  break;

 default:

  return FALSE;

 }

 return TRUE;

}

There are a few important differences between a dialog procedure and window procedure. One is that you DO NOT call DefWindowProc()

for message you don't handle. With dialogs this is done automatically for you (and will really screw things up if you do it).

Secondly, in general you return FALSE for messages you don't process, and TRUE for messages you do process, UNLESS the message specifies you return something else. Note that this is what we do above, the default is to do nothing and return FALSE, while messages we do handle break the switch() and return TRUE.

Thirdy, You do not call DestroyWindow() to close a dialog, you call EndDialog(). The second paramter is the value that is returned to whatever code called DialogBox().

Finally, instead of handling WM_CREATE, you handle WM_INITDIALOG to do any processing that needs to be done before the dialog appears, and then return TRUE to have the keyboard focus set to the default control. (You can actually handle WM_CREATE as well, but it is sent BEFORE any of the controls have been created, so you can't access them. In WM_INITDIALOG the controls have already been created).

Enough chit-chat, lets create it….

case WM_COMMAND:

 switch(LOWORD(wParam)) {

 case ID_HELP_ABOUT:

  {

   int ret = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);

   if (ret == IDOK) {

    MessageBox(hwnd, "Dialog exited with IDOK.", "Notice", MB_OK | MB_ICONINFORMATION);

   }

   else if (ret == IDCANCEL) {

    MessageBox(hwnd, "Dialog exited with IDCANCEL.", "Notice", MB_OK | MB_ICONINFORMATION);

   }

   else if (ret == –1) {

    MessageBox(hwnd, "Dialog failed!", "Error", MB_OK | MB_ICONINFORMATION);

   }

  }

  break;

  // Other menu commands…

 }

 break;

This is the code I used to create my about box, you can probably guess that this is to be merged into your WM_COMMAND handler, if you aren't clear on this aspect, you might want to review the section on menus. ID_HELP_ABOUT is the identifier of my Help→About menu item.

Since we want the menu on our main window to create the dialog, we obviously want to put this code in the WndProc() of our main window, not the dialog proc.

Now I stored the return value from the call to DialogBox() , this is just so you can observe the effects of pressing the two buttons, hitting Esc, Enter etc… from inside the dialog. It also illustrates how to use the return value from a dialog box to check for success, failure, a users choice, or whatever other information you choose to send back to the caller from the Dialog Procedure.

DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);

This is the only important part, and you can choose to put it wherever in your code that you want the dialog to come up. IDD_ABOUT is the id of the dialog resource. hwnd is the handle to the parent window of the dialog. AboutDlgProc() is of course the dialog procedure to use to control the dialog.

That's it! Sit IDD_UBU, sit.

A perticularly astute reader might eventually wonder, if DialogBox() doesn't return untill the dialog closes we can't process messages while it's up, so how does it work? Well the nifty thing about DialogBox() is that it has it's own message loop, so while the dialog is displayed, our message loop is out of the picture and the default loop is handled by windows. This loop also takes care of fun things like moving the keyboard focus from control to control when you press Tab.

Another effect of using DialogBox is that your main window is disabled untill the dialog is dismissed. Sometimes this is what we want, and sometimes it isn't, such as when we want to use a dialog as a floating toolbar. In this case we want to be able to interact with both out dialog and our main window, and this will be the focus of the next section.

Modeless Dialogs

Example: dlg_two

Now we take a look at CreateDialog(), DialogBox()'s sister function. The difference is that while DialogBox() implements it's own message loop and does not return untill the dialog is closed, CreateDialog() acts more like a window created with CreateWindowEx() in that it returns immediately and depends on your message loop to pump the messages as it does for your main window. This is termed Modeless, whereas DialogBox() creates Modal dialogs.

You can create the dialog resource just like you did for the last dialog example, you might also want to set the "Tool window" extended style to give it's title bar the typical smaller caption of toolbars. The dialog resource I created follows: