📄 见招拆招《windows程序设计》(九) .txt
字号:
见招拆招《Windows程序设计》(九)
相关的例子:下载>>> 作者:Zoologist 于2008-7-19上传
--------------------------------------------------------------------------------
菜单及其它资源
--------------------------------------------------------------------------------
大多数Windows程序都包含一个自订的图标,Windows将该图标显示在应用程序窗口标题列的左上角。当程序显示在屏幕底部的任务栏,显示在Windows Explorer中,或者作为快捷方式显示在桌面上时,Windows也显示该程序的图标。有些程序--比如很多类似于画板一类的图形绘制工具--也使用自订鼠标光标来表示程序的不同操作。还有许多Windows程序使用菜单和对话框。菜单、对话框加上滚动条,这是标准Windows使用者接口。
图标、光标、菜单和对话框都是相互关联的,它们是Windows的全部资源型态。资源即数据,它们被储存在程序的.EXE文件中,但是它们并非驻留在程序的数据区域中。也就是说,资源不能从程序源程序中定义的变量直接存取,Windows提供函数直接或间接地把它们加载内存以备使用。我们已经遇到了两个这样的函数,即LoadIcon和LoadCursor,它们出现在范例程序,定义窗口类别结构的内容。它们从Windows中加载二进制图标和光标映象,并传回该图标或光标的句柄。在本期中,我们先建立自己的图标,它会从程序自己的.EXE文件中载入。
在本书中,我们将讨论这些资源:
图示
光标
字符串
自订资源
菜单
键盘快捷键
对话框
位图
前六个资源在本期讨论,对话框和位图将在后面几期中讨论。
图标、光标、字符串和自订资源
使用资源的好处之一,在于程序的许多组件能够连结编译进程序的.EXE文件中。如果没有资源这一个概念,如图标图像之类的二进制文件可能会存放在单独的文件中,.EXE会把它读入内存中使用。或者图标不得不在程序中以字节数组的形式定义(这样就无法看到实际的图标图像了)。作为资源,图标储存在开发者计算机上可单独编辑的文件中,但在编译程序中被连结编译进.EXE文件中。
从简单的角度理解,我们需要编写一个 *.rc 文件,是文本文件格式,里面描述我们要使用什么文件或者菜单格式等等,通过编译后生成 *.res文件,这是二进制格式的文件,我们在Win32汇编语言中直接使用了。我们在 rc 文件中给资源编号,然后在程序中说“我要使用xx号资源”,系统就会自动将它读取出来供你使用。
将图标添加到程序
MasmPlus 处理资源非常简单。比如,我们想更换生成 exe 的图标。
程序10-1 ICONDEMO
ICONDEMO.ASM
;MASMPlus 代码模板 - 普通的 Windows 程序代码
.386
.Model Flat, StdCall
Option Casemap :None
Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
include macro.asm
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
ICO_MAIN equ 1000h
IDI_ICON equ 101
.DATA
szAppName db "IconDemo",0
.DATA?
hIcon HICON ?
cxIcon DD ?
cyIcon DD ?
cxClient DD ?
cyClient DD ?
.CODE
START:
invoke GetModuleHandle,NULL
invoke WinMain,eax,NULL,NULL,SW_SHOWDEFAULT
invoke ExitProcess,0
WinMain proc hInst:DWORD,hPrevInst:DWORD,CmdLine:DWORD,iCmdShow:DWORD
LOCAL wndclass :WNDCLASSEX
LOCAL msg :MSG
local hWnd :HWND
mov wndclass.cbSize,sizeof WNDCLASSEX
mov wndclass.style,CS_HREDRAW or CS_VREDRAW
mov wndclass.lpfnWndProc,offset WndProc
mov wndclass.cbClsExtra,0
mov wndclass.cbWndExtra,0
push hInst
pop wndclass.hInstance
invoke LoadIcon,hInst,IDI_ICON
mov wndclass.hIcon,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wndclass.hCursor,eax
invoke GetStockObject,WHITE_BRUSH
mov wndclass.hbrBackground,EAX
mov wndclass.lpszMenuName,NULL
mov wndclass.lpszClassName,offset szAppName
mov wndclass.hIconSm,0
invoke RegisterClassEx, ADDR wndclass
.if (EAX==0)
invoke MessageBox,NULL,CTXT("This program requires Windows NT!"),addr szAppName,MB_ICONERROR
ret
.endif
invoke CreateWindowEx,
NULL,
ADDR szAppName, ;window class name
ADDR szAppName,
WS_OVERLAPPEDWINDOW, ;window style
CW_USEDEFAULT, ;initial x position
CW_USEDEFAULT, ;initial y position
CW_USEDEFAULT, ;initial x size
CW_USEDEFAULT, ;initial y size
NULL, ;parent window handle
NULL, ;window menu handle
hInst, ;program instance handle
NULL ;creation parameters
mov hWnd,eax
invoke ShowWindow,hWnd,iCmdShow
invoke UpdateWindow,hWnd
StartLoop:
invoke GetMessage,ADDR msg,NULL,0,0
cmp eax, 0
je ExitLoop
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
jmp StartLoop
ExitLoop:
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hwnd:DWORD,uMsg:DWORD,wParam :DWORD,lParam :DWORD
LOCAL hdc:HDC
LOCAL hInstance:HINSTANCE
LOCAL ps:PAINTSTRUCT
LOCAL x, y:DWORD
.if uMsg==WM_CREATE
mov esi,lParam
mov eax,[esi+4]
mov hInstance,eax
invoke LoadIcon,hInstance,IDI_ICON
mov hIcon,eax
invoke GetSystemMetrics,SM_CXICON
mov cxIcon,eax
invoke GetSystemMetrics,SM_CYICON
mov cyIcon,eax
xor eax,eax
ret
.elseif uMsg == WM_SIZE
mov eax,lParam
and eax,0FFFFh
mov cxClient,eax
mov eax,lParam
shr eax,16
mov cyClient,eax
xor eax,eax
ret
.elseif uMsg == WM_PAINT
invoke BeginPaint,hwnd, addr ps
mov hdc,eax
mov y,0
LoopY:
mov x,0
LoopX:
invoke DrawIcon,hdc,x,y,hIcon
mov eax,cxIcon
add x,eax
mov eax,x
cmp eax,cxClient
jl LoopX
mov eax,cyIcon
add y,eax
mov eax,y
cmp eax,cyClient
jl LoopY
invoke EndPaint,hwnd, addr ps
xor eax,eax
ret
.elseif uMsg == WM_DESTROY
invoke PostQuitMessage,NULL
xor eax,eax
ret
.endif
invoke DefWindowProc,hwnd,uMsg,wParam,lParam
ret
WndProc endp
END START
如果您马上试着编译该程序,运行结果同普通的程序别无二致。这是因为我们还没有定义好程序要的图标资源。
这里推荐Aogo裁剪出来的,VC版的资源编辑器。可以用如下的方法建立一个资源文件:从「文件」菜单中选择「新建」,选择「文件」页面标签,单击「资源脚本」,在「文件名」栏中键入「ICONDEMO」,单击OK。之后,资源编辑器就会建立会建立两个文本文件:CONDEMO.RC(资源描述档)和RESOURCE.H。对于我们来说,只需要前者。
资源描述档是文本文件。它包括这些资源的可用文字形式表达的描述,例如菜单和对话框。资源描述文件也包括对非文字资源的二进制档案的引用,例如图标和自订的鼠标光标。
对于上面这个程序,您可以直接使用编辑好的图标文件,也可以尝试着手动在资源编辑器中创建一个新图标。如果你用Windows XP的图片和传真查看器直接查看这个图标的话,你会发现放大之后看到的图片似乎和“原始图片”不一样。这是因为ICONDEMO.ICO实际上包含了2个ICON。
我们在文件的开头定义了 IDI_ICON equ 101,在程序中用如下方法使用:
invoke LoadIcon,hInst,IDI_ICON
mov wndclass.hIcon,eax
面的几期中,是这样写的:
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
之所以改变叙述,是因为以前我们为应用程序使用的是标准的图示,而这里我们的目的是使用自订图示。
现在呈现的是一个空白的32×32图素的图示,您可以在其中填入颜色。您会看到带有一组绘图工具和可用颜色的浮动工具列。注意颜色工具列中包括两个与颜色无关的选项,这两种颜色选项有时被称为「屏幕颜色」跟「反屏幕颜色」。当一个图素在着色时选择了「屏幕颜色」时,它实际上是透明的。不管图标在什么表面上显示,图示未着色的部分会显示出底色。这样我们就可以建立非矩形的图示。
双击围绕图标的区域,会出现「Icon Properties」对话框,该对话框使您能够更改图标的ID和文件名称。Developer Studio可能已经将ID设定为IDI_ICON1,将它改为IDI_ICON,这样ICONDEMO就可以引用图标(前缀IDI代表「图标的ID」)。同样地,将文件名改为ICONDEMO.ICO。
现在选择一种有特色的颜色(如红色)并在图示上画一个大的B(代表BIG),请注意不必像图10-1那么整齐。
图10-1 显示在Developer Studio中的标准(32×32)ICONDEMO文件
此时程序应该能够编译并执行得很好了。Developer Studio将在ICONDEMO.RC资源描述档中划一条横线,表示下面是带有标识符(IDI_ICON)的图示文件(ICONDEMO.ICO)。RESOURCE.H表头文件中会包含IDI_ICON标识符的定义。
编译过程中,我们会使用RC.EXE编译资源。文字资源描述文件被转化为二进制形式,也就是具有扩展名.RES的文件。然后,该已编译的资源文件随同.OBJ和.LIB文件一起在LINK步骤中被指定连结。这就是资源被添加到最后产生出来的.EXE文件中的方式。
当您执行ICONDEMO时,程序图标显示在标题列的左上角和工作列中。如果您将程序添加到「开始」菜单中,或在桌面上放置快捷方式,您也会在那儿看到该图示。
ICONDEMO也在显示区域水平和垂直地重复显示该图示。程序使用叙述
hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON)) ;
取得图示的句柄。使用叙述
cxIcon = GetSystemMetrics (SM_CXICON) ;
cyIcon = GetSystemMetrics (SM_CYICON) ;
取得图示的大小。然后,程序通过多次呼叫
DrawIcon (hdc, x, y, hIcon) ;
显示图标,其中x和y是被显示图示其左上角的坐标。
在目前使用的大多数显卡上,带有SM_CXICON和SM_CYICON索引的GetSystemMetrics会回报图示的大小为32×32图素。这是我们在资源编辑器中建立的图示大小,它也是图示出现在桌面上和显示在ICONDEMO程序显示区域的大小。然而,这个大小并非显示在程序的标题列或工作栏中的图示大小。小图示的大小可以由带有SM_CXSMSIZE和SM_CYSMSIZE索引的GetSystemMetrics获得(第一个SM表示「system metrics(系统度量)」,被包含的SM表示「small(小)」)。对于目前使用的大多数显示卡来说,小图示的大小为16×16图素。
这会产生问题。当Windows将32×32的图示缩小为16×16的图示时,必需减少图素的行和列。这样,对于某些比较复杂的图示,就会失真。因此,我们应该为那些图像缩小就会变形的图示建立特殊的16×16图素的图示。在Developer Studio中图标图像的上面是标识为「Device」的下拉式清单方块,在它的右边有一个按钮,按下该按钮会弹出「New Icon Image」对话框,此时选择「Small(16×16)」。现在您可以画另一个图示。如图10-2所示,画一个「S」(表示「小」)。
图10-2 在Developer Studio中显示的小(16×16)ICONDEMO文件
在该程序中您不必做任何事情。第二个图标图像被储存在相同的ICONDEMO.ICO文件中,并以相同的IDI_ICON标识符引用。在适当的时候,Windows会自动使用该较小的图示,例如在标题列或工作列中。当在桌面上显示快捷方式,以及程序呼叫DrawIcon装饰显示区域时,Windows会使用大图示。
在掌握这些知识之后,让我们看一看使用图示的详细情况。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -