Site hosted by Angelfire.com: Build your free website today!

Home
DelphiZeus
8. Using Windows Dialogs
Create Dialog Boxes

Home



Windows Dialogs
As the name implies, a Dialog is a window an application creates to give Information and get user input. In Delphi there is no standard Dialog Window Creation from templates. Delphi uses a TForm create to make it's Dialogs. A templete Dialog is suppose to make temporary input window creation easier, and use less code. Instead of creating a PopUp window and then adding controls on it with CreateWindow( ), you make a resource templete in a .RES resource and call the API DialogBox( ) or CreateDialog( ) functions. You may use fewer lines of code in your program for a templete Dialog box, however, it may be more "work" for you since you will need to write and compile a resource file (.RES) and then run your program to see if this new Dialog has the controls in the correct positions. Also instead of Pixels, they use a measurement called "Dialog Box units", which can be confusing, since these are different for horizontal and vertical units, , , And will change with the User's choosen Display PixelsPerInch setting (normal font, large font).

Here we will make and use Resource Templates to call the API DialogBox( ) function. You may want to read the Win32 API Help for index "Dialog Boxes". I will use DialogBox( ) to create a modal Dialog in this first Dialogs program example. You will need to create a Dialog Resource file "Dlg1.RES" for that.

Dialog Resource Creation
You will need to use the Delphi Resource compiler "brcc32.exe" to compile a dialog resource. There is no documentation for templete Dialogs resource creation in Delphi help. But you can read some about this in the Win32 API Help under index "DIALOG Resource". The .RES files that the brcc32.exe creates are "Windows" resource files, not resource files intended Only for Delphi or Pascal applications. The syntax for resource creation in Delphi's brcc32.exe is C code, NOT Pascal. There are specific coding methods, syntax and Identifiers for Resource creation, you can get some information about this in the Win32 API Help under index "Resources". You can click the >_> arrows to read the many pages about creating resource for the Windows system.

    NOTE - Why is this resource creation .RC in C Code and Delphi uses Pascal? It may be because resources in a program are accesed by the Operating System (Windows, using C code methods) and not directly by the program. So resource creation must follow the rules and syntax of the Operating System, which will be in C code.

General Resource creation code - To place a resource Item into a Resource Creation File (.RC) you would use this general format of at least three parameters -

Identifier   Resource-Type   Additional-Resource-Definitions

The "Identifier parameter" can be a text "String" name or a number ID (Word value),
The "Resource-Type parameter" can be one of the many Windows "Pre-Defined" resource-types or your own custom type, the Additional-Resource-Definitions will be different according to the type of resource it is. Here is the Code syntax for an Icon in a .RC file -
    Identifier  ICON  filename
and some code for 2 Icons
MyIcon  ICON  IconMy.ico
12  ICON  aIcon.ico
The Identifier can be text (MyIcon) or a number (12), and the Resource-Type is a standard ICON, and the Additional-Resource-Definitions for an ICON is the name of a file.

A Resource Creation for a Dialog will use the Window's standard DIALOG Resource-Type, the Additional-Resource-Definitions will be the Position and Size (Top, Left, Width and Height) and additional Style and Caption parameters. Let's start with a very simple Dialog .RC file.
MyDialog DIALOG  12, 10, 206, 86
   STYLE WS_POPUP | WS_DLGFRAME | WS_CAPTION
   CAPTION " A Dialog Form"
   FONT 10, "MS Sans Serif"
   {
   LTEXT "Simple Dialog"  200, 8, 6, 196, 8
   PUSHBUTTON "OK"   IDOK, 48, 71,  32, 12
   }
The "MyDialog" is the name of the resource, like "MyIcon" in the resource creation line

MyIcon  ICON  Floppy.ico

for an Icon in a .RC file.

This MyDialog templete, creates a dialog box window with a Client Area 206 dialog-units wide and 86 dialog-units high, 12 units from the Left of the Parent Window and 10 units from the Top. There are 2 controls on it, a Static Text and a Button.
The DIALOG is the type of resource, the 12, 10, 206, 86 are standard Top, Left, Width, Height parameters for the Dialog box (these are NOT pixels, they are Dialog Box units, see Win32 API Help index "GetDialogBaseUnits"). The Top and Left are relative to the Parent Window's Top and Left as the 0 point. The Width and Height are for the Client Area of the Dialog Box, NOT the Bounding Rectangle for the Dialog Window. Next is -
STYLE WS_POPUP | WS_DLGFRAME | WS_CAPTION
- which sets the window creation style of the Dialog window (the | are C code for Pascal "or"). Look at the window creation Styles in Win32 API Help for CreateWindow( ). There are several addtional Dialog styles. -
DS_LOCALEDITTells the system that edit controls in this dialog box will use memory in the application's data section. By default, edit controls in dialog boxes use memory outside the application's data section (system memory). If this flag is NOT used, EM_GETHANDLE and EM_SETHANDLE messages must not be used for a dialog Edit, since the text memory buffer for the edits is not directly accessable by this program.
DS_MODALFRAMEMakes a dialog box with a Modal dialog box border that you can combine with a title bar and System menu adding the WS_CAPTION and WS_SYSMENU styles.
DS_NOIDLEMSGStops the WM_ENTERIDLE messages that Windows would normally send to the owner window of the dialog box, while the dialog box is displayed.
DS_SYSMODALCreates a system-modal dialog box. Should only be used if there is a problem from the system, like lack of resources, no memory.

If you use the style WS_CAPTION then the line -
CAPTION " A Dialog Form"
will place that string in the Caption of the Dialog. The line -
FONT 10, "MS Sans Serif"
sets the Font face and size for all controls in the Dialog. The { and } corespond to Pascal begin and end. Between these { } you put the controls you want to be in the Dialog, a PUSHBUTTON is a Button, the parameters of this button follow the PUSHBUTTON, like this -

PUSHBUTTON  "Text on Control"   IDNUMBER, Left, Top, Width, Height

these are in Dialog units not pixels, The Line-
LTEXT "Simple Dialog" 200, 8, 6, 196, 8
Has the Control-Type LTEXT, which will make a Static Text Control, that is Left Aligned.

Some more Dialog Controls -
the syntax for dialog controls is

    controlName  text, IDnumber, Left, Top, Width, Height,  Style,  Extended-Style

Below is a list of Standard controls that the Resource Compiler will recognize -
DEFPUSHBUTTON "Cancel" IDCANCEL, 8, 67,  32, 12
PUSHBUTTON "a Button"   501, 108, 71,  44, 12,
LTEXT "Static Text Left aligned"  201, 5, 21, 196, 24
CTEXT "Static Text Centered"     202, 18, 12, 170, 8
RTEXT "Static Text Right Aligned"     203, 9, 25, 100, 8
ICON  "IconResName" -1, 1,1,0,0
EDITTEXT 300, 9, 47, 180, 50, ES_MULTILINE, WS_EX_CLIENTEDGE
CHECKBOX "Check Box", 100, 10, 60, 69, 8
AUTOCHECKBOX "Auto CheckBox", 101, 140, 60, 61, 8
RADIOBUTTON "radio", 400, 8, 32, 64, 8
AUTORADIOBUTTON "needs WS_GROUP", 401, 8, 42, 64, 8, WS_GROUP
GROUPBOX "GroupBox", -1, 4,22,150,42
SCROLLBAR 600, 4, 38, 180, 8, SBS_HORZ
COMBOBOX  703, 2, 2, 110, 10, WS_CLIPSIBLINGS
If to give a value of -1 to the IDnumber, the IDnumber will not be used for that control. The text parameter is optional, and can be left out entirely or you can put an empty string "" . If you place an ampersand (&) character in the text, it indicates that the next character is used as a mnemonic (hot key) character for the control. When the control is displayed, the ampersand is not shown, but the mnemonic character is underlined. The user can click the control by pressing the keyboard key corresponding to the underlined mnemonic character. To use the ampersand as a character in a string, insert two ampersands (&&). . The Style and Extended-Style parameters are not always used like in the CreateWindow( ) function. A Dialog creation will ignore some of the style and Extended-Style bits for certain controls. You can also create other window's controls not in this list, by using CONTROL in it's control type and then setting a ClassName parameter.
See "Including COMMON CONTROLS in a Dialog" below.



Dialog Box Measurements, Dialog Box Units
As you have seen, the Resource Dialog Templetes use "Dialog Units" instead of "Pixels", like are used in the CreateWindow( ) function. A Reason for this is that Dialog Boxes are suppose to "Simplify" making a Temporary Popup window, so these Dialog Boxes will Resize every thing in the dialog box according to the current PixelsPerInch (font size) that is set for your computer Display. Which is what you are suppose to do in all of your windows (Main Forms). And for the most part, if your Dialogs are simple, you do not need to worry about this measurement conversion, since everything in the dialog will be resized. . . But if you will have run-time controls created in your dialog box in it's WM_INITDIALOG message using the CreateWindow( ) function, then you will need to Convert Dialog units to Pixels or Pixels to Dialog Units, by using the dialog box base unit. To get the "dialog box base units" for "Conversion", , you can call the function GetDialogBaseUnits( ) which will return a Cardinal value that has these dialog box base units. To make this even more confusing, there is a different dialog box base unit for horizontal and vertical measurements. The LOWORD of the result contains the horizontal dialog box base unit, and the HIWORD contains the vertical dialog box base unit. You then will need to use a conversion factor of Four for the horizontal and a factor of eight for the vertical. Some code to demonstrate the conversions -
var
DialogUnits: Cardinal;
Xpixel, Ypixel, Xdialog, Ydialog: Integer;
begin
DialogUnits := GetDialogBaseUnits;
Xdialog := 120;
Ydialog := 92;
Xpixel := Round((Xdialog * LOWORD(DialogUnits)) / 8);
Ypixel := Round((Ydialog * HIWORD(DialogUnits)) / 4);

Xpixel := 74;
YPixel := 20;
Xdialog = Round((Xpixel * 4) / LOWORD(DialogUnits);  
Ydialog = Round((Ypixel * 8) / HIWORD(DialogUnits);
end;
I do Not do any pixel or dialog unit conversions in this Dialogs Program, but you should be aware that the dialog measurements are NOT pixels, AND that they will change if the display font size (PixelsPerInch) changes.



Dialog Box Creation Functions
A Dialog Box can be Modal or Non-Modal, , the DialogBox( ) function creates a Modal Dialog Box, the CreateDialog( ) function creates a Non-Modal Dizlog Box. In this first Dialog Program, I will only create a Modal Dialog Box, and in the Next Program I will create a Non-Modal Dialog Box.

Using -   DialogBox( ) function;
The DialogBox( ) function is defined in windows.pas as -
function DialogBox(hInstance: HINST; lpTemplate: PChar;
      hWndParent: HWND; lpDialogFunc: TFNDlgProc): Integer;
The hInstance parameter is the program's hInstance, the lpTemplate is the text name for the DIALOG in the program's resources, , the hWndParent parameter is for the owner or parent window of the dialog box, ussually the main Window, the lpDialogFunc is a Pointer type where you put the address of the Function that will do the Message processing for the dialog box. And the result of DialogBox( ) is the integer that is placed in the nResult parameter of the EndDialog( ) function. (The TFNDlgProc type for the lpDialogFunc parameter, is NOT defined as a special type, it is just given a plain old "Pointer" type, I guess the name of TFNDlgProc type is suppose to be descriptive, but it can be confusing when you try to match types).

Look at the "procedure DoDialog" in the Dialogs Program below. You will see that it sets some variables used in the Dialog's WM_INITDIALOG message, and then calls the DialogBox( ) function. The lpTemplate parameter in DialogBox( ) is a PChar of the Resource Name, and the Parent Window (hWndParent) is hForm1, and the lpDialogFunc has to be set to the address of a Dialog Message Function (see API help "DialogProc"). The Result of the DialogBox( ) is tested to see if it is IDCANCEL, which is used in the nResult paramteter of the EndDialog( ) function if the dialog's caption button "X" is used to close the Dialog.

DialogProc, the Dialog's message processing function
This DialogProc is like the WndProc we have seen in our programs, and is used for getting the Dialog Window messages, (see function DialogProc below). There are some differences between the WndProc and the DialogProc, here is how the DialogProc is defined in the API Help -
BOOL DlgProc(HWND hwndDlg; UINT message; 
             WPARAM wParam; LPARAM lParam);

Pascal -

function DlgProc(hwndDlg, message: Cardinal; 
                 wParam, lParam: Integer): BOOL;
Notice that the Result is a BOOL and not an Integer, like the WndProc we have seen before. The Result of this function is suppose to be True or False, but some messages require a Result as a Handle or other integer value, so you might think of True as integer value One, and False as integer value Zero. A Result of True (one) means that the message has been Handled and no Default system processing is to be done, a False (zero) Result means that the system should do the default message processing for a window.
If a dialog box message fuction does not process a message, it must set the Result to FALSE (zero) to direct Windows to process the messages internally. The only exception to this rule is with the WM_INITDIALOG message. The message function must return FALSE (zero), to direct Windows to further process the WM_INITDIALOG message. In any case, your Dialog message function must NEVER call DefWindowProc, like the WndProc have done before.
NOTE -The DialogProc Result is a 4 byte BOOL type, However this seems to be left over from 16-bit Windows, the System seems to read this as an Integer, and Should be an Integer Type for 32-Bit Pascal, the same as used in the Window Proc Result. For this first example program, I will change this to an Integer type, and Setting the Result to Zero for False and to Any number above Zero for True (One). . .
function DlgProc(hwndDlg, message, wParam, lParam: Integer): Integer;
DialogProc messages
Most of the messages for a DialogProc are just like the messages we have processed before in the Window Proc (MessageProc) functions, but generally there is less to do in dialog message handling. I set the Default Result to Zero at the begining of this function, so it will call for the system to do the default message processing for messages. There are several dialog messages that are not ever used in a general WndProc, most important is the WM_INITDIALOG

When the WM_INITDIALOG is sent the dialog window is being created, so with this message, you set up your controls (text, button states) here. With this message you need to initialize your controls, hide controls that are not needed, assign fonts to controls, place Text into controls from String variables set before the Dialog is shown. Since a dialog is created from a template, the control's handles are not known, instead the control's ID numbers are used for access and reference instead of Handles, like we have done before. You can use many of the control's SendMessage or change states (Enable( ), ShowWindow( )) by using the control's ID to get the controls handle with GetDlgItem(hWnd,IDNUMBER). There are Special Dialog functions for use with ID numbers (SendDlgItemMessage, CheckDlgButton, SetDlgItemText, GetDlgItemText). In the WM_COMMAND message the LOWORD(wParam) is the control's ID number. So you can use a Dialog function with the ID number.

The other dialog message used in this program is the WM_CTLCOLORDLG message, which will get the brush handle used to color the bakground od the client area of the Dialog.

You can Also assign ID numbers to controls Not in a Dialog Box. In this first example program, I will assign ID numbers for all of the controls on the main form, I will not get their "Handles" as we have done before. The ID numbers will be used in the MessageProc and anywhere it is nessary to reference the control.

Closing a Modal Dialog
Windows supplies a function to close a Modal Dialog called EndDialog( ), which looks like this -
function EndDialog(hDlg: HWND; nResult: Integer): BOOL;
This has two parameters, the hDlg will be the Handle of the Dialog window to destroy, and the nResult is the Result that will be returned in the DialogBox( ) function. This EndDialog function is called in the DialogProc to Close the Dialog, you will also need to set the DialogProc Result to One (True), so the default processing does not happen. See the code in the Dialog Program below.



Dialogs Program


Dialog Resource Creation Code
The first thing you will need to do is create a Dialog Templete in a Resource file. The code for this is Dlg1.RC file is below. Remember that the Units for control placement are NOT pixels but Dialog Units. I have put 2 Icons in the Resource to be in ICON dialog controls, if you set the "ID Number" to -1, then the control does not use an ID number. I have used several types of controls in this dialog to show you how to place controls in a dialog. You should try and change these controls, , and then place more controls in this dialog to see how these dialogs work.

For this Dialogs program here is the code for the "Dlg1.rc" file -
Z1 ICON Done2.ICO
Z2 ICON Flop.ICO

First DIALOG  12, 10, 206, 86
     STYLE WS_POPUP | WS_DLGFRAME | WS_CAPTION | WS_SYSMENU
     CAPTION " A Dialog Form"
     FONT 10, "MS Sans Serif"
     {
     CTEXT "Dialogs are really NON Delphi"     200, 18, 1, 170, 10
     ICON  "Z1" -1, 1,1,0,0
     ICON  "Z2" -1, 189,1,0,0
     CTEXT "Checkbox was Unchecked"     201, 18, 12, 170, 8
     LTEXT " "  202, 5, 21, 196, 24
     EDITTEXT      300, 14, 47, 100, 10
     AUTOCHECKBOX "Show &MessageBox", 100, 10, 60, 69, 8
     AUTOCHECKBOX "&Check me", 101, 140, 60, 61, 8
     DEFPUSHBUTTON "&OK"   IDOK, 48, 71,  32, 12, WS_GROUP
     PUSHBUTTON "set Edit &Text"   401, 108, 71,  44, 12,
     }
Complie this Dlg1.rc file with brcc32.exe. Notice that I have put the "&" ampersand charater in the text for all of the button controls, which will make the next Character a "HotKey" to click that button, if the Edit does Not have focus. I don't know why you do not need to have -
#include <windows.h>
- with these, but they compile without it.


Program Code
This program shows how to create and use a windows Dialog. You must have the Dlg1.RES file complied from the code above. You will see how to use the DialogBox( ) function and how the DialogProc( ) is used for dialog message processing, like the Window Proc in an Application, however there are some differences from the MessageProc( ) function. Look at the code in the DialogProc( ) function. You will see the WM_INITDIALOG message, which is a message that is unique to a Dialog Proc. In this message you will set the Icon for the Dialog Box, set the font for the Static 200 control, set the Text of the 202 Static control and other dialog control initialization. There are the WM_COMMAND and WM_CLOSE messages, which you have seen before in Wnd Proc. There is one other unique dialog messgage, WM_CTLCOLORDLG, which sets the brush for the dialog's background color.

On this Main Form there are Six controls, in the programs before I would get the Handle of a control when it is created, but in this program, I will assign a unique ID number to each control, and not get a Handle for the control. This ID will be used to reference the controls in the same way used for Dialog boxes. Look at the MessageProc in the WM_COMMAND message and see that the LOWORD(wParam) is used for a control test, instead of the control's Handle in the LParam, as we have used before. Inteaed of the usuall SendMessage( ) function, to set the font for a control, I use the Dialog function "SendDlgItemMessage" and the ID number of that control, as you see these dialog functions can be used in window that are NOT dialogs, , in any window where the controls have ID numbers. I use four ID numbers for constants, like ID_EXIT, for the controls on the Main Form, you may also set constants of the Dialog control IDs.

program Dialogs;
{this program will use DialogBox function to create a
templete Dialog Box, The resource templete for the dialog
is in the Dlg1.RES resource}

uses
  Windows, Messages, smallUtils;

{$R *.RES}
{$R Dlg1.RES} // Include dialog resource

var
wClass: TWndClass;
hForm1, Font1, hLabel3, Brush1: Integer;
mainMsg: TMSG;
Rect1: TRect;
DlgText, DlgEditText: String;
DlgChk, Dlg2Chk: Boolean;

const
{because there are so many zeros, I set a constant as a Zero value}
Zero = 0;
{I give the three buttons on the main Form ID numbers as constants}
ID_EXIT = 100;
ID_ShowDlg = 101;
ID_DlgCB = 102;
ID_Edit1 = 303;

{- - The Result of this DialogProc is listed
as Type BOOL, a 4 byte Boolean value, , , However this seems to be left over
from 16-bit windows, the system seems to read this as an Integer, and use
this function just like the WindowProc (MessageProc), where you can pass
integers as the Result, see the  WM_CTLCOLORDLG  message below}
function DialogProc(hWnd, Msg, wParam, lParam:Integer): Integer{BOOL}; stdcall;
{this is the Message Proc for the Dialog Box. Some of the messages
here are like WndProc (MessageProc) messages (WM_COMMAND, WM_CLOSE)
and othes (WM_INITDIALOG, WM_CTLCOLORDLG) are not. In a Dialog Proc 
a DlgItem ID is often used instead of a hWnd}
var
OKrect:TRect;
Buffer: Array[Zero..255] of Char;
begin
Result := Zero {False};
case Msg of
  WM_INITDIALOG: begin
{WM_INITDIALOG is where you set your Dlg Items properties. There are
special DlgItem functions (SendDlgItemMessage, SetDlgItemText) to help
with this.}
               DlgEditText := '';
               SendMessage(hWnd, WM_SETICON, 1, LoadIcon(hInstance,'Z1'));
         {a default Icon is used in Dialogs, you should set the Icon}
               SendDlgItemMessage(hWnd,200,WM_SETFONT,Font1, Zero);
         {SendDlgItemMessage uses an ID number instesd of hWnd}
               CheckDlgButton(hWnd,100,BST_CHECKED);
               
    {NOTICE - that the next IsDlgButtonChecked function has the hForm1 and
     NOT the hWnd, this gets the Check State of the checkBox on the Main Form,
     NOT on the Dialog Box, this is to show you that the Dialog functions can
     be used with non-dialog windows}
               if IsDlgButtonChecked(hForm1, ID_DlgCB) = BST_CHECKED then
               //if SendMessage(hCheckCB,BM_GETCHECK,0,0) = BST_CHECKED then
                 begin
                 {you can get info from your main Form to set Dialogs}
                 SetWindowText(GetDlgItem(hWnd,201),'Checkbox is Checked');
           { you could use the SetWindowText, but SetDlgItemText does the same
             SetDlgItemText(hWnd,201,'Checkbox is Checked');}
                 EnableWindow(GetDlgItem(hWnd,101),False);
                 {most of the change Window functions will work in Dialogs}
                 end;
               {SetWindowText(GetDlgItem(hWnd,202),PChar(DlgText));}
               SetDlgItemText(hWnd,202,PChar(DlgText));
               GetDlgItemText(hForm1, ID_Edit1, Buffer, 256);
               SetDlgItemText(hWnd,300,Buffer);
               GetWindowRect(GetDlgItem(hWnd,IDOK),OKrect);
               SetCursorPos(OKrect.Left+10,OKrect.Top+10);
               end;
  WM_COMMAND: begin
{like the WM_COMMAND in MessageProc, but the wParam may be used instead
of the LParam, you can get the ID number of the control, instead of it's
Handle}
            if LOWORD(wParam) = IDOK then
              begin
              {Dialogs use DlgItem ID's in the LOWORD(wParam)}
              if (IsDlgButtonChecked(hWnd,101) = BST_CHECKED) then
              Dlg2Chk := True;
              if (IsDlgButtonChecked(hWnd,100) = BST_CHECKED) then
                begin
                MessageBox(hWnd,'Dialog Checkbox was checked',
                  'Dialog exit',MB_OK or MB_ICONQUESTION);
                DlgChk := True;
                end;
              DlgEditText := GetWindowStr(GetDlgItem(hWnd,300));
    {unlike MessageProc you use EndDialog to kill a Modal Dialog}
              EndDialog(hWnd, IDOK);
              Result := 1{True};
    {You need to set the Result to One when you call EndDialog}
              end else
              if LOWORD(wParam) = 401 then
              SetDlgItemText(hWnd,300, 'New Edit Text')
              else
              if LOWORD(wParam) = 101 then
              MessageBox(hWnd,'Dialog Checkbox was clicked',
                  'Click It',MB_OK or MB_ICONQUESTION);
            end;
  WM_CLOSE:
    begin
{unlike MessageProc you use EndDialog to kill a Modal Dialog}
    EndDialog(hWnd, IDCANCEL);
    Result := 1 {True};
    end;
  WM_CTLCOLORDLG: Result := Brush1;
{this WM_CTLCOLORDLG is sent to the Dialog's DialogProc and you set the
Result to the color brush used to do the WM_ERASEBKGND message.
You can Leave this message out to get the normal button face color.
This message is rarely used in dialogs and I used it just to show you how}
  WM_CTLCOLORSTATIC:
    begin
    SetBkColor(wParam, $FFFFCC);
    Result := Brush1;
    end;
end;

{You do NOT call any Default message handling for a DialogProc.
You do not Call DefWindowProc( ) or CallWindowProc( ), the default message
handling will be called if you have the Result as Zero}
end;

procedure DoDialog;
var
Dsize: TdriveSize;
begin
if hLabel3 <> Zero then
  begin
{hLabel3 is created according to the check box on the Dialog Box}
  DestroyWindow(hLabel3);
  while PeekMessage(mainMsg, Zero, Zero, Zero, PM_REMOVE) do
  DispatchMessage(mainMsg);
  hLabel3 := Zero;
  end;
Dsize := DiskSpace('C:\');
DlgText := 'C drive''s Total capacity is '+Int2Str(Dsize.TotalS)+
           ' bytes - And it''s free space is '+ Int2Str(Dsize.FreeS);
{DlgText is used in a Static Text control in the Dialog, you should set all
the variables needed for a dialog before you call DialogBox( )}

{DialogBox will create a Modal Dialog from the Resource DIALOG of 'First',
with hForm1 as Parent, and the DialogProc as the WndProc (MessageProc)}
if DialogBox(hInstance, 'First', hForm1, @DialogProc) = IDCANCEL then
  begin
  {the DialogBox function will return the integer used in the EndDialog
  function, which will close this dialog box}
  MessageBox(hForm1,'Dialog was CANCELED',
      'a Dialog result',MB_OK or MB_ICONINFORMATION);
  Exit;
  end;

if DlgChk then
MessageBox(hForm1,'This is DlgChk = True',
      'a Dialog result',MB_OK or MB_ICONQUESTION);
      
if Dlg2Chk then
  begin
{the Dlg2Chk comes from the OK button click on the Dialog Box
and will create a Static Label here}
  hLabel3 := CreateWindow('Static', 'that Check me was Checked',
         WS_VISIBLE or WS_CHILD or SS_CENTER, 6, 200, 300, 29,
         hForm1, Zero, hInstance, nil);
  SendMessage(hLabel3, WM_SETFONT, Font1, Zero);
  end;

SetDlgItemText(hForm1, 201, @DlgEditText[1]);
{instead of SetWindowText, I use SetDlgItemText, with the ID set as 201
which is the second Static (Label) control}
DlgChk := False;
Dlg2Chk := False;
end;

function MessageProc(hWnd,Msg,wParam,lParam:Integer):Integer; stdcall;
begin
{this MessageProc uses ID numbers instead of Handles in the WM_COMMAND
message, just like is used in the DialogProc}
case Msg of
    WM_COMMAND: if LOWORD(wParam) = ID_EXIT then
       PostMessage(hForm1,WM_CLOSE, Zero, Zero)
       else if LOWORD(wParam) = ID_ShowDlg then DoDialog;

    WM_DESTROY: PostQuitMessage(Zero);
end; // case
Result := DefWindowProc(hWnd,Msg,wParam,lParam);
end;


begin  //  MAIN BEGIN / / / / / / / / / / / / /
DlgChk := False;
Dlg2Chk := False;
hLabel3 := Zero;
Brush1 := CreateSolidBrush($FFFFCC);

Font1 := CreateFont(-18, Zero, Zero, Zero, FW_BOLD, Zero, Zero,
                    Zero, ANSI_CHARSET,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
                    DEFAULT_QUALITY, VARIABLE_PITCH or FF_SWISS,'Arial');

with wClass do
  begin
    style :=        CS_PARENTDC or CS_BYTEALIGNWINDOW;
    hIcon :=        LoadIcon(hInstance,'MAINICON');
    hInstance := SysInit.hInstance;
    lpfnWndProc :=  @MessageProc;
    hbrBackground:= COLOR_BTNFACE+1;
    lpszMenuName := nil;
    lpszClassName:= 'Form Class';
    hCursor :=      LoadCursor(Zero, IDC_ARROW);
    cbClsExtra := Zero;
    cbWndExtra := Zero;
  end;

RegisterClass(wClass);

SetRect(Rect1,Zero,Zero,430,240);
if not AdjustWindowRect(Rect1,WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU,False)
  then SetRect(Rect1,Zero,Zero,438,268);

hForm1 := CreateWindow(wClass.lpszClassName, 'Doing Dialogs',
    WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU,
    (GetSystemMetrics(SM_CXSCREEN) div 2)-200,
    (GetSystemMetrics(SM_CYSCREEN) div 2)-160,
    Rect1.Right-Rect1.Left, Rect1.Bottom-Rect1.Top,
    Zero, Zero, hInstance, nil);

{NOTICE - I create ALL controls here without getting a Handle
for them, Instead I assign them an ID number (200 for this first Static control)
and use that ID number as a "Dialog" control ID}
CreateWindow('Static', 'Dialogs Demo',
       WS_VISIBLE or WS_CHILD or SS_CENTER,8,8,388,22,hForm1, 200,hInstance,nil);
{Instead of using the SendMessage function, I use the SendDlgItemMessage, and use
the ID number of the control, just like is used in a Dialog's box message Proc.
This will work with any window, even if it is NOT a Dialog Box}
SendDlgItemMessage(hForm1, 200, WM_SETFONT, Font1, Zero);

CreateWindow('Static', 'Put the Text you want to see in the dialog below'+
       #10'the Text you put in the Dlg Edit will show here',
       WS_VISIBLE or WS_CHILD or SS_LEFT,10,38,290,28,hForm1, 201,hInstance,nil);
SendDlgItemMessage(hForm1, 201, WM_SETFONT, GetStockObject(ANSI_VAR_FONT), Zero);

CreateWindow('Button','E x i t',
    WS_VISIBLE or WS_CHILD or BS_PUSHBUTTON or BS_TEXT,
    320,200,74,24, hForm1, ID_EXIT, hInstance,nil);
{this Exit Button is created without getting it's Handle, by assigning
an ID number ID_EXIT, I will use that to reference this button}

CreateWindowEx(WS_EX_CLIENTEDGE,'Edit','type here to be in Dlg Edit',
    WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL,
    16,78,410,21,hForm1, ID_Edit1,hInstance,nil);
SendDlgItemMessage(hForm1, ID_Edit1, WM_SETFONT,
                   GetStockObject(ANSI_VAR_FONT), Zero);

CreateWindow('Button','Show Dialog',
    WS_VISIBLE or WS_CHILD or BS_PUSHBUTTON or BS_TEXT,
    30,160,84,24, hForm1, ID_ShowDlg, hInstance,nil);
SendDlgItemMessage(hForm1, ID_ShowDlg, WM_SETFONT,
                   GetStockObject(ANSI_VAR_FONT), Zero);

CreateWindow('Button','Dialog checkbox',
    WS_CHILD or BS_AUTOCHECKBOX or WS_VISIBLE,
    20,130,150,24, hForm1, ID_DlgCB,hInstance,nil);
SendDlgItemMessage(hForm1, ID_DlgCB, WM_SETFONT,
                   GetStockObject(ANSI_VAR_FONT), Zero);


ShowWindow(hForm1, SW_SHOWDEFAULT);
while GetMessage(mainMsg, Zero, Zero, Zero) do
  begin
    TranslateMessage(mainMsg);
    DispatchMessage(mainMsg);
  end;
DeleteObject(Font1);
DeleteObject(Brush1);
DlgText := '';
DlgEditText := '';

end.

Be sure to test the mnemonic (HotKey) keyboard charaters assigned to the Dialog's Button Controls by the "&" charater, which will make the mnemonic character underlined on the control. But these will only work if the Edit Control Does Not Have Focus. If you press the "o" key the OK button will be clicked and the Dialog will close. You should change the code in the Dlg1.RC and change and add controls to the dialog box, so you can get some knowledge on how the code in the .RC file affect the dialog box. Also you should change the "Display Setting's" "Font Size" (from SmallFont to LargeFont, or from Large to Small) on your computer, using the Display Property Dialog Box (a windows Dialog Box), to see how this will change the Dialog measurement units and change the size of your dialog box and all of it's controls. You are suppose to change the size of everything in your main form according to the current Display PixelsPerInch setting. You may want to try and do this by getting the PixelsPerInch from the GetDeviceCaps(hDC, LOGPIXELSY) function.




Including COMMON CONTROLS in a Dialog
To create the Predefined control Classes in a dialog you would put the word "CONTROL" first and then use this general syntax , with these parameters:
CONTROL text, IDnumber, ClassName, style, x, y, width, height, extended-style
The X and width are in Horizontal dialog units which are 1/4 of the dialog base width unit. The Y and height are in Vertical units which are 1/8 of the dialog base height unit. The current dialog base units are computed from the height and width of the current system font. The GetDialogBaseUnits( ) function returns the dialog base units in pixels. You can create the same standard controls that you have seen in the previous example, like PUSHBUTTON, LTEXT, EDITTEXT, however there is no advantage to using this "Control" creation instead of the method shown before.

    Parameters - - - - - - - -

text - Specifies text that is displayed with the control. The text is positioned within the control's specified dimensions or adjacent to the control.This parameter must contain zero or more characters enclosed in double quotation marks ("). Strings are automatically null-terminated and converted to Unicode in the resulting resource file.
By default, the characters listed between the double quotation marks are ANSI characters, and escape sequences are interpreted as byte escape sequences. If the string is preceded by the L prefix, the string is a wide-character string and escape sequences are interpreted as 2-byte escape sequences that specify Unicode characters. If a double quotation mark is required in the text, you must include the double quotation mark twice.An ampersand (&) character in the text indicates that the following character is used as a mnemonic character for the control. When the control is displayed, the ampersand is not shown, but the mnemonic character is underlined. The user can choose the control by pressing the key corresponding to the underlined mnemonic character. To use the ampersand as a character in a string, insert two ampersands (&&).

IDnumber - Specifies the control identifier. This value must be a Word value in the range 0 through 65,535.

ClassName -
The Class Name of the control being defined, such as the Standard Control Classes, but you should probaly use the previous creation methods for Standard Controls -

BUTTON, COMBOBOX, EDIT, LISTBOX, SCROLLBAR, STATIC.

Or some of the "Common Controls", which is more what this creation method was intended for. The following are Text Contants and should not be put in Quotation marks -

TRACKBAR_CLASS, STATUSCLASSNAME, PROGRESS_CLASS, WC_TREEVIEW, WC_COMBOBOXEX, WC_TABCONTROL, TOOLBARCLASSNAME, REBARCLASSNAME, UPDOWN_CLASS, WC_LISTVIEW, WC_HEADER, TOOLTIPS_CLASS, DATETIMEPICK_CLASS, ANIMATE_CLASS


x - Gives the x-coordinate of the left side of the control on the Client area of the Dialog box. This value must be a Word value in the range 0 through 65,535. The coordinate is in dialog units and 0 is the left edge of the Client area of the dialog box.

y - Gives the y-coordinate of the top side of the control on the Client area of the Dialog box. This value must be a Word value in the range 0 through 65,535. The coordinate is in dialog units and 0 is the top edge of the Client area of the dialog box.

width - Specifies the width of the control. This value must be a Word value in the range 1 through 65,535. The width is in 1/4-character units.

height - Specifies the height of the control. This value must be a Word value in the range 1 through 65,535. The height is in 1/8-character units.

style - Specifies the control styles. Use the bitwise OR ( | ) operator to combine styles. Using this creation method does NOT prevent the Dialog Creation from Ignoring or not using the Styles that it normally does not use.

extended-style - Specifies extended (WS_EX_xxx) styles. You must specify a style in order to give an extended-style.




Sample Code for Common Controls -
This code is for a resource creation file that will produce a Dialog box with a ScrollBar, a TrackBar, a UpDown Button, and a StatusBar. Notice that I use the previous creation method for the Standard Controls, CTEXT and DEFPUSHBUTTON, because there is no advantage to using the "Control" method. Also Notice That the SCROLLBAR is created with this new method, and the Class Name "SCROLLBAR" is in Quotation marks, AND that the track Bar Class Name TRACKBAR_CLASS is NOT in quoatation marks, because it is a Text contant for "msctls_trackbar32" -
ComCtrl DIALOG DISCARDABLE 8, 6, 200, 120
     STYLE WS_POPUP | WS_DLGFRAME | WS_CAPTION | WS_SYSMENU
     CAPTION " CommCtrl Dialog Box"
     FONT 10, "MS Sans Serif"
     {
     CTEXT "Some ComCtrls"     200, 41, 3, 119, 10
     CONTROL "", 600, "SCROLLBAR", SBS_HORZ | WS_TABSTOP, 4, 25, 180, 8
     CONTROL "Track Bar" 700, TRACKBAR_CLASS, WS_VISIBLE | TBS_BOTTOM, 4, 40, 180, 16
     CONTROL "Up Down" 800, UPDOWN_CLASS, WS_VISIBLE | UDS_ALIGNRIGHT | UDS_ARROWKEYS, 14, 60, 9, 10
     DEFPUSHBUTTON "OK"   IDOK, 84, 84,  42, 12, WS_TABSTOP
     CONTROL "Status Bar" 900, STATUSCLASSNAME, WS_VISIBLE, 10, 10, 10, 10
     }


                           

Next
We have used a Dialog. It's time to learn how to create and use Non-Modal Dialogs and Scroll Bars in lesson 9
  9. Non-Modal Dialogs and Scroll Bars


       

Lesson -     One  Two  Three  Four  Five  Six  Seven  Eight  Nine  Ten  Eleven  Twelve  Thirteen  Fourteen




H O M E