Adding Controls to the Dialog

Once the dialog has been created, we can add controls to it. For our example, we will add a text box to let the user type in their name, and also add two BUTTON controls ("OK" and "Cancel"):

CONTROL ADD TEXTBOX, hDlg, IdText&

, "", 14, 21, 134, 12, Style&, exStyle&

CONTROL ADD BUTTON, hDlg, 1, "&OK", 44, 38, 40, 14, %BS_DEFAULT or %WS_TABSTOP CALL Ok

CONTROL ADD BUTTON, hDlg, 2, "&Cancel", 90, 38, 40, 14 CALL Cancel

hDlg refers to the handle of the dialog you're adding the control to, as returned by the DIALOG NEW statement.

The next parameter IdText&, 1, and 2 in the example lines above) is the unique numeric identifier (ID) for the control. Whereas dialog handles are determined by Windows at run-time, controls use ID values that are specified by the programmer. By knowing the dialog handle and a control ID, we can identify and interact programmatically with any control on a DDT dialog using any of the control-related DDT statements.

In general, ID values should be kept within in the range 100 to 65535. It should also be noted that some values below 100 are reserved by Windows for special purposes. For example, the special ID value 1 (%IDOK) is usually assigned to a Button control that is to be activated when the ENTER key is pressed (this would typically be the "OK" button on a dialog). Similarly, the special ID value of 2 (%IDCANCEL) is usually assigned to a Button control that is to be activated when the ESCAPE key is pressed (typically this would be the "Cancel" button).

In general, two controls on a given dialog should not use the same ID value, as it prevents them from being identified uniquely. However, it is common to assign the special value -1& to plain Label (static) controls that will not have their content, style, or color changed at run-time.

It is always a good idea to plan the values of control identifiers carefully. For example, a set of related Option (radio) controls should use ID values that are ordered sequentially, as this makes it very easy to manipulate them as a group with the CONTROL SET OPTION statement, etc. Another common scheme is keep all the ID numbers for the controls in a specific range. For example, the first dialog in a program might use controls whose ID values are in the range 100 to 199, the second dialog might use the range 200 to 299, etc.

The identifier parameter is followed by the caption text for the control. The ampersand symbols "&" within the caption text fields is surprisingly helpful - the letter that follows the symbol specifies a command accelerator (hot-key). At run-time, the accelerator character is drawn underscored: OK and Cancel. In this case, the underscored character informs the user that pressing the ALT+O keys has the same effect as using the mouse to click the "OK" button. Similarly, the ALT+C combination will trigger the "Cancel" button.

Coordinates used in the CONTROL ADD statement are specified in the same terms (dialog units or pixels) as the parent dialog. The final Style& (primary style) and exStyle& (extended style) parameters tell Windows how to draw the control, and how the control should behave. These parameters are optional, and if omitted, receive default styles according to the type of control.

Each type of control has its own unique set of style options. Most of the equates have been predefined in the DDT.INC and WIN32API.INC files supplied with PowerBASIC. It should be noted that explicit (custom) style values replace the default values for the control. That is, custom styles are not additional to the default style values - your code must specify all necessary style parameters. This also applies to the extended styles parameter - if your code specifies a custom primary style, the default extended style will no longer be in effect either. In this case, an explicit extended style may also need to be added to the CONTROL ADD statement if an explicit primary style is specified.

The CONTROL ADD statement for the "OK" button includes the keyword CALL. This tells Windows to call the "OK" function each time the "OK" button is pressed. The "OK" function is simply a Callback Function that contains the code you want to execute when the button is pressed (or when some other control-related event occurs).

In this example, we want to assign the text from the text box control to a global string, and then close the dialog box. However, we first must check that our code is executed only in response to a "click" event - we would not want our dialog to end if some other notification message was sent to the callback! We do this by testing the values of the message parameters held in the CB.HNDL, CB.MSG, and CB.CTLMSG system variables:

CALLBACK FUNCTION Ok() AS LONG

IF CB.MSG = %WM_COMMAND AND CB.CTLMSG = %BN_CLICKED THEN

CONTROL GET TEXT CB.HNDL, %IDTEXT TO gsUserName

DIALOG END CB.HNDL, 1 ' Return 1

FUNCTION = 1

END IF

END FUNCTION

Similarly, we provide a Callback Function for the "Cancel" button, which will close the dialog box, ignoring any text entered into the text box:

CALLBACK FUNCTION Cancel() AS LONG

IF CB.MSG = %WM_COMMAND AND CB.CTLMSG = %BN_CLICKED THEN

DIALOG END CB.HNDL, 0 ' Return 0

FUNCTION = 1

END IF

END FUNCTION

Once the dialog has been created and the controls added, we are ready to display the dialog on the screen. In this example, we will create it as a Modal dialog. That means that when the DIALOG SHOW MODAL statement is executed, the execution of this portion of our program will block (halt) until the dialog is closed: (see Modal vs. Modeless below for more information on modal and modeless dialogs)

LOCAL lResult AS LONG

...

DIALOG SHOW MODAL hDlg TO lResult

During the time that the "main" part of our code is blocked by the modal dialog, DDT may call the code in the Callback Functions in response to user interaction, etc. If no events occur, our code is not executed at all, and therefore uses no CPU time. In this example, the dialog only closes when the user eventually clicks the OK or the Cancel button (or presses the ENTER or ESCAPE keys).

Once the dialog is closed, the lResult variable will contain the value set using the DIALOG END statement, and execution of the statements following the DIALOG SHOW statement will resume. In our example, we use a return value of one (1) to indicate that the user clicked the OK button, and a return value of 0 to indicate the user clicked the Cancel button.

The complete example code can be found in the HELLODDT.BAS file in the \PB\SAMPLES\DDT\HELLODDT folder:

#COMPILE EXE

#INCLUDE "DDT.INC"

%IDOK = 1

%IDCANCEL = 2

%IDTEXT = 100

%BS_DEFAULT = 1

' Global variable to receive the user name

GLOBAL gsUserName AS STRING

CALLBACK FUNCTION OkButton()

IF CB.MSG = %WM_COMMAND AND CB.CTLMSG = %BN_CLICKED THEN

CONTROL GET TEXT CB.HNDL, %IDTEXT TO gsUserName

DIALOG END CB.HNDL, 1

FUNCTION = 1

END IF

END FUNCTION

CALLBACK FUNCTION CancelButton()

IF CB.MSG = %WM_COMMAND AND CB.CTLMSG = %BN_CLICKED THEN

DIALOG END CB.HNDL, 0

FUNCTION = 1

END IF

END FUNCTION

FUNCTION PBMAIN() AS LONG

LOCAL hDlg AS DWORD

LOCAL lResult AS LONG

' ** Create a new dialog template

DIALOG NEW 0, "What is your name?", ,, 160, 50, 0, 0 TO hDlg

' ** Add controls to it

CONTROL ADD TEXTBOX, hDlg, %IDTEXT, "", 14, 12, 134, 12

CONTROL ADD BUTTON, hDlg, %IDOK, "OK", 34, 32, 40, 14, %BS_DEFAULT OR %WS_TABSTOP CALL OkButton

CONTROL ADD BUTTON, hDlg, %IDCANCEL, "Cancel", 84, 32, 40, 14 CALL CancelButton

' ** Display the dialog

DIALOG SHOW MODAL hDlg TO lResult

' ** Check the dialog return result

IF lResult THEN

MSGBOX "Hello " & gsUserName, &H00002000& ' = %MB_TASKMODAL

END IF

END FUNCTION

See Also

Dynamic Dialog Tools (DDT)

Creating a Dialog

Modal vs. Modeless

Controls

Control Styles

Callbacks

Dialog Styles

Menus