分享
 
 
 

通用控件

王朝c/c++·作者佚名  2006-01-06
窄屏简体版  字體: |||超大  

本课中我们将学习什么是通用控件和如何使用它们。

理论:

WIN95相对于WIN3X有几个加强的用户界面控件。其实在WIN95正式发行前这些控件就在使用,譬如:状态条、工具条等。以前程序员要自己去编程使用它们,现在微软已经把它们包含到了WIN9X和WINNT中了。

Toolbar ---工具条

Tooltip ---提示文本

Status bar ---状态条

Property sheet ---属性页单

Property page ---属性页

Tree view ---树型视图

List view ---列表视图

Animation ---动画

Drag list ---能够处理Drag-Drop的列表框

Header ---

Hot-key ---热键

Image list ---图象链表

Progress bar ---进程状态条

Right edit ---

Tab ---跳格表

Trackbar ---跟踪条

Up-down ---滚动条

因为通用控件的数量非常多,把它们全部装入内存并注册它们是非常浪费内存的。除了“RTF文本编辑”控件外其他控件的可执行代码都放在comctl32.dll中,这样其他的应用程序就可以使用它们了。“RTF文本编辑”控件在richedXX.dll中,由于该控件非常的复杂,所以也比其它控件大。

要加载comctl32.dll可以在您的应用程序中调用函数InitCommonControls。InitCommonControls函数是动态链接库comctl32.dll中的一个函数,只要在您的程序中的任意地方引用了该函数就、会使得WINDOWS的程序加载器PE Loader加载该库。函数InitCommonControls其实只有一条指令“ret”,它的唯一目的是为了使得在调用了个该函数的应用程序的可执行文件的PE头中的“引入”段中包含有comctl32.dll,这样无论什么时候该应用程序都会为您加载该库。所以真正初始化的工作是在该库的入口点处做的,在这里会注册所有的通用控件类,然后所有的通用控件就可以在这些类上进行创建,这就象创建其它的子窗口控件一样。

RTF文本编辑控件则不同。如果您要使用它,就必须调用LoadLibrary函数来动态加载,并调用FreeLibrary来动态地卸载。

现在我们学习如何创建这些通用控件。您可以用资源编辑器把它们放到一个对话框中,或者您也可以自己调用相关的函数来手动创建它们。几乎所有的通用控件都是调用函数CreateWindowEx或CreateWindow来创建的,您只要在其中传递通用控件的类名即可。有一些通用控件有一些特别的创建函数,但是其实这些函数在内部都调用了CreateWindowEx,只是包装后的函数更方便使用而已。经过包装的函数有:

CreateToolbarEx

CreateStatusWindow

CreatePropertySheetPage

PropertySheet

ImageList_Create

为了创建通用控件您必须要知道它们的类名,我们把类名列于如下:

类名 通用控件

ToolbarWindow32 Toolbar

tooltips_class32 Tooltip

msctls_statusbar32 Status bar

SysTreeView32 Tree view

SysListView32 List view

SysAnimate32 Animation

SysHeader32 Header

msctls_hotkey32 Hot-key

msctls_progress32 Progress bar

RICHEDIT Rich edit

msctls_updown32 Up-down

SysTabControl32 Tab

Property sheets、property pages和image list控件有它们自己的创建函数。Drag list其实是可以伸缩的listbox控件,所以它没有自己的类名。上面的类名是VC++的资源编辑器提供的,它们和Borland公司的WIN32 API指南中提出的不一样,和Petzold的书《Programming Windows 95》也不一样。可以肯定的是我们上面列出的类名绝对准确。 这些通用控件可以有通用的窗口类的一些风格,譬如WS_CHILD等。它们当然还有其他的特殊风格,譬如树型视图控件就有TVS_XXXXX风格,列表控件就有LVS_xxxx风格。具体的最好查找有关的WIN32 API函数指南。 既然我们已经知道了如何创建一个通用控件,我们就可以讨论这些通用控件之间以及和它们的父窗口之间是如何通讯的了。不象子窗口控件,通用控件在某些状态发生变化时不是通过发送WM_COMMAND而是发送WM_NOTIFY消息和父窗口通讯的。父窗口可以通过发送消息来控制子窗口的行为。对于那些新的通用控件,还有一些新的消息类型。您可以参考您的WIN32 API手册。

在下面的例子中我们将要实验一下进度条和状态条。

例子代码:

.386

.model flat,stdcall

option casemap:none

include \masm32\include\windows.inc

include \masm32\include\user32.inc

include \masm32\include\kernel32.inc

include \masm32\include\comctl32.inc

includelib \masm32\lib\comctl32.lib

includelib \masm32\lib\user32.lib

includelib \masm32\lib\kernel32.lib

WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD

.const

IDC_PROGRESS equ 1 ; control IDs

IDC_STATUS equ 2

IDC_TIMER equ 3

.data

ClassName db "CommonControlWinClass",0

AppName db "Common Control Demo",0

ProgressClass db "msctls_progress32",0 ; the class name of the progress bar

Message db "Finished!",0

TimerID dd 0

.data?

hInstance HINSTANCE ?

hwndProgress dd ?

hwndStatus dd ?

CurrentStep dd ?

.code

start:

invoke GetModuleHandle, NULL

mov hInstance,eax

invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT

invoke ExitProcess,eax

invoke InitCommonControls

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD

LOCAL wc:WNDCLASSEX

LOCAL msg:MSG

LOCAL hwnd:HWND

mov wc.cbSize,SIZEOF WNDCLASSEX

mov wc.style, CS_HREDRAW or CS_VREDRAW

mov wc.lpfnWndProc, OFFSET WndProc

mov wc.cbClsExtra,NULL

mov wc.cbWndExtra,NULL

push hInst

pop wc.hInstance

mov wc.hbrBackground,COLOR_APPWORKSPACE

mov wc.lpszMenuName,NULL

mov wc.lpszClassName,OFFSET ClassName

invoke LoadIcon,NULL,IDI_APPLICATION

mov wc.hIcon,eax

mov wc.hIconSm,eax

invoke LoadCursor,NULL,IDC_ARROW

mov wc.hCursor,eax

invoke RegisterClassEx, addr wc

invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\

WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,\

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\

hInst,NULL

mov hwnd,eax

.while TRUE

invoke GetMessage, ADDR msg,NULL,0,0

.BREAK .IF (!eax)

invoke TranslateMessage, ADDR msg

invoke DispatchMessage, ADDR msg

.endw

mov eax,msg.wParam

ret

WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

.if uMsg==WM_CREATE

invoke CreateWindowEx,NULL,ADDR ProgressClass,NULL,\

WS_CHILD+WS_VISIBLE,100,\

200,300,20,hWnd,IDC_PROGRESS,\

hInstance,NULL

mov hwndProgress,eax

mov eax,1000 ; the lParam of PBM_SETRANGE message contains the range

mov CurrentStep,eax

shl eax,16 ; the high range is in the high word

invoke SendMessage,hwndProgress,PBM_SETRANGE,0,eax

invoke SendMessage,hwndProgress,PBM_SETSTEP,10,0

invoke CreateStatusWindow,WS_CHILD+WS_VISIBLE,NULL,hWnd,IDC_STATUS

mov hwndStatus,eax

invoke SetTimer,hWnd,IDC_TIMER,100,NULL ; create a timer

mov TimerID,eax

.elseif uMsg==WM_DESTROY

invoke PostQuitMessage,NULL

.if TimerID!=0

invoke KillTimer,hWnd,TimerID

.endif

.elseif uMsg==WM_TIMER ; when a timer event occurs

invoke SendMessage,hwndProgress,PBM_STEPIT,0,0 ; step up the progress in the progress bar

sub CurrentStep,10

.if CurrentStep==0

invoke KillTimer,hWnd,TimerID

mov TimerID,0

invoke SendMessage,hwndStatus,SB_SETTEXT,0,addr Message

invoke MessageBox,hWnd,addr Message,addr AppName,MB_OK+MB_ICONINFORMATION

invoke SendMessage,hwndStatus,SB_SETTEXT,0,0

invoke SendMessage,hwndProgress,PBM_SETPOS,0,0

.endif

.else

invoke DefWindowProc,hWnd,uMsg,wParam,lParam

ret

.endif

xor eax,eax

ret

WndProc endp

end start

分析:

invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT

invoke ExitProcess,eax

invoke InitCommonControls

我故意把函数InitCommonControls放到ExitProcess后,这样就可以验证调用该函数仅仅是为了在我们程序的可执行文件的PE头中的引入段中放入引用了comctl32.dll的信息。您可以看到,即使该函数什么都没有做,我们的通用控件对话框依旧可以正常工作。

.if uMsg==WM_CREATE

invoke CreateWindowEx,NULL,ADDR ProgressClass,NULL,\

WS_CHILD+WS_VISIBLE,100,\

200,300,20,hWnd,IDC_PROGRESS,\

hInstance,NULL

mov hwndProgress,eax

在这里我们创建了通用控件。注意CreateWindowEx函数中的参数hWnd是父窗口的句柄。另外它也指定了通用控件的ID号。因为我们直接使用控件的窗口句柄,所以就没有使用该ID号。所有的窗口都必须具有WS_CHILD风格。

mov eax,1000

mov CurrentStep,eax

shl eax,16

invoke SendMessage,hwndProgress,PBM_SETRANGE,0,eax

invoke SendMessage,hwndProgress,PBM_SETSTEP,10,0

在创建了进度条后我们先设定它的范围。缺省的范围是0-100。如果您不满意,可以重新设置,这通过传递PBM_SETRANGE消息来实现。参数lParam中包含了范围值,其中底字和高字分别是范围的起始和终了的值。您可以指定进度条每移动一格的步长。本例子中把步长设置成10,意味着每发送一次PBM_STEPIT消息给进度条,它的显示指针就会移动10。当然您可以调用PBM_SETPOS 来直接设定进度条上的指针的位置。用该消息您可以更方便地设定进度条了。

invoke CreateStatusWindow,WS_CHILD+WS_VISIBLE,NULL,hWnd,IDC_STATUS

mov hwndStatus,eax

invoke SetTimer,hWnd,IDC_TIMER,100,NULL ; create a timer

mov TimerID,eax

下面我们调用CreateStatusWindow来创建状态条。这个调用很好理解,无需我多解释。在状态条创建后我们创建一个计时器。在本例中我们每隔100毫秒就更新一次进度条。下面时创建记时器的函数原型:

SetTimer PROTO hWnd:DWORD, TimerID:DWORD, TimeInterval:DWORD, lpTimerProc:DWORD

hWnd : 父窗口的句柄。

TimerID : 计时器的ID号。您可以指定一个唯一的非零值。

TimerInterval : 以毫秒计的时间间隔。

lpTimerProc : 计时器回调函数的地址。每当时间间隔到了的时候,该函数就会被系统调用。如果该值为NULL,计时器就会把WM_TIMER消息发送到父窗口。

如果SetTimer调用成功的话就会返回计时器的ID号值,否则返回0。这也是为什么计时器的ID号必须为非零值的原因。

.elseif uMsg==WM_TIMER

invoke SendMessage,hwndProgress,PBM_STEPIT,0,0

sub CurrentStep,10

.if CurrentStep==0

invoke KillTimer,hWnd,TimerID

mov TimerID,0

invoke SendMessage,hwndStatus,SB_SETTEXT,0,addr Message

invoke MessageBox,hWnd,addr Message,addr AppName,MB_OK+MB_ICONINFORMATION

invoke SendMessage,hwndStatus,SB_SETTEXT,0,0

invoke SendMessage,hwndProgress,PBM_SETPOS,0,0

.endif

当指定的时间到了的时候,计时器将发送WM_TIMER消息。您可以在处理该消息时作适当的处理。本例中我们将更新进度条,并检查进度条是否超过最大的值。如果超过了的话,我们通过发送SB_SETTEXT消息来在状态条中设置文本。这时,弹出一个对话框,当用户关闭掉对话框后,我们去除掉进度条和状态条中的文本。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有