Dialogs

How to create dialog

Working with the Dialog Editor

How to show dialog

Dialog types

How to get data from controls

How to initialize controls

Variable names

Using an user-defined type

Smart dialogs

Multi-page dialogs

Encrypted macros

Dialogs now and before QM 2.1.9

Unicode

Fonts and colors

Menus and accelerators (hot keys)

Common controls, other controls

ActiveX controls

Dialog examples and tutorials

How to create dialog

To create new dialog, you can use the Custom Dialog dialog from the floating toolbar or File -> New menu. This creates initial dialog definition (text that begins with BEGIN DIALOG and ends with END DIALOG) and opens it in the Dialog Editor. Add controls, order them, change text, etc, and click Apply. It updates the dialog definition. To edit the dialog later, open the macro that contains the dialog definition, and run the Dialog_Editor function. If first line of macro text is

 

 /Dialog_Editor

 

, the Dialog Editor runs when you press the Run button. If it finds a dialog definition in the text, it loads the definition.

 

You can also edit a dialog definition directly. The first line defines dialog window, other lines - controls. Line format: id class style exstyle x y width height text

Working with the Dialog Editor

Select control: click it. Small red rectangle will appear at the top-left corner.

Move control:  drag with the mouse left button. To move multiple controls, Shift+drag a "Group" control that surrounds them.

Resize control:  drag with the mouse right button.

Resize dialog:  resize the dialog editor window.

Send control to the top of the Z order and tab order:  Shift+click.

Send control to the bottom of the Z order:  Ctrl+click.

Place control behind the currently selected control in the Z order: Ctrl+Shift+click.

Z-order all controls: select dialog, then Ctrl+Shift+click all controls starting from the control that must be at the top of the Z order. Alternatively, close the Dialog Editor and reorder lines in the dialog definition. The order of controls in the dialog definition is the same as the Z order in the dialog.

Underline character in contro's text: place ampersand (&) before.

Create group of option buttons: add "Option first" and then several "Option next".

 

In the Dialog Editor, you can set text for some controls. For other controls, text is used only as control's name, making it easier for you to recognize the control in the Dialog Editor. The first three characters also are used for variable name. Generally, controls are identified by an unique control id - numeric value that you can see in variable name. For example, if variable name is b3But, you know that control id is 3.

How to show dialog

To show dialog, is used ShowDialog function. When you save (Apply) dialog in the Dialog Editor, the code to show the dialog is displayed in the QM output. The code contains ShowDialog function, and (optionally) declarations of variables that represent controls and can be used to initialize them and get data from them (read below). Copy the code and paste in a macro or function, where you need to show the dialog. You can paste it in any macro(s) or function(s), not necessary in the macro where the dialog definition is. To insert/update the code automatically, enter macro name(s) in Dialog Editor Options.

 

As said above, the minimum code to show the dialog is created by the Dialog Editor. If you need more control, you can use more arguments with ShowDialog. Arguments:

 

macro - the name of the item (macro or function) that contains the dialog definition. Can be "" or omitted if in the same function. Other arguments are optional, and can be omitted or 0. See also: flag 2.

dlgproc - the address of a custom dialog procedure. Used only for smart dialogs (read below).

controls - array of strings (address of first str variable in the array) for controls, as explained later in this topic.

hwndowner - owner window handle. If the dialog is child window (flags includes 1, and style includes WS_CHILD), hwndowner must be parent window handle.

flags - combination of the following values: 1 - nonmodal dialog (read below), 2 - macro is string (not macro) containing dialog definition, 4 - style replaces dialog style (default - adds), 64 - raw x y.

style - combination of window styles (WS_ and/or DS_ constants). Use only if you want to modify or replace default style that is set by the Dialog Editor.

notstyle - combination of styles to remove from default style.

param - some value to pass to the dialog procedure. The dialog procedure can retrieve it using DT_GetParam function.

x, y - dialog coordinates. Read more below.

icon - title bar icon. Can be icon file, or icon resource id (in exe) preceded by : (eg ":150" or ":151 file.ico"). Default: "".
menu - menu. Can be name of item that contains menu definition (read below), or menu definition itself, or menu resource id (in exe) preceded by : (eg ":1"). Default: "". Menu definition can contain accelerators (hot keys). If using resource, uses accelerator table that have the same id as the menu (if exists).

 

Actual dialog coordinates depend on x, y, hwndowner, some styles, flag 64, and _monitor. If x and y are omitted or 0, by default dialogs are shown in screen center.

If WS_CHILD style used, uses raw x and y in parent's client area.

Else if flag 64 used, uses raw x and y relative to the primary monitor. If DS_CENTER style used (it is default), ensures that the dialog is completely in the work area.

Else if DS_CENTERMOUSE style used, the dialog is placed by the mouse pointer. Nonzero x y can be used to add offset.

Else if DS_CENTER style used (it is default), negative x and/or y values are interpreted as offset from the right and/or bottom edge of the work area, 0 values - screen center. Positive coordinates are interpreted as coordinates in the work area of the monitor. The monitor depends on the _monitor variable.

Else if hwndowner used and DS_ABSALIGN style not used, uses raw x and y, relative to the owner's client area.

Else uses raw x and y relative to the work area of the monitor. The monitor depends on the _monitor variable.

 

Tip: If your dialog shows message boxes or other unowned dialogs, it should do it in the same monitor. Under case WM_INITDIALOG insert _monitor=hDlg. Without this, these unowned dialogs will be in the primary monitor regardless where your dialog is.

Dialog types

Dialog can be modal (ShowDialog returns only when dialog is closed) or modeless (ShowDialog creates dialog and returns immediately). Usually are used modal dialogs. It is default.

 

ShowDialog for modal dialog returns 1 on OK, 0 on Cancel. When you click some other push-button in dialog that does not have custom dialog procedure (that is, is not a "smart" dialog), it closes the dialog, and ShowDialog returns button id.

 

To create modeless dialog, use flag 1. You cannot simply get data from modeless dialog. To make modeless dialog useful, you must use dialog procedure for it. ShowDialog for modeless dialog returns dialog window handle.

 

Sometimes dialogs are used as child windows. To create child dialog, when calling ShowDialog specify parent window handle, flag 1 (modeless) and WS_CHILD style.

 

If an error occurs and the dialog cannot be shown, is generated run-time error.

How to get data from controls

Before calling ShowDialog, declare str variables for each control with which you want to communicate. Variables must be declared in particular order, described below. As mentioned above, the Dialog Editor automatically creates the dialog calling code that also may contain variables for controls. Example:

 

str controls = "3 5"
str e3Nam c5Var
if(!ShowDialog("Dialog2" 0 &controls)) ret

if(c5Var=1) ;;checked
	out e3Nam

 

The first str variable contains identifiers of desired controls, separated with spaces. Then follow str variables for each control whose id is included in the first variable (in the same order). Variable names include control id. The third argument of ShowDialog must be the address of the first variable.

 

When ShowDialog returns (on OK), variables contain data from corresponding controls. The format is:

 

1. Check and Option buttons: "1" if checked, "0" if not checked.

2. ListBox (except multiplesel) and ComboBox: "index string". Here index is zero-based index of selected item; string is text of selected item. If not selected any item, index is -1. You can use the TO_CBGetItem function to extract the text and index.

3. ListBox multiplesel: string consisting of '0' and '1' characters. For example, if selected are items 0 and 3 in 4-item listbox, the string will be "1001".

4. Edit and rich edit controls: control's text. Gets text only if not read-only.

5. Other controls: unchanged.

How to initialize controls

In the Dialog Editor, you can set text for buttons, group, static text and read-only edit controls. If you want to initialize some other controls, before showing dialog set the corresponding strings as follows:

 

1. Check and Option buttons: if string is "1", button will be checked.

2. ListBox and ComboBox: string should contain list of item strings separated by newline characters ([]). Item(s) preceded with ampersand (&) will be selected.

3. Static icon: icon file. If first character is ampersand (&), uses large icon.

4. Static bitmap: picture file (bmp, jpg or gif).

5. Dialog itself (id=0): title bar text.

6. Edit: text.

7. Rich edit: text. If string begins with &, loads file instead. Example: "&$desktop$\document.rtf".

8. ActiveX SHDocVw.WebBrowser: URL, folder or file that can be opened in web browser. To open empty page, use "".

9. Other controls: control's text. Variables for these controls are not declared automatically. For static text, frame, push-buttons and read-only edit, it would change text that is set in the Dialog Editor. For other controls (ActiveX, common controls, etc) it would not have any effect.

 

Example:

 

str controls = "3 5 6 7 4"
str c3 cb5 e6 si7 sb4
c3 = 1 ;;checkbox checked
cb5 = "Sunday[]&Monday[]Tuesday" ;;combobox with three items; Monday is selected
e6 = "Default text" ;;edit control's text is "Defaut text"
si7 = "&files.ico" ;;large icon from files.ico file
sb4 = "c:\pictures\tree.bmp" ;;picture
if(!ShowDialog("Dialog2" 0 &controls)) ret

 

Static icons and bitmaps can contain exe resource id. Examples ":150", ":151 file.ico", ":10 file.bmp".

Variable names

The Dialog Editor automatically creates names for variables that represent controls. A variable name is composed from abbreviated class name, id and max 3 characters of control's name. For example, if combo box with id 15 is named "Value", variable name is cb15Val.

 

If you change variable names (change variable's text in the Dialog Editor), or edit an old dialog (prior to QM version 2.1.3, variable names were constructed from full class name and id), you must update variable names in the macro. To do this easily, in Dialog Editor Options, enter macro name (or *, if in the same function). Then variable names always will be updated automatically whenever you apply changes in the Dialog Editor. Alternatively, you can use this macro.

Using an user-defined type

Instead of array of str variables, you can use an user-defined type. You can enter type name in Dialog Editor Options. Example:

 

type TYPE_A ~controls ~c3Che ~e4 ~cb5
TYPE_A d.controls="3 4 5"

d.cb5="Sunday[]&Monday[]Tuesday"

if(!ShowDialog("Dialog4" 0 +&d)) ret

TO_CBGetItem d.cb5
out d.cb5

 

Examples of getting control values in a dialog procedure:

 

 modal dialog (don't use this for modeless dialogs)
TYPE_A& d=+DT_GetControls(hDlg)
out d.e4

 modal or modeless dialog
TYPE_A d.controls="3 4 5"
DT_GetControls(hDlg &d)
out d.e4

 

Example of using the registry to save dialog data:

 

type DLGVAR ~controls ~e3 ~c4Che
DLGVAR d.controls="3 4"

if(rget(_s "DLGVAR" "\test")) _s.setstruct(d)

if(!ShowDialog("Dialog33" 0 &d)) ret

_s.getstruct(d); rset(_s "DLGVAR" "\test")

Smart dialogs

When you use a simple dialog, you can only initialize controls before calling ShowDialog, and get data from them when ShowDialog returns. While the dialog is open, the macro waits until it is closed. That is enough in many cases. But sometimes you need to execute some code while dialog is open. For example, show a Open File dialog when the user clicks a button. Then you need custom dialog procedure.

 

A dialog procedure is an user-defined function with four arguments: hDlg (dialog window handle), message (integer value; messages are defined in the WinMessages function), and two other integer arguments that depend on message - wParam and lParam. The dialog procedure is called by the system whenever the dialog receives a message (e.g., when the user clicks a button or selects a listbox item).

 

For messages that the dialog procedure processes itself, it should return 1. For other messages it must return 0. In some rare cases when the dialog procedure has to return some value for other purposes, use ret DT_Ret(hDlg value).

 

When you choose to create smart dialog (in the Custom Dialog dialog), QM creates initial dialog procedure, where QM also places initial dialog definition. This function allows to execute code whenever some event (dialog created, button clicked, etc) occurs in the dialog or some control. On event, Windows sends message to the dialog. That is, calls this function. The sel-case statements decide what message is sent, and from which control. The first sel handles dialog-related messages. The second sel handles control-related messages (for standard controls). When a message arrives, is executed code that follows the case statement for that message. To add case statements for various messages, you can use the Events button in the Dialog Editor. Then write code for that message.

 

Some often used messages.

 

Since all dialogs from the floating toolbar are implemented as user-defined functions (most of them are smart dialogs), you have lots of samples to see how various features are implemented. The functions are in the System/Tools folder. They use several helper functions, such as TO_S, TO_N, but you should not use them (unless you will make copies), because they may change in the future. However, you can use functions from the System/Dialogs/Dialog Functions folder.

 

The dialog calling code (ShowDialog) for a smart dialog should be in other macro or function. Alternatively, it can be in the same function, but then it cannot receive arguments. If the dialog calling code is in the same function, the code is executed when hDlg is 0. If hDlg is nonzero (the function is called by Windows to process a message), the dialog calling code is skipped.

 

API function EndDialog should not be used in QM. Instead can be used DT_Ok or DT_Cancel, although it is not needed on IDOK/IDCANCEL.

Multi-page dialogs

QM dialogs don't have support for real property pages, but you can easily show and hide groups (pages) of related controls so that only one page would be visible at a time. In the Dialog Editor, use buttons < and > to switch pages and create new pages. Controls with id 1 to 999 are always visible (common). Controls with id greater or equal 1000 belong to pages that can be easily shown and hidden. Each page can have maximum 100 controls. For example, controls in page 0 have id 1000 to 1099, controls in page 1 have id 1100 to 1199, and so on.

 

To switch pages at run time, in the dialog procedure call the DT_Page function. The first argument hDlg is dialog window handle (hDlg). The second argument index is zero-based page index. It can be -1 to hide all pages. The third optional argument map can be used to map index to different page. It is string consisting of page indexes separated by spaces. For example, map "0 0 1 2 2" forces to show page 0 when index is 0 or 1, page 1 when index is 2, and page 2 when index is 3 or 4. Parentheses may be used to show several pages simultaneously. For example, map "0 (1 3) 2" forces to show pages 1 and 3 when index is 1.

Encrypted macros

If you encrypt a macro that contains a dialog definition, the dialog will not work, because dialog functions cannot decrypt it to take the dialog definition. You can either place the dialog definition in a nonencrypted macro, or store the dialog definition in a variable and use flag 2 with ShowDialog. Example:

 

\Dialog_Editor

str dd=
 BEGIN DIALOG
 0 "" 0x10C80A44 0x100 0 0 109 50 "Form"
 3 Edit 0x54030080 0x200 6 8 96 14 ""
 1 Button 0x54030001 0x4 4 32 48 14 "OK"
 2 Button 0x54030000 0x4 56 32 48 14 "Cancel"
 END DIALOG
 DIALOG EDITOR: "" 0x2010507 "*" ""

str controls = "3"
str e3
if(!ShowDialog(dd 0 &controls 0 2)) ret
out e3

Dialogs now and before QM 2.1.9

In QM versions < 2.1.9, the dialog procedure must call DT_Init on WM_INITDIALOG, DT_DeleteData on WM_DESTROY, DT_Ok on OK, and DT_Cancel on Cancel. Starting from QM 2.1.9, these functions are not necessary. Now you have to use them only if the dialog will be used by someone that has an older QM version (this does not apply to exe-macros). Also, to avoid any problems, you should leave these functions in dialogs where they already exist.

 

A note about IDOK and IDCANCEL. Before QM 2.1.9, DT_Ok and DT_Cancel functions were used to close the dialog. If they were not called, the dialog was not closed. Now dialogs are closed automatically. To prevent this, return 0 on IDOK or IDCANCEL. For backward compatibility, a dialog also is not closed automatically if it calls DT_Init on WM_INITDIALOG (it is the way QM recognizes old dialogs).

Unicode

QM 2.3.0 and later versions support Unicode. To enable it for whole program, check the checkbox in Options. To enable it for a dialog, select Unicode or As QM in dialog editor Options. By default, dialogs work in ANSI mode, like in previous QM versions.

 

When Unicode is enabled for a dialog, Unicode characters are correctly displayed in dialog title and in all controls (QM also should run in Unicode mode). However, if it is a smart dialog, you may have to modify its dialog function, because it then receives Unicode versions of some messages, particularly those that can pass or query text. Then the text is in Unicode UTF-16 format. QM string functions don't understand UTF-16. You can use str.ansi to convert the text to UTF-8 or ANSI. The _unicode variable can tell you in which mode QM is running.

 

For example, in a dialog function of a Unicode dialog, lParam of WM_SETTEXT is UTF-16 text. If the dialog is ANSI, it is ANSI text. Common controls (tree view, list view, etc) have their own Unicode mode, which is enabled in Unicode dialogs, and disabled in ANSI dialogs. In Unicode mode they send different messages (codes used with WM_NOTIFY message). For example, in Unicode mode a tree view control sends TVN_SELCHANGEDW instead of TVN_SELCHANGED. Control Unicode mode can be turned on/off using CCM_SETUNICODEFORMAT message, documented in the MSDN library.

Fonts and colors

QM 2.2.1. Use class __Font. Example.

Menus and accelerators (hot keys)

ShowDialog accepts an optional menu argument. It can be the name of a macro (or item of other type) that contains menu definition. It also can be menu definition itself. Example menu definition:

 

BEGIN MENU
>&File
	&Open : 101 0 0 Co
	-
	>&Recent
		Empty : 102 0 3
		<
	<
>&Edit
	Cu&t : 103 0 0 Cx
	-
	Select &All : 104 0 0 Ca
	<
&Help : 105 0
END MENU

 

You can see that it is similar to QM menus. A single line (except <), creates a menu item. Items that open popup menus or submenus begin with >. They usually don't have an id and accelerator. The end of a popup menu or submenu is marked by < line. Hyphen is used for separators. A line can optionally begin with any number of spaces and tabs.

 

Syntax used for menu items:

 

Label : id [type] [state] [accelerator]

 

label - menu item text. Use ampersand to underline characters. Can be used escape sequences.

id - menu item id. A positive number smaller than 32768 (32K). When you click the menu item, the dialog procedure receives WM_COMMAND message that can be handled in the same way as it would be a button with the id. You should use bigger numbers (e.g. above 10000) to avoid conflicts with buttons.

type - numeric combination of menu item types. Normally it is omitted or 0.

state - numeric combination of menu item states. Normally it is omitted or 0. Some states: 3 disabled, 8 checked, 0x1000 default (bold).

accelerator - a hot key in QM format (same as with the key command). The effect of pressing the hot key is the same as clicking the menu item. The key string is appended to the menu item label automatically.

 

id, type and state must be single numbers, without operators and named constants. More info about menu item types and states can be found in the MSDN Library (search for MENUITEMINFO structure).

 

In exe also can be used menus from resources. The menu argument of ShowDialog must be semicolon followed by resource id, e.g. ":15". If the resource contains accelerator table with the same id, the table is used for accelerators, although accelerator text is not added (must be included in label text, after tab).

 

To change or remove menu at run time, call DT_SetMenu from dialog procedure. To create or load menu, use DT_CreateMenu.

 

Menus and accelerators can be used with modal and modeless dialogs, but not with child dialogs.

Common controls, other controls

The Dialog Editor and dialog functions support controls of the following classes: Button (buttons, checkboxes, frames), Edit, RichEdit20A, Static (static text, bitmap, icon, line), ComboBox and LixtBox. Working with controls of these classes is easy. You can initialize them before you call ShowDialog, and get data (text, checked, etc) from them when dialog is closed.

 

Dialogs can contain controls of other classes too. For example, TreeView32, SysTabControl32. However, only programmers can use them. To interact with these controls, use SendMessage in dialog procedure (it means, you can use them in smart dialogs only). Messages, styles and other information can be found in the MSDN library. If you don't know the value of a constant, click it, press F1, and search for definition on the Internet.

 

Several samples can be found in the System folder, Samples2 file, and in the QM forum. Search for class name.

ActiveX controls

Controls that you usually use in dialogs are Windows controls. Also you can use ActiveX controls. ActiveX controls are COM objects that provide graphical user interface. They are used differently than Windows controls. To work with Windows controls, are used messages. To work with ActiveX controls, are used functions that they provide.

 

To insert an ActiveX control, click "ActiveX controls..." in the Dialog Editor. It opens the Type Libraries dialog that displays available (registered) ActiveX controls. Select the control you need and click Add Control To Dialog.

 

ActiveX controls are defined in type libraries, as COM classes. To use an ActiveX control in a dialog, at first declare the type library where the control class is defined. To insert type library declarations, use the Type Libraries dialog. When adding a control to a dialog, QM prompts to insert type library declaration if it still does not exist in current macro. Several type libraries, including SHDocVw (web browser control) are already declared.

 

You can read more about type libraries and ActiveX controls in the Using COM Components topic.

 

When you have an ActiveX control created, you usually need some way to communicate with it. For this purpose, declare a variable of that class and call _getcontrol. Pass handle of ActiveX control's host window (which itself is a Windows control of "ActiveX" class). Then you can call functions with the variable to manipulate the control. To receive events, use _setevents. Don't use thread variables, but rather use _getcontrol everywhere. Or, under WM_DESTROY, assign 0 to the thread variable.

 

Example:

 

...
sel message
	case WM_INITDIALOG ;;Dialog just created
	SHDocVw.WebBrowser b
	b._getcontrol(id(3 hDlg))
	b._setevents("b_DWebBrowserEvents2")
	b.Navigate("http://www.google.com")
...
	case 4 ;;Back button
	b._getcontrol(id(3 hDlg))
	b.GoBack
...

 

There is a sample dialog with web browser control in the Samples2 file.

 

You cannot set text (using setwintext or some other function) of ActiveX controls. The only exception is the web browser control (SHDocVw.WebBrowser). If the text is URL or path of a html, image or other file, it opens that web page or file. Does not wait until finished loading. Sets silent mode to avoid script error messages. If the text begins with "<", loads it as HTML (QM 2.3.0. In previous versions it didn't work well.). If the text is "", loads "about:blank" or clears the control.

 

ActiveX controls can be used in other windows (non-dialog) too. To create an ActiveX control, use CreateControl or CreateWindowEx. As class name, specify "ActiveX". As text, specify ActiveX control's class, e.g. "SHDocVw.WebBrowser".

 

QM 2.2.0. Instead of or after Typelib.Class, can be used CLSID string. Examples: "{22D6F312-B0F6-11D0-94AB-0080C74C7E95}", "MediaPlayer.MediaPlayer {22D6F312-B0F6-11D0-94AB-0080C74C7E95}". If CLSID is included, the code still works with previous versions, except in exe. To make the code completely compatible with previous versions, don't use CLSID, or use #exe addactivex.

 

QM 2.2.0. QM supports run-time licensing of ActiveX controls. It allows you to add purchased ActiveX controls to macros and exes and distribute these macros and exes. When you insert an ActiveX control in the Dialog Editor using the Type Libraries dialog, QM automatically attaches encrypted run-time license key, if the control can generate it. With attached run-time license key, the control can be used on any computer. If you distribute macro (not exe), you should encrypt the macro that contains the dialog definition to prevent others to reuse the run-time license key in their macros. See Encrypted Macros. Even if the macro is not encrypted, the key can only be used in Quick Macros, because only QM can decrypt the key. Also, others will not be able to create exes with the key. Note that some controls may use different ways to verify license. For example, you may have to call certain function on the object and pass the license key. Make sure that the code is encrypted.

 

Some ActiveX controls don't work well in QM. This is because they are designed for full-featured containers, such as Visual Basic forms, or only for certain programs. At design time, you can only move and resize ActiveX controls (or control placeholders). Properties can be changed only at run time.

 

Many other COM components are not controls, and must be created with _create or other functions instead. Such components usually are in dll files. Controls usually are in ocx or dll files.

 

See also: Using COM components.

Dialog examples and tutorials

Search for ShowDialog or dialog in the forum.

 

Several topics to get started:

 

Tips how to copy/paste QM code in the forum, and how to use dialog examples.

 

A tutorial for a simplest dialog with checkboxes.

 

Running and ending macros from a dialog (without closing the dialog).

 

Executing code from a dialog with a combo box (without closing the dialog). An example with a list box.