使用资源--对话框--在对话框中使用子窗口控件
8、使用列表框
列表框提供一个可供用户选择的列表,用户可以一次选择一个项目,也可以同时选中多个项目。
//Listbox.rc
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define ICO_MAIN 0x1000 //图标
#define DLG_MAIN 1
#define IDC_LISTBOX1 101
#define IDC_LISTBOX2 102
#define IDC_SEL1 103
#define IDC_RESET 104
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN ICON "Main.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN DIALOG 163, 160, 190, 108
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "列表框控件示例"
FONT 9, "宋体"
{
LISTBOX IDC_LISTBOX1, 6, 5, 55, 86, LBS_STANDARD
LISTBOX IDC_LISTBOX2, 68, 5, 115, 86, LBS_STANDARD | LBS_MULTIPLESEL
LTEXT "", IDC_SEL1, 6, 93, 55, 8
PUSHBUTTON "复位(&R)", IDC_RESET, 89, 90, 45, 14
DEFPUSHBUTTON "查看(&S)", IDOK, 139, 90, 45, 14, WS_DISABLED
}
//Listbox.asm
.386
.model flat, stdcall
option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN equ 1000h
DLG_MAIN equ 1
IDC_LISTBOX1 equ 101
IDC_LISTBOX2 equ 102
IDC_SEL1 equ 103
IDC_RESET equ 104
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
hInstance dd ?
.const
szText1 db '项目1',0
szText2 db '项目2',0
szText3 db '项目3',0
szPath db '*.*',0
szMessage db '选择结果:%s',0
szTitle db '您的选择',0
szSelect db '您选择了以下的项目:'
szReturn db 0dh,0ah,0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMain proc uses ebx edi esi hWnd, wMsg, wParam, lParam
local @szBuffer[128]:byte
local @szBuffer1[128]:byte
local @szTextBuff[2048]:byte
local @dwCount
mov eax, wMsg
.if eax == WM_CLOSE
invoke EndDialog, hWnd, NULL
.elseif eax == WM_INITDIALOG
invoke LoadIcon, hInstance, ICO_MAIN
invoke SendMessage, hWnd, WM_SETICON, ICON_BIG, eax
;********************************************************************************
; 初始化列表框
;********************************************************************************
invoke SendDlgItemMessage, hWnd, IDC_LISTBOX1, LB_ADDSTRING, 0, addr szText1
invoke SendDlgItemMessage, hWnd, IDC_LISTBOX1, LB_ADDSTRING, 0, addr szText2
invoke SendDlgItemMessage, hWnd, IDC_LISTBOX1, LB_ADDSTRING, 0, addr szText3
invoke SendDlgItemMessage, hWnd, IDC_LISTBOX2, LB_DIR, DDL_ARCHIVE or DDL_DRIVES or DDL_DIRECTORY, addr szPath
;********************************************************************************
.elseif eax == WM_COMMAND
mov eax, wParam
.if ax == IDOK
invoke SendDlgItemMessage, hWnd, IDC_LISTBOX2, LB_GETSELCOUNT, 0, 0
mov @dwCount, eax
invoke SendDlgItemMessage, hWnd, IDC_LISTBOX2, LB_GETSELITEMS, 128/4, addr @szBuffer
invoke lstrcpy, addr @szTextBuff, addr szSelect
lea esi, @szBuffer
.while @dwCount
lodsd
lea ecx, @szBuffer1
invoke SendDlgItemMessage, hWnd, IDC_LISTBOX2, LB_GETTEXT, eax, ecx
invoke lstrcat, addr @szTextBuff, addr szReturn
invoke lstrcat, addr @szTextBuff, addr @szBuffer1
dec @dwCount
.endw
invoke MessageBox, hWnd, addr @szTextBuff, addr szTitle, MB_OK
.elseif ax == IDC_RESET
invoke SendDlgItemMessage, hWnd, IDC_LISTBOX2, LB_SETSEL, FALSE, -1
.elseif ax == IDC_LISTBOX1
shr eax, 16
.if ax == LBN_SELCHANGE
;********************************************************************************
; 将鼠标点击结果显示在文本框中
;********************************************************************************
invoke SendMessage, lParam, LB_GETCURSEL, 0, 0
lea ecx, @szBuffer
invoke SendMessage, lParam, LB_GETTEXT, eax, ecx
invoke SetDlgItemText, hWnd, IDC_SEL1, addr @szBuffer
;********************************************************************************
; 双击项目则弹出对话框
;********************************************************************************
.elseif ax == LBN_DBLCLK
invoke SendMessage, lParam, LB_GETCURSEL, 0, 0
lea ecx, @szBuffer
invoke SendMessage, lParam, LB_GETTEXT, eax, ecx
invoke wsprintf, addr @szBuffer1, addr szMessage, addr @szBuffer
invoke MessageBox, hWnd, addr @szBuffer1, addr szTitle, MB_OK
.endif
;********************************************************************************
.elseif ax == IDC_LISTBOX2
shr eax, 16
.if ax == LBN_SELCHANGE
invoke SendMessage, lParam, LB_GETSELCOUNT, 0, 0
mov ebx, eax
invoke GetDlgItem, hWnd, IDOK
invoke EnableWindow, eax, ebx
.endif
.endif
.else
mov eax, FALSE
ret
.endif
mov eax, TRUE
ret
_ProcDlgMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke DialogBoxParam, hInstance, DLG_MAIN, NULL, offset _ProcDlgMain, NULL
invoke ExitProcess, NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
程序中总共定义了两个列表框。左边列表框为IDC_LISTBOX1,这是一个单选的列表框,选择一个项目的时候下面的文本会显示出选择的项目,双击某个项目的时候会弹出消息框,显示所选中的项目。右边的列表框是IDC_LISTBOX2,是一个多选的列表框,选择完毕可以用“查看”按钮弹出消息框,消息框中显示了所有选中的项目。按下“复位”按钮清除列表框的选择。
列表框可以使用的风格
风格
|
说明
|
LBS_DISABLENOSCROLL
|
在不需滚动的时候也显示垂直滚动条
|
LBS_EXTENDEDSEL
|
在多选列表框中允许按住Shitf键同时选中一个范围
|
LBS_MULTIPLESEL
|
允许多选,如果不定义的话则是单选列表框
|
LBS_NOSEL
|
列表框项目只能查看不能选择
|
LBS_NOTIFY
|
用户点击或双击项目时向父窗口发送WM_COMMAND消息
|
LBS_SORT
|
自动按字母顺序排序插入的项目
|
LBS_USETABSTOPS
|
列表框项目的文本中允许将Tab字符的位置展开
|
LBS_STANDARD
|
组合LBS_NOTIFY, LBS_SORT, WS_VSCROLL和WS_BORDER
|
一般单选列表框只需定义LBS_STANDARD就可以了。
列表框使用说明:
当列表框有 LBS——NOTIFY风格的时候,用户有所动作时列表框会向父窗口发送WM_COMMAND,同时在wParam的高16位中指定通知码,列表框的通知码种类很少,基本上就是以下几种:
l LBN_DBLCLK 用户双击了一个项目。
l LBN_ERRSPACE 插入项目时无法申请到足够的内存。
l LBN_KILLFOCUS 输入焦点被切换到其他控件中,列表框丢失了焦点。
l LBN_SELCANCEL 用户撤销了一个选择。
l LBN_SELCHANGE 选定状态改变。
l LBN_SETFOCUS 列表框得到输入焦点。
我们最关心的是LBN_DBLCLK和LBN_SELCHANGE通知码,在单选列表框中,如果程序用双击来选择项目,那么就要处理LBN_DBLCLK通知,例子程序中当用户双击IDC_LISTBOX1时弹出一个消息框,读者可以查看其使用方法。在多选列表框中,由于用户可能选择了多个项目,所以一般不用双击的方法选定:如果收到LBN_SELCHANGE通知的话,可以得知用户有一个选择动作,在这里可以进行相应的操作。
列表框通知父窗口是通过发送WM_COMMAND消息,而程序控制列表框的时候是通过向列表框发送消息来完成的。
常用的列表框消息如下表所示:
消息
|
wParam
|
lParam
|
说明
|
LB_ADDSTRING
|
0
|
字符串地址
|
添加一个项目,返回加入后的索引。
|
LB_DELETESTRING
|
位置索引
|
0
|
删除一个项目,返回剩余的项数。
|
LB_FINDSTRING
|
开始索引
|
字符串地址
|
查找以字符串开头的项目,找到则返回位置索引,未找到则返回LB_ERR。
|
LB_FINDSTRINGEXACT
|
开始索引
|
字符串地址
|
精确查找一个项目,返回值同上。
|
LB_GETANCHORINGEX
|
0
|
0
|
返回多选列表框多选时的起始位置。
|
LB_GETCARETINGEX
|
0
|
0
|
多选列表框中的当前焦点项目位置。
|
LB_GETCOUNT
|
0
|
0
|
返回列表框中的项目总数
|
LB_GETCURSEL
|
0
|
0
|
返回单选列表框当前选中的项目。
|
LB_GETSEL
|
位置索引
|
0
|
检测指定项目的选中状态,返回非0为选中,返回0为未选中。
|
LB_GETSELCOUNT
|
0
|
0
|
返回多选列表框选中项目的总数
|
LB_GETSELITEMS
|
最大项数
|
缓冲区地址
|
返回多选列表框的选中项目索引列表到缓冲区中
|
LB_GETTEXT
|
位置索引
|
缓冲区地址
|
返回某个项目的字符串
|
LB_GETTEXTLEN
|
位置索引
|
0
|
返回某个项目的字符串长度
|
LB_GETTOPINDEX
|
0
|
0
|
返回当前可见的第一个项目位置
|
LB_INSERTSTRING
|
插入位置
|
字符串地址
|
在指定位置插入一个项目
|
LB_RESETCONTENT
|
0
|
0
|
删除所有项目
|
LB_SELECTSTRING
|
开始位置
|
字符串地址
|
将以指定字符串开头的项目选中
|
LB_SELITEMRANGE
|
选择状态
|
范围
|
在多选框中将一个范围选中或清除
|
LB_SETCURSEL
|
位置索引
|
0
|
在单选列表框中选中一个项目
|
LB_SETSEL
|
选择状态
|
位置索引
|
在多选框中将一个项目选中或清除
|
LB_SETTOPINDEX
|
位置索引
|
0
|
滚动显示到指定的项目
|
LB_DIR
|
属性
|
文件通配符
|
搜索目录并将符合文件通配符的文件名加入到列表框中
|
这些消息中LB_DIR是个比较有趣的消息,它可以将指定目录中的文件名自动列出来并加入列表框中,如例子中用*.*将当前目录中的全部文件名加到列表框中。LB_DIR消息中wParam参数可以指定的属性可以是是以下值的组合:
DDL_ARCHIVE 加入归档属性的文件。
DDL_DIRECTORY 加入目录。
DDL_DRIVES 加入驱动器名。
DDL_HIDDEN 包含隐含文件。
DDL_READONLY 包含只读文件。
DDL_READWRITE 包含可读写的文件。
DDL_SYSTEM 包含系统文件。
在列表框中初始化时加入项目可以使用LB_ADDSTRING和LB_INSERTSTRING消息,删除项目可以用LB_DELETESTRING消息,删除全部项目用LB_RESETCONTENT消息。
对于单选列表框,要获取选中项目可以发送LB_GETCURSEL消息,要得到这个项目的字符串需要用索引值通过LB_GETTEXT消息获取,读者可以查看例子中处理LBN_DBLCLK通知码的部分代码。
对于多选列表框,需要用LB_GETSELITEMS消息获取全部选中项目,这个消息返回的是一个列表,所有选中项目的索引按顺序排列返回到缓冲区中,所以在例子中处理“查看”按钮消息(IDOK)的时候,程序先发送LB_GETSELCOUNT消息得到选中的项目数,以便在下面用一个循环获取所有的项目,得到数目数后,再用LB_GETSELITEMS将选中项目的索引取到@szBuffer中,接下来进入一个循环,循环的次数就是LB_GETSELCOUNT得到的数值,在循环中,程序从@szBuffer中将索引值逐个取出并用LB_GETTEXT消息获取每一项的字符串,最后用一个MessageBox显示出来。