Foundation of Control Programming

There are predefined controls in a relatively complex GUI system, and they are the main elements for the human-machine interaction. This chapter will illustrate what is the control and control class, and briefly introduce the predefined control classes in MiniGUI.

Control and Control Class

The concept of controls (or widgets) is well known. The control can be interpreted as the child window in the main window. The behaviors of these child windows, as well as that of the main window, both can accept the exterior input such as the keyboard and the mouse, and can output in their own regions - but all the actions are restricted within the main window. MiniGUI also supports child windows, and can create nested child windows in the child window. We refer to all the child windows in MiniGUI as controls.

In Window or X Window, the system will predefine some control classes. When you use a certain control class to create controls, all the controls belonging to this control class will have the same behaviors and appearances. With this technique, the consistent human-machine interaction interface can be ensured, and the program can construct the graphics user interface as building toy bricks. MiniGUI uses the concept of control and control class, and can conveniently overload the existed control to make it have some special effects. For example, when an edit box which only allows digit to input in, you can realize it by overloading the existed EDIT control class, instead of developing a new control class.

If you have the experience of developing a Windows application, you should remember that before creating a new window, you must assure that the corresponding window class of this new window has existed in the system. In Windows operating system, each window created by the program corresponds to a certain window class. This concept is similar to the relationship between the class and the object in the object-oriented programming. Referring to the terms of object oriented, each window in Windows is an instance of a certain window class. Similar concepts are present in the X Window programming; for example, each widget created is actually an instance of a certain widget class.

Thus, if a program needs to create a window, it should first be sure to select the correct window class, because each window class determines the appearances and behaviors of the corresponding window instances. Herein the presentation means the appearance of the window, such as the width of the window border, whether or not the caption bar exists, etc. The behavior means the response of the window to the user input. Each GUI system will predefine some window classes. Examples of the common window classes include the button, list box, scroll bar, edit box, etc. If the window to be created by the program is very special, you can first register your own window class, and then create an instance of this window class. Thus the code reusability is improved substantially.

In MiniGUI, the main window is generally considered as a special window. Since the reusability of the main window code is usually very low, it will cause additional unnecessary memory space if we register a window class for each main window in a usual way. So we do not provide window class support in the main window, but all the child windows, i.e. controls, in the main window support the concept of the window class (control class). MiniGUI provides the predefined control classes commonly used, including button (including radio button, check box), static control, list box, progress bar, track bar, edit box, etc. A program can customize its own control class, register the control class and then create the corresponding control instances. Table 1 lists the predefined control classes and the corresponding class names in MiniGUI.

Table 1 Control class and corresponding class name predefined in MiniGUI

Control Class

Class Name

C Macro for Control Name

Note

Static Text

"static"

CTRL_STATIC

refer to Chapter 19

Button

"button"

CTRL_BUTTON

refer to Chapter 20

List Box

"listbox"

CTRL_LISTBOX

refer to Chapter 21

Single-Line Edit Box

"sledit"

CTRL_SLEDIT

refer to Chapter 22

Multi-Line Edit Box

"mledit"

CTRL_MLEDIT

(same with TRL_TEXTEDIT)

Text Edit Box

“textedit”

CTRL_TEXTEDIT

refer to Chapter 22

Combo Box

“combobox”

CTRL_COMBOBOX

refer to Chapter 23

Menu Button

"menubutton"

CTRL_MENUBUTTON

refer to Chapter 24

Progress Bar

"progressbar"

CTRL_PRORESSBAR

refer to Chapter 25

Trackbar

"trackbar"

CTRL_TRACKBAR

refer to Chapter 26

New Toolbar

"newtoolbar"

CTRL_NEWTOOLBAR

refer to Chapter 27

Property Sheet

"propsheet"

CTRL_PROPSHEET

refer to Chapter 28

Scrollable Window

"scrollwnd"

CTRL_SCROLLWND

refer to Chapter 29

Scrollable View

"scrollview"

CTRL_SCROLLVIEW

refer to Chapter 30

Tree View

"treeview"

CTRL_TREEVIEW

refer to Chapter 31

List View

"listview"

CTRL_LISTVIEW

refer to Chapter 32

Month Calendar

"monthcalendar"

CTRL_MONTHCALENDAR

refer to Chapter 33

SpinBox

"spinbox"

CTRL_SPINBOX

refer to Chapter 34

Cool Bar

"coolbar"

CTRL_COOLBAR

refer to Chapter 35

Animation

"animation"

CTRL_ANIMATION

refer to Chapter 36

Grid View

“gridview”

CTRL_GRIDVIEW

refer to Chapter 37

Icon View

“iconview”

CTRL_ICONVIEW

refer to Chapter 38

Scrollbar

"scrollbar"

CTRL_SCROLLBAR

refer to Chapter 39

Creating Control Instance by Using Predefined Control Class

In MiniGUI, by calling the CreateWindow function (the CreateWindow is in fact a macro of the CreateWindowEx function) can create an instance of a certain control class. The control class can be either the predefined MiniGUI control classes in Table 1, or a user-defined control class. Following are the prototypes of several functions related to CreateWindow function (minigui/window.h):

HWND GUIAPI CreateWindowEx2 (const char* spClassName,
        const char* spCaption, DWORD dwStyle, DWORD dwExStyle,
        int id, int x, int y, int w, int h, HWND hParentWnd,
        const char* werdr_name, const WINDOW_ELEMENT_ATTR* we_attrs,
        DWORD dwAddData);

static inline HWND GUIAPI CreateWindowEx (const char* spClassName,
        const char* spCaption, DWORD dwStyle, DWORD dwExStyle,
        int id, int x, int y, int w, int h, HWND hParentWnd,
        DWORD dwAddData)
{
    return CreateWindowEx2 (spClassName, spCaption, dwStyle, dwExStyle,
                id, x, y, w, h, hParentWnd, NULL, NULL, dwAddData);
}

#define CreateWindow(class_name, caption, style, id, x, y, w, h, parent, add_data) \
        CreateWindowEx(class_name, caption, style, 0, id, x, y, w, h, parent, add_data)

BOOL GUIAPI DestroyWindow (HWND hWnd);

The CreateWindow function creates a child window, i.e. a control. It specifies the control class (class_name), the control caption (caption), the control style (style), the control identifier (id), and the initial position and size of the control (x, y, w, h). This function also specifies the parent window (parent) of the child window. The parameter add_data is used to pass a special data to the control, and the data structures pointed to by this pointer are different for different control classes.

The affection of the CreateWindowEx function is same as CreateWindow function; however, the CreateWindowEx can be used to specify the extended style (dwExStyle) of the control.

CreateWindowEx2 function is a new added function in MiniGUI 3.0. It is based on CreateWindowEx and has two new arguments: werdr_name and we_attrs, they specify the name and the property of renderer for control.

The DestroyWindow function is used to destroy the control or the child window created by above two functions.

The program in List 1 creates several types of controls by using the predefined control classes: static control, button and single-line edit box. Among them hStaticWnd1 is the static control created in the main window hWnd; hButton1, hButton2, hEdit1, and hStaticWnd2 are several controls created in hStaicWnd1, and existing as the child controls of hStaticWnd1; While hEdit2 is the child control of hStaicWnd2, and is the grandchild control of hStaticWnd1.

List 1 Creating controls using the predefined control classes

#define IDC_STATIC1     100
#define IDC_STATIC2     150
#define IDC_BUTTON1     110
#define IDC_BUTTON2     120
#define IDC_EDIT1       130
#define IDC_EDIT2       140

      /* Create a static control */
      hStaticWnd1 = CreateWindow (CTRL_STATIC, 
                    "This is a static control", 
                    WS_CHILD | SS_NOTIFY | SS_SIMPLE | WS_VISIBLE | WS_BORDER,
                    IDC_STATIC1, 
                    10, 10, 180, 300, hWnd, 0);

      /* Create two button controls in hStaticWnd1 */
      hButton1  = CreateWindow (CTRL_BUTTON,
                    "Button1", 
                    WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 
                    IDC_BUTTON1, 
                    20, 20, 80, 20, hStaticWnd1, 0);
      hButton2  = CreateWindow (CTRL_BUTTON,
                    "Button2", 
                    WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 
                    IDC_BUTTON2, 
                    20, 50, 80, 20, hStaticWnd1, 0);

      /* Create one edit control in hStaticWnd1 */
      hEdit1   = CreateWindow (CTRL_EDIT,
                    "Edit Box 1", 
                    WS_CHILD | WS_VISIBLE | WS_BORDER, 
                    IDC_EDIT1, 
                    20, 80, 100, 24, hStaticWnd1, 0);

      /* Create a static control in hStaticWnd1 */
      hStaticWnd2 = CreateWindow (CTRL_STATIC, 
                    "This is child static control", 
                    WS_CHILD | SS_NOTIFY | SS_SIMPLE | WS_VISIBLE | WS_BORDER,
                    IDC_STATIC1, 
                    20, 110, 100, 50, hStaticWnd1, 0);

      /* Create an edit box hEdit2 in hStaticWnd2, 
       * thus hEdit2 is the grandchild window of hStaticWnd1 */
      hEdit2   = CreateWindow (CTRL_EDIT,
                    "Edit Box 2", 
                    WS_CHILD | WS_VISIBLE | WS_BORDER, 
                    IDC_EDIT2, 
                    0, 20, 100, 24, hStaticWnd2, 0);

Topics Involved in Control Programming

In control programming, besides creating and destroying of the control, following subjects are usually involved:

  • The control has its own window style definition. You need to specify the needed style when creating the control. Different styles will result in different appearance and behavior.

  • Getting or setting the status and contents and so on of the control. In general, sending some general or special messages to the control can complete this. In addition, the general functions for windows are usually suitable for the controls, such as ShowWindow, MoveWindow, EnableWindow, SetWindowFont, etc.

  • Informing the parent window by notification messages when a certain event happens in the control. Notification messages are generally sent by MSG_COMMAND messages. WParam parameter of this message consists of the window identifier and the notification code, and lParam includes the handle of the control sending the notification messages. For example, when users change the contents of an edit box, the edit box will send EN_CHANGE notification message to the parent window. If the window procedure of the parent window needs to know this change, the notification message should be handled in the window procedure of the parent window as follows:

switch (message) {
        case MSG_COMMAND:
        {
            int id = LOWORD(wParam);
            int nc = HIWORD(wParam);
            if (id == ID_MYEDIT && nc == EN_CHANGE) {
                /* The user has changed the content of ID_MYEDIT edit box 
                * of the child window, and further handling is being done now. */
            }
        }
        break;
    }
  • MiniGUI V1.2.6 introduces SetNotificationCallback function for the notification message handling of control. This function can set a callback function of the notification message for a control. When the control has a notification message, it will call the callback function, instead of sending the notification message to the parent window. New applications should use this function as far as possible to handle notification messages of a control to get a good program structure. All the sample programs for this guide use this interface to handle notification messages of a control.

The function in List 2 creates a simple dialog box by using the predefined control classes. When the user inputs data in unit of millimeter (mm) into the edit box, the system will display the corresponding data in unit of inch in the static control below the edit box, and return the data input by the user to the function calling the dialog box when the user select “OK” button.

List 2 Realizing a simple input dialog box using the predefined controls

#include <stdio.h>
#include <stdlib.h>

#include <minigui/common.h>
#include <minigui/minigui.h>
#include <minigui/gdi.h>
#include <minigui/window.h>
#include <minigui/control.h>

/* Define dialog box template */
static DLGTEMPLATE DlgBoxInputLen =
{
    WS_BORDER | WS_CAPTION, 
    WS_EX_NONE,
    120, 150, 400, 160, 
    "请输入长度",
    0, 0,
    4, NULL,
    0
};

#define IDC_SIZE_MM     100
#define IDC_SIZE_INCH   110

/* 
 * The dialog includes four controls in total, which are used to 
 * display prompt information, input value, display the 
 * transformed length value, and show a “OK” button to close the program
 */
static CTRLDATA CtrlInputLen [] =
{ 
    {
        CTRL_STATIC,
        WS_VISIBLE | SS_SIMPLE,
        10, 10, 380, 18, 
        IDC_STATIC, 
        "请输入长度(单位:毫米)",
        0
    },
    {
        CTRL_EDIT,
        WS_VISIBLE | WS_TABSTOP | WS_BORDER,
        10, 40, 380, 24,
        IDC_SIZE_MM,
        NULL,
        0
    },
    {
        CTRL_STATIC,
        WS_VISIBLE | SS_SIMPLE,
        10, 70, 380, 18, 
        IDC_SIZE_INCH, 
        "相当于 0.00 英寸",
        0
    },
    {
        CTRL_BUTTON,
        WS_TABSTOP | WS_VISIBLE | BS_DEFPUSHBUTTON, 
        170, 100, 60, 25,
        IDOK, 
        "确定",
        0
    }
};

/* This is the notification callback funciton of the input box. */
static void my_notif_proc (HWND hwnd, int id, int nc, DWORD add_data)
{
    /* When the value in the input box is changed, 
     * get the value, transform it into inch,and display it in the inch box
     */
    if (id == IDC_SIZE_MM && nc == EN_CHANGE) {
        char buff [60];
        double len;

        GetWindowText (hwnd, buff, 32);
        len = atof (buff);
        len = len / 25.4;

        sprintf (buff, "相当于 %.5f 英寸", len);
        SetDlgItemText (GetParent (hwnd), IDC_SIZE_INCH, buff);
    }
}

/* The dialog box callback function */
static int InputLenDialogBoxProc (HWND hDlg, int message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
    case MSG_INITDIALOG:
        /* 
         * Save the pointer passed by the last parameter of DialogBoxIndirectParam
         * in the form of window additonal data for future use.
         */
        SetWindowAdditionalData (hDlg, lParam);
        /* Set the notification callback function for the edit box.
         */
        SetNotificationCallback (GetDlgItem (hDlg, IDC_SIZE_MM), my_notif_proc);
        return 1;

    case MSG_COMMAND:
        switch (wParam) {
        case IDOK:
        {
            char buff [40];
            /* Get data from the input box, and save it in the pointer passed in.
             */
            double* length = (double*) GetWindowAdditionalData (hDlg);
            GetWindowText (GetDlgItem (hDlg, IDC_SIZE_MM), buff, 32);
            *length = atof (buff);
        }
        case IDCANCEL:
            EndDialog (hDlg, wParam);
            break;
        }
        break;
    }

    return DefaultDialogProc (hDlg, message, wParam, lParam);
}

static void InputLenDialogBox (HWND hWnd, double* length)
{
    DlgBoxInputLen.controls = CtrlInputLen;

    DialogBoxIndirectParam (&DlgBoxInputLen, hWnd, InputLenDialogBoxProc, (LPARAM)length);
}

int MiniGUIMain (int argc, const char* argv[])
{
    double length;

#ifdef _MGRM_PROCESSES
    JoinLayer(NAME_DEF_LAYER , "input" , 0 , 0);
#endif

    InputLenDialogBox (HWND_DESKTOP, &length);

    /* Print the value input by the user in the dialog box to the terminal
     */
    printf ("The length is %.5f mm.\n", length);

    return 0;
}

#ifndef _MGRM_PROCESSES
#include <minigui/dti.c>
#endif

The running effect of the program in List 2 is shown in Figure 1. Please refer to the input.c file of the sample program package for this guide to get the complete source code of the program.

Figure 1 A simple input dialog box

In the Part IV, we will introduce the predefined controls of MiniGUI. We will describe all the predefined controls in three aspects: the purpose and usage of the control, the styles, messages, and notification codes. We will also give the sample code of the controls.

Operations Specific to Control

MiniGUI provides some operation functions specific to control, as show in Table 2.

Table 2 Operation functions specific to control

Function

Purpose

Comment

GetNotificationCallback

Gets the notification callback procedure of a control

Appear in MiniGUI version 1.2.6

SetNotificationCallback

Sets the notification callback procedure of a control

^

NotifyParentEx

Sends a notification message to the parent


<< Foundation of Dialog Box Programming | Table of Contents | Advanced Programming of Control >>

Last updated