Files
minigui-docs/programming-guide-zh/MiniGUIProgGuidePart6Chapter03-zh.md
lisimeng123 24cfe07828 update
2022-11-21 08:46:18 +08:00

25 KiB
Raw Blame History

列表框

列表框通常为用户提供一系列的可选项这些可选项显示在可滚动的子窗口中用户可通过键盘及鼠标操作来选中某一项或者多个项选中的列表项通常高亮显示。列表框的最典型用法就是文件打开对话框见__图 1.1__。

列表框的典型应用场合:“打开文件”对话框 图 1.1 列表框的典型应用场合:“打开文件”对话框

CTRL_LISTBOX 为控件类名调用 CreateWindow 函数,即可创建列表框控件。

1.1 列表框的类型和风格

MiniGUI 的列表框控件可划分为三种类型:单选列表框、多选列表框和位图列表框。默认情况下,列表框是单项选择的,用户只能从中选择一个列表项。如果要建立一个可选择多个列表项的列表框,则应使用 LBS_MULTIPLESEL 风格。使用该风格时用户可通过单击某个项的方法选中这个项再次单击将取消对其的选中。当列表框拥有输入焦点时也可以使用空格键选择某个项或者取消某个项的选择。多选列表框的运行效果如__图 1.2__ 所示。

多选列表框 图 1.2 多选列表框

除上述两种列表框的基本形态之外MiniGUI 还提供有一种高级列表框类型。这种列表框中的列表项不仅仅是字符串,还可以用来附带位图或者图标,还可以在列表项旁边显示一个检查框,代表选中或者未选中。要建立这种高级列表框,需用指定 LBS_USEICON 或者 LBS_CHECKBOX 风格。图 1.3 是这种高级列表框的运行效果。如果希望在用户单击检查框时自动切换选中状态,则可以使用 LBS_AUTOCHECK 风格。高级列表框也可以具有 LBS_MULTIPLESEL 风格。

高级列表框 图 1.3 高级列表框

除上述用来区别列表框类型的风格之外,还可以在创建列表框时指定其他通用风格。

默认状态下,列表框窗口消息处理程序只显示列表条目,它的周围没有任何边界。你可以使用窗口风格 WS_BORDER 来加上边框。另外,你可以使用窗口风格 WS_VSCROLL 来增加垂直滚动条,以便用鼠标来滚动列表框条目,也可以使用 WS_HSCROLL 来增加水平滚动条,可以用来显示超出列表框宽度的条目。

缺省的列表框风格不会在用户选中某个列表项时产生通知消息,这样一来,程序必须向列表框发送消息以便了解其中条目的选择状态。所以,列表框控件通常都包括列表框风格 LBS_NOTIFY,它可以使列表框控件在用户进行操作时,将一些状态信息及时反馈给应用程序。

另外,如果希望列表框控件对列表框中的条目进行排序,那么可以使用另一种常用的风格 LBS_SORT

一般情况下,创建列表框控件最常用的风格组合如下:

(LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER)

1.2 列表框消息

1.2.1 将字符串加入列表框

建立列表框之后,下一步是将字符串放入其中,你可以通过调用 SendMessage 为列表框窗口消息处理程序发送消息来做到这一点。字符串通常通过以0开始计数的索引数来引用其中 0 对应于最顶上的条目。在下面的例子中,hwndList 是子窗口列表框控件的句柄,而 index 是索引值。在使用 SendMessage 传递字符串的情况下,lParam 参数是指向以 NULL 字符结尾的字符串指针。

在大多数例子中,当列表框控件所能存储的内容超过了可用内存空间时,SendMessage 将传回 LB_ERRSPACE。如果是因为其他原因而出错,那么 SendMessage 将传回 LB_ERR。如果操作成功,那么 SendMessage 将传回 LB_OKAY。我们可以通过测试 SendMessage 的非零值来判断出这两种错误。

如果你采用 LBS_SORT 风格,或者仅仅希望将新的字符串追加为列表框的最后一项,那么填入列表框最简单的方法是借助 LB_ADDSTRING 消息:

SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM)string) ;

我们也可以使用 LB_INSERTSTRING 指定一个索引值,将字符串插入到列表框中的指定位置:

SendMessage (hwndList, LB_INSERTSTRING, index, (LPARAM)string) ;

例如,如果 index 等于 4那么 string 将变为索引值为 4 的字符串――从顶头开始算起的第 5 个字符串(因为是从 0 开始计数的),位于这个点后面的所有字符串都将向后推移。索引值为 -1 时,将字符串增加在最后。我们也可以对具有 LBS_SORT 风格的列表框使用 LB_INSERTSTRING,但是这时列表框将会忽略 index 的值,而根据排序的结果插入新的项。

需要注意的是,在指定了 LBS_CHECKBOX 或者 LBS_USEICON 风格之后,在向列表框添加条目时,必须使用 LISTBOXITEMINFO 结构,而不能直接使用字符串地址,例如:

HICON hIcon1;           /* 声明图标句柄 */
LISTBOXITEMINFO lbii;   /* 声明列表框条目结构体变量 */

hIcon1 = LoadIconFromFile (HDC_SCREEN, "res/audio.ico", 1);  /* 加载图标 */

/* 设定结构信息,并添加条目 */
lbii.hIcon = hIcon1;
lbii.cmFlag = CMFLAG_CHECKED;
lbii.string = "abcdefg";
SendMessage (hChildWnd3, LB_ADDSTRING, 0, (LPARAM)&lbii);

其中,cmFlag 的值可以设置为 CMFLAG_CHECKEDCMFLAG_BLANK 以及 CMFLAG_PARTCHECKED 三种,分别表示:选中、未选中和部分选中。

我们也可以在高级列表框中显示位图,而不是默认的图标。如果你希望列表项显示的是位图而不是图标,则可以在该标志中包含 IMGFLAG_BITMAP,并在 hIcon 成员中指定位图对象的指针,如下所示:

/* 设定结构信息,并添加条目 */
lbii.hIcon = (DWORD) GetSystemBitmap (SYSBMP_MAXIMIZE);
lbii.cmFlag = CMFLAG_CHECKED | IMGFLAG_BITMAP;
lbii.string = "abcdefg";
SendMessage (hChildWnd3, LB_ADDSTRING, 0, (LPARAM)&lbii);

1.2.2 删除列表框条目

发送 LB_DELETESTRING 消息并指定索引值就可以从列表框中删除指定的条目:

SendMessage (hwndList, LB_DELETESTRING, index, 0) ;

我们甚至可以使用 LB_RESETCONTENT 消息清空列表框中的所有内容:

SendMessage (hwndList, LB_RESETCONTENT, 0, 0) ;

1.2.3 选择和取得条目

发送 LB_GETCOUNT 消息可获得列表框中的条目个数:

count = SendMessage (hwndList, LB_GETCOUNT, 0, 0) ;

在需要获得某个条目的字符串时,可发送 LB_GETTEXTLEN 消息确定列表框中指定条目的字符串长度:

length = SendMessage (hwndList, LB_GETTEXTLEN, index, 0) ;

并将该条目复制到文字缓冲区中:

length = SendMessage (hwndList, LB_GETTEXT, index, (LPARAM)buffer) ;

在这两种情况下,上述消息返回的 length 值是字符串的长度。对以 NULL 字符终结的字符串长度来说,buffer 必须足够大才行。你可以用 LB_GETTEXTLEN 消息返回的字符串长度来分配一些局部内存来存放字符串。

如果我们要设置列表框条目的字符串,可发送 LB_SETTEXT 消息:

SendMessage (hwndList, LB_SETTEXT, index, buffer) ;

对于高级列表框来讲,我们必须使用 LB_GETITEMDATALB_SETITEMDATA 才能获得列表框条目的其他信息,比如位图对象或图标句柄、检查框状态等,这些消息也可以用来获取或设置条目的字符串:

HICON hIcon1;           /* 声明图标句柄 */
LISTBOXITEMINFO lbii;   /* 声明列表框条目结构体变量 */

hIcon1 = LoadIconFromFile (HDC_SCREEN, "res/audio.ico", 1);  /* 加载图标 */

/* 设定结构信息,并添加条目 */
lbii.hIcon = hIcon1;
lbii.cmFlag = CMFLAG_CHECKED;
lbii.string = "new item";
SendMessage (hChildWnd3, LB_SETITEMDATA, index, (LPARAM)&lbii);

下面的消息用来检索列表框条目的选中状态,这些消息对单项选择列表框和多项选择列表框具有不同的调用方法。让我们先来看看单项选择列表框。

通常,用户会通过鼠标和键盘在列表框中选择条目。但是我们也可以通过程序来控制当前的选中项,这时,需要发送 LB_SETCURSEL 消息:

SendMessage (hwndList, LB_SETCURSEL, index, 0) ;

反之,我们可以使用 LB_GETCURSEL 获得当前选定的索引项:

index = SendMessage (hwndList, LB_GETCURSEL, 0, 0) ;

如果没有条目被选中,那么这个消息将返回 LB_ERR

对于多项选择列表框来说,使用 LB_SETCURSELLB_GETCURSEL 只能用来设置和获取当前高亮项,无法获得所有具有选中状态的条目。但我们可以使用 LB_SETSEL 来设定某特定条目的选择状态,而不影响其他项:

SendMessage (hwndList, LB_SETSEL, wParam, (LPARAM)index) ;

wParam 参数不为 0 时,选择并加亮某一条目;wParam 为 0 时,取消选择。反之,我们可以用 LB_GETSEL 消息确定某特定条目的选择状态:

select = SendMessage (hwndList, LB_GETSEL, index, 0) ;

其中,如果由 index 指定的条目被选中,select 为非 0否则为 0。

另外,你还可以使用 LB_GETSELCOUNT 消息获得多选列表框中当前被选中的条目个数。然后发送 LB_GETSELITEMS 消息获得所有被选中条目的索引值。示例如下:

int i, sel_count;
int* sel_items;

sel_count = SendMessage (hwndList, LB_GETSELCOUNT, 0, 0L) ;
if (sel_count == 0)
return;

sel_items = alloca (sizeof(int)*sel_count);
SendMessage (hwndList, LB_GETSELITEMS, sel_count, sel_items);
for (i = 0; i < sel_count; i++) {
        /* sel_items [i] 为选中条目的索引值 */
}

1.2.4 查找含有字符串的条目

index = SendMessage (hwndList, LB_FINDSTRING, (LPARAM)string) ;

其中,string 为希望查找的字符串的指针,该消息返回模糊匹配字符串 string 的条目索引值,LB_ERR 表示查找失败。如果使用消息 LB_FINDSTRINGEXACT 将进行严格精确匹配查找。

1.2.5 设置和获取某条目的检查框的当前状态

status = SendMessage (hwndList, LB_GETCHECKMARK, index, 0) ;

返回由 index 指定索引处条目的检查框的状态。如果没有找到相应条目,则返回 LB_ERRCMFLAG_CHECKED 表示该条目的检查框处于选择状态。CMFLAG_PARTCHECKED 表示该条目的检查框处于部分选择状态。CMFLAG_BLANK 表示该条目的检查框处于未选择状态。

ret = SendMessage (hwndList, LB_SETCHECKMARK, index, (LPARAM)status) ;

设置由 index 指定索引处条目的检查框的状态为 status 中指定的值。当没有找到 index 指定的条目时,返回 LB_ERR 表示失败,否则返回 LB_OKAY 表示成功。

1.2.6 设置某列表框条目加粗显示状态

ret = SendMessage (hwndList, LB_SETITEMBOLD, index, (LPARAM)status) ;

设置由 index 指定索引处条目的检查框的状态为加粗显示状态。当没有找到 index 指定的条目时,返回 LB_ERR 表示失败,否则根据 lParam 的值判断是否进行加粗设置,如果为 1 则加粗显示,为 0 则正常显示。

1.2.7 设置和获取某列表框条目的选择状态

status = SendMessage (hwndList, LB_GETITEMDISABLE, index, 0) ;

返回由 index 指定索引处条目的检查框是否处于禁止选中状态。如果没有找到相应条目,则返回 LB_ERR。1 表示该条目的检查框处于禁止选中状态。0 表示该条目的检查框处于可选择状态。

ret = SendMessage (hwndList, LB_SETITEMDISABLE, index, (LPARAM)status) ;

设置由 index 指定索引处条目的检查框的状态为禁止选中状态。当没有找到 index 指定的条目时,返回 LB_ERR 表示失败,否则根据 lParam 的值判断是否进行禁止选中状态设置,如果为 1 则设置为禁止选中状态,为 0 则为可选择状态。

1.2.8 添加多个列表框条目

LB_MULTIADDITEM 消息用于向列表框一次添加多个条目。当列表框控件所能存储的内容超过了可用内存空间时,SendMessage 将传回 LB_ERRSPACE。如果是因为其他原因而出错,那么SendMessage 将传回 LB_ERR。如果操作成功,那么 SendMessage 将传回 LB_OKAY。我们可以通过测试 SendMessage 的非零值来判断出这两种错误。

如果你采用 LBS_SORT 风格,或者仅仅希望将新的字符串数组追加到列表框条目中,方法如下:

int num = 2;
const char text[num][] = {item1, item2};

SendMessage (hwndList, LB_MULTIADDITEM, num, (LPARAM)text);

其中 hwndList 是列表框控件的句柄,num 是添加的条目数,text 是字符串数组。

需要注意的是,在指定了 LBS_CHECKBOX 或者 LBS_USEICON 风格之后,在向列表框添加多个条目时,必须使用 LISTBOXITEMINFO 结构,而不能直接使用字符串数组地址,例如:

int num = 2;
HICON hIcon1;           /* 声明图标句柄 */
LISTBOXITEMINFO lbii[num];   /* 声明列表框条目结构体变量数组 */

hIcon1 = LoadIconFromFile (HDC_SCREEN, "res/audio.ico", 1);  /* 加载图标 */

/* 设定结构信息,并添加条目 */
lbii[0].hIcon = hIcon1;
lbii[0].cmFlag = CMFLAG_CHECKED;
lbii[0].string = "item1";

lbii[1].hIcon = hIcon1;
lbii[1].cmFlag = CMFLAG_CHECKED;
lbii[1].string = "item2";

SendMessage (hwndList, LB_MULTIADDITEM, num, (LPARAM)lbii);

1.2.9 其他消息

默认情况下,具有 LBS_SORT 风格的列表框在排序时使用标准 C 函数的 strncmp 函数排序。但我们可以通过 LB_SETSTRCMPFUNC 来重载默认的排序方式,而以自己希望的方式排序。比如:

static int my_strcmp (const char* s1, const char* s2, size_t n)
{
        int i1 = atoi (s1);
        int i2 = atoi (s2);
        return (i1  i2);
}

SendMessage (hwndList, LB_SETSTRCMPFUNC, 0, (LPARAM)my_strcmp);

这样,列表框将使用我们自己定义的函数对条目进行排序。上述排序函数可用来对诸如 1、2、3、4、10、20 等条目进行正常的以数值为大小的排序,而默认的排序规则会将上述 6 个数字排序为 1、10、2、20、3、4。一般而言应用程序要在添加条目之前使用该消息设定新的字符串比较函数。

我们还可以为每个列表框条目追加一个附加的 32 位数据,并在适当的时候将这个值取出,这时,我们可以使用 LB_SETITEMADDDATALB_GETITEMADDDATA 消息。这两个消息所操作的值对列表框控件来说没有任何意义,它只是负责存储这个值,并在需要时返回这个值。

另外,我们还可以使用 LB_SETITEMHEIGHT 来消息来设定条目所占的高度,LB_GETITEMHEIGHT 返回这个高度。通常情况下,条目的高度取决于控件字体的大小,当控件字体发生变化时(调用 SetWindowFont 而改变),条目的高度将发生变化。用户也可以设定一个自己的条目高度。实际的高度将是设定高度和控件字体大小的最大值。

1.3 列表框通知码

具有 LBS_NOTIFY 风格的列表框可能产生的通知消息及其含义如__表 1.1__ 所示。

表 1.1 列表框通知码

通知码标识符 含义
LBN_ERRSPACE 内存分配失败。
LBN_SELCHANGE 单项选择列表框的当前选择项发生变化。
LBN_CLICKED 用户在列表框某条目上单击了鼠标左键。
LBN_DBLCLK 用户在列表框某条目上双击了鼠标左键。
LBN_SELCANCEL 用户取消了某个条目的选择。
LBN_SETFOCUS 列表框获得了输入焦点。
LBN_KILLFOCUS 列表框失去了输入焦点。
LBN_CLICKCHECKMARK 用户单击了条目的检查框。
LBN_ENTER 用户在列表框中按下 ENTER

只有列表框窗口风格包括 LBS_NOTIFY 时,列表框控件才会向父窗口发送上述通知消息。当然,如果你调用 SetNotificationCallback 函数设定了列表框控件的通知回调函数,则控件不会向父窗口发送 MSG_COMMAND 通知消息,而是会直接调用设定的通知回调函数。

LBN_ERRSPACE 表示内存分配失败。LBN_SELCHANGE 表示目前选中条目已经被改变,这个消息出现在下列情况下:用户在列表框中使用键盘或鼠标改变加亮的条目时,或者用户使用空格键或鼠标切换选择状态时。LBN_CLICKED 表示列表框被鼠标点击了。该消息出现在使用鼠标单击某项时。LBN_DBLCLK 说明某条目已经被鼠标双击。如果设置了 LBS_CHECKBOX 风格,LBN_CLICKCHECKMARK 表示鼠标击中了检查方框,如果同时设置了 LBS_AUTOCHECK 风格,则检查框会自动在勾选或者空白间切换。

根据应用程序的需要,也许要使用 LBN_SELCHANGELBN_DBLCLK,也许二者都要使用。程序会收到许多 LBN_SELCHANGE 消息,但是 LBN_DBLCLK 消息只有当使用者双击鼠标时才会出现。

1.4 编程实例

清单 1.1 所示的程序代码给出了列表框控件的使用范例。该程序仿照“打开文件”对话框实现了文件删除功能。初始时程序列出了当前目录下的所有文件用户也可以通过目录列表框切换到其他路径。用户可在文件列表框中通过检查框选择多个要删除的文件当用户按“删除”按钮时该程序将提示用户。当然为了保护用户的文件该程序并未实现真正的删除功能。该程序创建的对话框效果如__图 1.4__ 所示,完整源代码见本指南示例程序包 mg-samples 中的 listbox.c 文件。

清单 1.1 列表框控件的使用范例

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <errno.h>

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

#define IDL_DIR    100
#define IDL_FILE   110
#define IDC_PATH   120

/* 定义对话框模板 */
static DLGTEMPLATE DlgDelFiles =
{
        WS_BORDER | WS_CAPTION,
        WS_EX_NONE,
        100, 100, 304, 225,
        "删除文件",
        0, 0,
        7, NULL,
        0
};

static CTRLDATA CtrlDelFiles[] =
{ 
        {
                CTRL_STATIC,
                WS_VISIBLE | SS_SIMPLE, 
                10, 10, 130, 15,
                IDC_STATIC,
                "目录列表框",
                0
        },
        /* 这个列表框中显示目录项 */
        {
                CTRL_LISTBOX,
                WS_VISIBLE | WS_VSCROLL | WS_BORDER | LBS_SORT | LBS_NOTIFY,
                10, 30, 130, 100,
                IDL_DIR,
                "",
                0
        },
        {
                CTRL_STATIC,
                WS_VISIBLE | SS_SIMPLE, 
                150, 10, 130, 15, 
                IDC_STATIC, 
                "文件列表框",
                0
        },
        /* 这个列表框中显示文件,前面带一个检查框 */
        {
                CTRL_LISTBOX,
                WS_VISIBLE | WS_VSCROLL | WS_BORDER | LBS_SORT | LBS_AUTOCHECKBOX,
                150, 30, 130, 100,
                IDL_FILE,
                "",
                0
        },
        /* 这个静态框用来显示当前路径信息 */
        {
                CTRL_STATIC,
                WS_VISIBLE | SS_SIMPLE, 
                10, 150, 290, 15, 
                IDC_PATH, 
                "路径:",
                0
        },
        {
                "button",
                WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_GROUP,
                10, 170, 130, 25,
                IDOK, 
                "删除",
                0
        },
        {
                "button",
                WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
                150, 170, 130, 25,
                IDCANCEL,
                "取消",
                0
        },
};

/* 这个函数获取当前目录下的所有目录项,分别填到目录列表框和文件列表框中 */
static void fill_boxes (HWND hDlg, const char* path)
{
        struct dirent* dir_ent;
        DIR*   dir;
        struct stat ftype;
        char   fullpath [PATH_MAX + 1];
        
        SendDlgItemMessage (hDlg, IDL_DIR, LB_RESETCONTENT, 0, (LPARAM)0);
        SendDlgItemMessage (hDlg, IDL_FILE, LB_RESETCONTENT, 0, (LPARAM)0);
        SetWindowText (GetDlgItem (hDlg, IDC_PATH), path);
        
        if ((dir = opendir (path)) == NULL)
        return;
        
        while ( (dir_ent = readdir ( dir )) != NULL ) {
                
                /* Assemble full path name. */
                strncpy (fullpath, path, PATH_MAX);
                strcat (fullpath, "/");
                strcat (fullpath, dir_ent->d_name);
                
                if (stat (fullpath, &ftype) < 0 ) {
                        continue;
                }
                
                if (S_ISDIR (ftype.st_mode))
                SendDlgItemMessage (hDlg, IDL_DIR, LB_ADDSTRING, 0, (LPARAM)dir_ent->d_name);
                else if (S_ISREG (ftype.st_mode)) {
                        /* 使用检查框的列表框,需要使用下面的结构 */
                        LISTBOXITEMINFO lbii;
                        
                        lbii.string = dir_ent->d_name;
                        lbii.cmFlag = CMFLAG_BLANK;
                        lbii.hIcon = 0;
                        SendDlgItemMessage (hDlg, IDL_FILE, LB_ADDSTRING, 0, (LPARAM)&lbii);
                }
        }
        
        closedir (dir);
}

static void dir_notif_proc (HWND hwnd, int id, int nc, DWORD add_data)
{
        /* 用户双击目录名或者按下 ENTER 键时,进入对应的目录 */
        if (nc == LBN_DBLCLK || nc == LBN_ENTER) {
                int cur_sel = SendMessage (hwnd, LB_GETCURSEL, 0, 0L);
                if (cur_sel >= 0) {
                        char cwd [MAX_PATH + 1];
                        char dir [MAX_NAME + 1];
                        GetWindowText (GetDlgItem (GetParent (hwnd), IDC_PATH), cwd, MAX_PATH);
                        SendMessage (hwnd, LB_GETTEXT, cur_sel, (LPARAM)dir);
                        
                        if (strcmp (dir, ".") == 0)
                        return;
                        strcat (cwd, "/");
                        strcat (cwd, dir);
                        /* 重新填充两个列表框 */
                        fill_boxes (GetParent (hwnd), cwd);
                }
        }
}

static void file_notif_proc (HWND hwnd, int id, int nc, DWORD add_data)
{
        /* Do nothing */
}

static void prompt (HWND hDlg)
{
        int i;
        char files [1024] = "你选择要删除的文件是:\n";
        
        /* 获取所有勾选的文件 */
        for (i = 0; i < SendDlgItemMessage (hDlg, IDL_FILE, LB_GETCOUNT, 0, 0L); i++) {
                char file [MAX_NAME + 1];
                int status = SendDlgItemMessage (hDlg, IDL_FILE, LB_GETCHECKMARK, i, 0);
                if (status == CMFLAG_CHECKED) {
                        SendDlgItemMessage (hDlg, IDL_FILE, LB_GETTEXT, i, (LPARAM)file);
                        strcat (files, file);
                        strcat (files, "\n");
                }
        }
        
        /* 提示用户 */
        MessageBox (hDlg, files, "确认删除", MB_OK | MB_ICONINFORMATION);
        
        /* 在这里把那些文件真正删除! */
}

static int DelFilesBoxProc (HWND hDlg, int message, WPARAM wParam, LPARAM lParam)
{
        switch (message) {
                case MSG_INITDIALOG:
                {
                        char cwd [MAX_PATH + 1];
                        SetNotificationCallback (GetDlgItem (hDlg, IDL_DIR), dir_notif_proc);
                        SetNotificationCallback (GetDlgItem (hDlg, IDL_FILE), file_notif_proc);
                        fill_boxes (hDlg, getcwd (cwd, MAX_PATH));
                        return 1;
                }
                
                case MSG_COMMAND:
                switch (wParam) {
                        case IDOK:
                        prompt (hDlg);
                        case IDCANCEL:
                        EndDialog (hDlg, wParam);
                        break;
                }
                break;
                
        }
        
        return DefaultDialogProc (hDlg, message, wParam, lParam);
}

int MiniGUIMain (int argc, const char* argv[])
{
        #ifdef _MGRM_PROCESSES
        JoinLayer(NAME_DEF_LAYER , "listbox" , 0 , 0);
        
        #endif
        
        DlgDelFiles.controls = CtrlDelFiles;
        
        DialogBoxIndirectParam (&DlgDelFiles, HWND_DESKTOP, DelFilesBoxProc, 0L);
        
        return 0;
}

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

“删除文件”对话框 图 1.4 “删除文件”对话框