Win32汇编教程六
工具栏和状态栏的使用

在这儿下载本节的所有源程序

有关工具栏和状态栏

    工具栏和状态栏也是Windows标准界面的组成部分,工具栏一般位于菜单栏的下方,上面是一些系统定义的或自己定义的图片,可以通俗地显示这个按钮的作用。状态栏一般位于窗口的最下方,用来显示程序运行中的一些信息。工具栏和状态栏是Windows系统的两个通用的控件,你可以通过两个专用的 API 或者利用 CreateWindowEx 再使用制定的已经由系统定义的类来创建它们。这两个 API 分别是 CreateToolbarEx 和 CreateStatusWindow。下面将一下它们的用法。
    CreateToolbarEx 的声明为:

HWND CreateToolbarEx(

    HWND hwnd,	
    DWORD ws,	
    UINT wID, 	
    int nBitmaps, 	
    HINSTANCE hBMInst, 	
    UINT wBMID, 	
    LPCTBBUTTON lpButtons, 	
    int iNumButtons, 	
    int dxButton, 	
    int dyButton, 	
    int dxBitmap, 	
    int dyBitmap, 	
    UINT uStructSize}

它的参数中 hwnd 是父窗口(也就是我们的主窗口)的句柄,ws 是工具栏的风格,可以由几项合成,如 WS_VISIBLE 是创建是可见,TBSTYLE_FLAT表示平面按钮,WS_BORDER表示有边线等,具体可以见手册。wID 是工具栏的标识,nBitmaps 是定义按钮的图片个数,因为如果你要使用自己的图片,所有图片是要放在同一行中的,然后就由你自己指定中间的个数, hBMInst 是包含已定义系统图片的资源句柄,在你不想自己画图,使用内定的标准图片时使用,一般包含这些图片的 hInstance 已经在 Widnows.inc 中定义为 HINST_COMMCTRL,同样 wBMID 一般是 IDB_STD_SMALL_COLOR,表示使用大图片还是小图片等等。接下来是定义按钮的数据结构,中间定义了各个按钮的命令号,图片号及其他属性,结构如下:

TBBUTTON STRUCT
  iBitmap   DWORD      ?
  idCommand DWORD      ?
  fsState   BYTE       ?
  fsStyle   BYTE       ?
  bReserved BYTE 2 dup(?)
  dwData    DWORD      ?
  iString   DWORD      ?
TBBUTTON ENDS

其中,每个结构定义一个按钮,数据结构中iBitmap 是图片ID,idCommand 是按钮的命令号,这个命令号当你按下按钮的时候会出现在 WM_COMMAND 消息的 wParam 中,你就可以知道哪个按钮被按下了。fsState 是按钮的初始状态,如 TBSTATE_PRESSED 是已经按下的,详细见手册,fsStyle 是风格。
    而建立状态栏的 CreateStatusWindow 的声明如下:

HWND CreateStatusWindow(

    LONG style, 	
    LPCTSTR lpszText, 	
    HWND hwndParent, 	
    UINT wID	
   );

style 是状态栏的风格,lpszText 指向初始化是要显示在状态栏的文本,你可以指向 NULL。hwndParent 是父窗口的句柄。wID 是窗口 ID。

使用工具栏和状态栏的源程序

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	是否包括调试代码
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DEBUG		=	1
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	Programmed by 罗云彬, bigluo@telekbird.com.cn
;	Website: http://asm.yeah.net
;	LuoYunBin's Win32 ASM page (罗云彬的编程乐园)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	版本信息
;	工具栏和状态栏演示程序 Ver 1.0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

		.386
		.model flat, stdcall
		option casemap :none   ; case sensitive

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	Include 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include		windows.inc
include		user32.inc
include		kernel32.inc
include		comctl32.inc
include		comdlg32.inc
include		gdi32.inc

includelib	user32.lib
includelib	kernel32.lib
includelib	comctl32.lib
includelib	comdlg32.lib
includelib	gdi32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	Equ 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

IDI_MAIN	equ		1000		;icon

IDM_MAIN	equ		4000		;menu
IDM_TOOLBAR	equ		4001
IDM_STATUSBAR	equ		4002
IDM_EXIT	equ		4003
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

		.data?

hInstance	dd		?
hWinMain	dd		?
hMenu		dd		?
hIcon		dd		?
hToolbar	dd		?
hStatusbar	dd		?

szBuffer	db	256 dup	(?)

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

		.data

szClassName	db	"Toolbar Template",0
szCaptionMain	db	'工具栏和状态栏演示程序 - 罗云彬',0
dwFlag		dd	F_TOOLBAR or F_STATUSBAR
;********************************************************************
;	标志位定义
F_TOOLBAR	equ	00000001b
F_STATUSBAR	equ	00000010b
stToolbar	TBBUTTON	< STD_FILENEW,1,TBSTATE_ENABLED,TBSTYLE_BUTTON,2 dup(0),-1>
		TBBUTTON	<0,0,TBSTATE_ENABLED,TBSTYLE_SEP,2 dup(0),-1>
		TBBUTTON	< STD_FILEOPEN,2,TBSTATE_ENABLED,TBSTYLE_BUTTON,2 dup(0),-1>
		TBBUTTON	< STD_FILESAVE,3,TBSTATE_ENABLED,TBSTYLE_BUTTON,2 dup(0),-1>
		TBBUTTON	<0,0,TBSTATE_ENABLED,TBSTYLE_SEP,2 dup(0),-1>
		TBBUTTON	< STD_PRINT,4,TBSTATE_ENABLED,TBSTYLE_BUTTON,2 dup(0),-1>
		TBBUTTON	< STD_PRINTPRE,0,TBSTATE_ENABLED,TBSTYLE_SEP,2 dup(0),-1>
NUM_BUTTONS	EQU	7

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

		.code

if		DEBUG
	include		Debug.asm
endif

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	程序开始
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
		call	_WinMain
		invoke	ExitProcess,NULL

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	主窗口程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain	proc
		local	@stWcMain:WNDCLASSEX
		local	@stMsg:MSG

;********************************************************************
;	如果已经在运行,则激活已运行的进程
;********************************************************************
		invoke	FindWindow,offset szClassName,NULL
		.if	eax != NULL
			invoke	ShowWindow,eax,SW_SHOWNORMAL
			invoke	ExitProcess,NULL
		.endif

		invoke	InitCommonControls
		invoke	GetModuleHandle,NULL
		mov	hInstance,eax
		invoke	LoadIcon,hInstance,IDI_MAIN
		mov	hIcon,eax
		invoke	LoadMenu,hInstance,IDM_MAIN
		mov	hMenu,eax
;*************** 注册窗口类 *****************************************
		invoke	LoadCursor,0,IDC_ARROW
		mov	@stWcMain.hCursor,eax
		mov	@stWcMain.cbSize,sizeof WNDCLASSEX
		mov	@stWcMain.hIconSm,0
		mov	@stWcMain.style,CS_HREDRAW or CS_VREDRAW
		mov	@stWcMain.lpfnWndProc,offset WndMainProc
		mov	@stWcMain.cbClsExtra,0
		mov	@stWcMain.cbWndExtra,0
		mov	eax,hInstance
		mov	@stWcMain.hInstance,eax
		mov	@stWcMain.hIcon,0
		mov	@stWcMain.hbrBackground,COLOR_BTNFACE+1
		mov	@stWcMain.lpszClassName,offset szClassName
		mov	@stWcMain.lpszMenuName,0
		invoke	RegisterClassEx,addr @stWcMain
;*************** 建立输出窗口 ***************************************
		invoke	CreateWindowEx,NULL,\	;WS_EX_CLIENTEDGE,\
			offset szClassName,offset szCaptionMain,\
			WS_OVERLAPPEDWINDOW,\	; OR WS_VSCROLL OR WS_HSCROLL,\
			50,50,550,350,\
			NULL,hMenu,hInstance,NULL

		invoke	ShowWindow,hWinMain,SW_SHOWNORMAL
		invoke	UpdateWindow,hWinMain
;*************** 消息循环 *******************************************
		.while	TRUE
			invoke	GetMessage,addr @stMsg,NULL,0,0
			.break	.if eax	== 0
			invoke	TranslateMessage,addr @stMsg
			invoke	DispatchMessage,addr @stMsg
		.endw
		ret

_WinMain	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
WndMainProc	proc	uses ebx edi esi, \
		hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

		mov	eax,uMsg
		.if	eax ==	WM_CREATE
			mov	eax,hWnd
			mov	hWinMain,eax
			call	_Init
;********************************************************************
		.elseif	eax ==	WM_SIZE
			invoke	SendMessage,hStatusbar,uMsg,wParam,lParam
			invoke	SendMessage,hToolbar,uMsg,wParam,lParam
;********************************************************************
		.elseif	eax ==	WM_COMMAND
			mov	eax,wParam
			movzx	eax,ax
			.if	eax ==	IDM_EXIT
				call	_Quit
			.elseif	eax ==	IDM_TOOLBAR
				xor	dwFlag,F_TOOLBAR
				call	_ArrangeWindow
			.elseif	eax ==	IDM_STATUSBAR
				xor	dwFlag,F_STATUSBAR
				call	_ArrangeWindow
			.else
				_Debug	"菜单和工具栏命令","命令ID",eax
			.endif
;********************************************************************
		.elseif	eax ==	WM_CLOSE
			call	_Quit
;********************************************************************
		.else
			invoke	DefWindowProc,hWnd,uMsg,wParam,lParam
			ret
		.endif
;********************************************************************
;	注意:WndProc 处理 Windows 消息后,必须在 Eax 中返回 0
;	但是由 DefWindowProc 处理后的返回值不能改变,否则窗口
;	将无法显示!
;********************************************************************
		xor	eax,eax
		ret

WndMainProc	endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	主窗口控制子程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Init		proc

		invoke	SendMessage,hWinMain,WM_SETICON,ICON_SMALL,hIcon
		invoke	CreateToolbarEx,hWinMain,\
			WS_VISIBLE or WS_CHILD or TBSTYLE_FLAT or WS_BORDER,\
			1,0,HINST_COMMCTRL,IDB_STD_SMALL_COLOR,offset stToolbar,\
			NUM_BUTTONS,0,0,0,0,sizeof TBBUTTON
		mov	hToolbar,eax

		invoke	CreateStatusWindow,WS_CHILD or WS_VISIBLE,NULL,hWinMain,2
		mov	hStatusbar,eax
		call	_ArrangeWindow

		ret

_Init		endp
;********************************************************************
_Quit		proc

		invoke	DestroyWindow,hWinMain
		invoke	PostQuitMessage,NULL
		ret

_Quit		endp
;********************************************************************
_ArrangeWindow	proc
		local	@stRect:RECT
		local	@stRectTemp:RECT
		local	@dwWidth:DWORD

		test	dwFlag,F_TOOLBAR
		.if	ZERO?
			invoke	ShowWindow,hToolbar,SW_HIDE
			invoke	CheckMenuItem,hMenu,IDM_TOOLBAR,MF_UNCHECKED
		.else
			invoke	ShowWindow,hToolbar,SW_SHOW
			invoke	CheckMenuItem,hMenu,IDM_TOOLBAR,MF_CHECKED
		.endif
		test	dwFlag,F_STATUSBAR
		.if	ZERO?
			invoke	ShowWindow,hStatusbar,SW_HIDE
			invoke	CheckMenuItem,hMenu,IDM_STATUSBAR,MF_UNCHECKED
		.else
			invoke	ShowWindow,hStatusbar,SW_SHOW
			invoke	CheckMenuItem,hMenu,IDM_STATUSBAR,MF_CHECKED
		.endif

		ret

_ArrangeWindow	endp
;********************************************************************
		end	start

程序的分析和要点

    在工具栏和状态栏编程中,要注意的就是工具栏和状态栏并不会随父窗口的大小变化自己调整位置和大小,所以要在父窗口的 WM_SIZE 消息中来移动和调整它们,这可以简单的把 WM_SIZE 消息传给它们就行了。不必自己再去计算。

		.elseif	eax ==	WM_SIZE
			invoke	SendMessage,hStatusbar,uMsg,wParam,lParam
			invoke	SendMessage,hToolbar,uMsg,wParam,lParam

另外,工具栏和状态栏也是一种子窗口,所以如果想把它们隐藏或显示的话,可以用标准的 ShowWindow 来处理。





(C) Copyright by LuoYunBin's Win32 ASM Page,http://asm.yeah.net