⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 见招拆招windows程序设计(六) .txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 5 页
字号:
见招拆招Windows程序设计(六)  
相关的例子:下载>>>  作者:Zoologist 于2008-3-16上传   

--------------------------------------------------------------------------------
鼠标  

         鼠标是有一个或多个键的定位设备。虽然也可以使用诸如触摸画面和光笔之类的输入设备,但是只有鼠标以及常用在笔记本上的轨迹球等才是渗透了PC市场的唯一输入设备。

情况并非总是如此。当然,Windows的早期开发人员认为他们不应该要求使用者为了执行其产品而必须买只鼠标。因此,他们将鼠标作为一种选择性的附加设备,而为Windows中的所有操作以及applet提供一种键盘接口(例如,查看Windows计算器程序的在线说明信息,可以看到每个按钮都提供了一个同等功效的键盘操作方式)。第三方软件开发人员使用键盘接口来提供与鼠标操作相同的功能,这本书以前的版本也是这么做的。

理论上来说,现在的Windows需要鼠标。至少,一些消息框是这样讲的。当然,您也可以拔下鼠标,而且Windows仍然可以执行良好(提醒一句,如果你使用的不是USB鼠标,最好不要尝试将鼠标再插回去,这样做可能会烧毁你的主板哦)。试图不用鼠标来使用Windows就像用脚趾来弹钢琴一样(至少在最初的一段时间里是这样),但您依然可以这样做。正因为如此,我还是喜欢为鼠标功能提供键盘操作。打字员尤其喜欢让他们的手保持在键盘上,并且我认为每个人都有在杂乱的桌上找不到鼠标,或者鼠标移动不灵敏的经验。使用键盘通常不需要花费更多的精力和努力,并且为喜欢使用键盘的人提供更多的功能。或者说大量使用键盘的通常给人很牛X的感觉。

我们通常认为,键盘便于输入和操作文字数据,而鼠标则便于画图和操作图形对象。实际上,本章大多数的范例程序都画了一些图形,并且用到了我们前面所学到的知识。

鼠标基础


Windows 98/2000/XP能支持单键、双键或者三键鼠标,也可以使用摇杆或者光笔来仿真单键鼠标。早期,由于许多使用者都有单键鼠标,所以Windows应用程序总是避免使用双键或三键鼠标。不过,由于双键鼠标已经成为事实上的标准,因此不使用第二个键的传统已经不再合理了。当然,第二个鼠标按键是用于启动一个「快捷菜单」,亦即出现在普通菜单列之外的窗口中菜单,或者用于特殊的拖曳操作(拖曳将在后面加以解释)。然而,程序不能依赖双键鼠标。(题外话,大多数的宣传都在说Windows操作系统是“抄袭”自Apple。不过,在鼠标方面,Apple的机器却整整花费了20年才考虑给他们的用户提供双键鼠标。以至于很多Apple的用户不得不在购买机器后马上购买一个第三方鼠标。)

理论上,您可以用我们的老朋友GetSystemMetrics函数来确认鼠标是否存在:

fMouse = GetSystemMetrics (SM_MOUSEPRESENT) ;
        
如果已经安装了鼠标,fMouse将传回TRUE(非0);如果没有安装,则传回0。然而,在Windows 98中,不论鼠标是否安装,此函数都将传回TRUE 。在Microsoft Windows NT中,它可以正常工作。

要确定所安装鼠标其上按键的个数,可使用

cButtons = GetSystemMetrics (SM_CMOUSEBUTTONS) ;
        
如果没有安装鼠标,那么函数将传回0。然而,在Windows 98下,如果没有安装鼠标,此函数将传回2。

习惯用左手的使用者可以使用Windows的「控制面板」来切换鼠标按键。虽然应用程序可以通过在GetSystemMetrics中使用SM_SWAPBUTTON参数来确定是否进行了这种切换,但通常没有这个必要。由食指触发的键被认为是左键,即使事实上是位于鼠标的右边。不过,在一个教育训练程序中,您可能想在屏幕上画一个鼠标,在这种情况下,您可能想知道鼠标按键是否被切换过了。

您可以在「控制面板」中设定鼠标的其它参数,例如双击速度。从Windows应用程序,通过使用SystemParametersInfo函数可以设定或获得此项信息。

一些简单的定义


当Windows使用者移动鼠标时,Windows在显示器上移动一个称为「鼠标光标」的小位图。鼠标光标有一个指向显示器上精确位置的单图素「热点」。当我提到鼠标光标在屏幕上的位置时,指的是热点的位置。

Windows支持几种预先定义的鼠标光标,程序可以使用这些光标。最常见的是称为IDC_ARROW的斜箭头(在WINUSER.H中定义)。热点在箭头的顶端。IDC_CROSS光标(在后面的BLOKOUT程序中有用到)的热点在十字交叉线的中心。IDC_WAIT光标是一个沙漏,通常用于指示程序正在执行。程序写作者也可以设计自己的光标。我们将在后面学习设计方法。在定义窗口类别结构时指定特定窗口的内定光标,例如:

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
        
下面是一些描述鼠标按键动作的术语: 

Clicking按下并放开一个鼠标按键。
  
Double-clicking快速按下并放开鼠标按键两次。
  
Dragging按住鼠标按键并移动鼠标。
  
对三键鼠标来说,三个键分别称为左键、中键、右键。在Windows表头文件中定义的与鼠标有关的标识符使用缩写LBUTTON、MBUTTON和RBUTTON。双键鼠标只有左键与右键,单键鼠标只有一个左键。

鼠标(Mouse)的复数


现在,为了展现我的勇气,我将面对输入设备最难辩的争论话题:什么是「mouse」的复数。虽然每个人都知道多只啮齿动物称为mice,似乎没有人对该如何称呼多个输入设备有最后的答案。不管「mice」或「mouse」听起来都不对劲。我惯常参考的《American Heritage Dictionary of the English Language》第三版则只字未提。

《Wired style:Principles of English Usage in the Digital Age》(HardWired, 1996)指出「mouse」比较好,以避免与啮齿动物搞混。在1964发明鼠标的Doug Engelbart对此争议也帮不上忙。我曾经问过他mouse的复数是什么,他说我不知道。

最后,高权威的Microsoft Manual of Style for Technical Publications告诉我们「避免使用复数mice。假如你必须提到多只mouse,使用mouse devices」。这听起来像是在逃避问题,但当一切听起来都不对劲时,它确实是个明智的忠告了。事实上,大部分需要mouse复数的句子都能重新修改来避开。例如,试着说"People use the almost as much as keyboard",而不是"Pople use mice almost as much as keyboards"。

显示区域鼠标消息


在前一期中您已经看到,Windows只把键盘消息发送给拥有输入焦点的窗口。鼠标消息与此不同:只要鼠标跨越窗口或者在某窗口中按下鼠标按键,那么窗口消息处理程序就会收到鼠标消息,而不管该窗口是否活动或者是否拥有输入焦点。Windows为鼠标定义了21种消息,不过,其中有11个消息和显示区域无关(下面称之为「非显示区域」消息),Windows程序经常忽略这些消息。

当鼠标移过窗口的显示区域时,窗口消息处理程序收到WM_MOUSEMOVE消息。当在窗口的显示区域中按下或者释放一个鼠标按键时,窗口消息处理程序会接收到下面这些消息:

表7-1
 


 按下
 释放
 按下(双键)
 
左 WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDBLCLK 
中 WM_MBUTTONDOWN WM_MBUTTONUP WM_MBUTTONDBLCLK 
右 WM_RBUTTONDOWN WM_RBUTTONUP WM_RBUTTONDBLCLK 

只有对三键鼠标,窗口消息处理程序才会收到MBUTTON消息;只有对双键或者三键鼠标,才会接收到RBUTTON消息。只有当定义的窗口类别能接收DBLCLK(双击)消息,窗口消息处理程序才能接收到这些消息(请参见本期「双击鼠标按键」)。

对于所有这些消息来说,其lParam值均含有鼠标的位置:低字组为x坐标,高字组为y坐标,这两个坐标是相对于窗口显示区域左上角的位置。您可以用LOWORD和HIWORD宏来提取这些值:

x = LOWORD (lParam) ;
        
y = HIWORD (lParam) ;
        
wParam的值指示鼠标按键以及Shift和Ctrl键的状态。您可以使用表头文件WINUSER.H中定义的位屏蔽来测试wParam。MK前缀代表「鼠标按键」。

MK_LBUTTON 按下左键 
MK_MBUTTON 按下中键 
MK_RBUTTON 按下右键 
MK_SHIFT 按下Shift键 
MK_CONTROL 按下Ctrl键 

例如,如果收到了WM_LBUTTONDOWN消息,而且值

wparam & MK_SHIFT
        
是TRUE(非0),您就知道当左键按下时也按下了Shift键。

当您把鼠标移过窗口的显示区域时,Windows并不为鼠标的每个可能的图素位置都产生一个WM_MOUSEMOVE消息。您的程序接收到WM_MOUSEMOVE消息的次数,依赖于鼠标硬件,以及您的窗口消息处理程序在处理鼠标移动消息时的速度。换句话说,Windows不能用未处理的WM_MOUSEMOVE消息来填入消息队列。当您执行下面将描述的CONNECT程序时,您将会更了解WM_MOUSEMOVE消息处理的速率。

如果您在非活动窗口的显示区域中按下鼠标左键,Windows将把活动窗口改为在其中按下鼠标按键的窗口,然后把WM_LBUTTONDOWN消息送到该窗口消息处理程序。当窗口消息处理程序得到WM_LBUTTONDOWN消息时,您的程序就可以安全地假定该窗口是活动化的了。不过,您的窗口消息处理程序可能在未接收到WM_LBUTTONDOWN消息的情况下先接收到了WM_LBUTTONUP的消息。如果在一个窗口中按下鼠标按键,然后移动到使用者窗口释放它,就会出现这种情况。类似的情况,当鼠标按键在另一个窗口中被释放时,窗口消息处理程序只能接收到WM_LBUTTONDOWN消息,而没有相应的WM_LBUTTONUP消息。

这些规则有两个例外: 

窗口消息处理程序可以「拦截鼠标」并且连续地接收鼠标消息,即使此时鼠标在该窗口显示区域之外。您将在本章的后面学习如何拦截鼠标。
  
如果正在显示一个系统模态消息框或者系统模态对话框,那么其它程序就不能接收鼠标消息。当系统模态消息框或者对话框活动时,禁止切换到其它窗口或者程序。一个显示系统模态消息框的例子,是当您关闭Windows时。
  
简单的鼠标处理:一个例子


程序7-1中所示的CONNECT程序能作一些简单的鼠标处理,使您对Windows如何向您的程序发送鼠标消息有一些体会。


程序7-1 CONNECT 

        
CONNECT.ASM
        
;MASMPlus 代码模板 - 普通的 Windows 程序代码

.386
.Model Flat, StdCall
Option Casemap :None

Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
Include libc.inc

includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
IncludeLib msvcrt.lib
include macro.asm
	
	WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
	WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
	
MAXPOINTS equ	1000

.DATA
	szAppName	DB		"Connect",0
.DATA?
	hInstance	DD		?
	pt 			POINT MAXPOINTS DUP (<?>)
	iCount		DD		?
	szBuffer		db		100 dup (?)

.CODE

START:   ;从这里开始执行
	invoke   GetModuleHandle,NULL
	mov 		hInstance,eax
	invoke   WinMain,hInstance,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,NULL,IDI_APPLICATION
	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
					CTXT("Connect"), ;window caption
					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
					hInstance,	;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,message:DWORD,wParam :DWORD,lParam :DWORD
	LOCAL hdc 				:HDC
   LOCAL i, j			   :DWORD
	LOCAL ps  				:PAINTSTRUCT 

	.if message == WM_LBUTTONDOWN
		 xor			eax,eax
		 mov			iCount,eax
       invoke     InvalidateRect,hwnd, NULL, TRUE
       ret
   .elseif message == WM_MOUSEMOVE  
      	mov	eax,wParam
      	test	eax,MK_LBUTTON
      	jz		@f
      	and	eax,iCount
      	cmp	eax,1000
      	jae	@f
      	mov	ebx,lParam
      	lea	esi,pt
      	mov	eax,iCount
      	shl	eax,3	;iCount * 8
      	add	esi,eax
      	
      	push	ebx	; pt[iCount  ].x = LOWORD (lParam)
      	shl	ebx,16
      	shr	ebx,16
      	mov   [esi],ebx
      	pop	ebx
      	
      	shr	ebx,16	; pt[iCount++].y = HIWORD (lParam) 
      	add	esi,4
      	mov [esi],ebx

			inc	iCount
         invoke GetDC,hwnd
         mov   hdc,eax
         mov	ebx,lParam
         mov	eax,ebx
         shr	eax,16
         
         push	0
         and	eax,0FFFFh	;HIWORD(lParam)
         push	eax
         and	ebx,0FFFFh	;LOWORD(lParam)
         push	ebx
         push	hdc
         call SetPixel
                                   
         invoke ReleaseDC,hwnd, hdc

		@@:	
		
			ret    	
		.elseif message == WM_LBUTTONUP
			invoke InvalidateRect,hwnd, NULL, FALSE
         ret	
		.elseif message == WM_PAINT
		invoke	BeginPaint,hwnd,addr ps
		mov		hdc,eax

		invoke	LoadCursor,NULL,IDC_WAIT
		invoke	SetCursor,eax
      invoke   ShowCursor,TRUE
       
		xor		eax,eax
		mov		i,eax
	Loopi:
		mov		eax,i
		inc		eax
		mov		j,eax
	  Loopj:
	  	
	  	lea		esi,pt
	  	mov		eax,i
	  	shl		eax,3
	  	add		esi,eax
	  	mov		eax,NULL
	  	push		eax
	  	mov		eax,[esi+4] ;pt[i].y
	  	push		eax
	  	mov		eax,[esi]	;pt[i].x
	  	push		eax
	  	push		hdc
	  	call		MoveToEx
	  	lea		esi,pt
	  	mov		eax,j
	  	shl		eax,3
	  	add		esi,eax	  	
	  	mov		eax,[esi+4]	;pt[j].y
	  	push		eax
	  	mov		eax,[esi]	;pt[j].x
	  	push		eax
	  	push		hdc
	  	call		LineTo
	  	inc		j
	  	mov		eax,j
	  	cmp		eax,iCount 
	  	jb			Loopj
      ;invoke	wsprintf,addr szBuffer,CTEXT("oo") ,NULL
	;invoke	MessageBox,hwnd,addr szBuffer,NULL,NULL	  	
		inc		i
	   mov		eax,i
	   inc		eax
	   cmp		eax,iCount
	   jb			Loopi
		
      invoke   ShowCursor,FALSE

		invoke	LoadCursor,NULL,IDC_ARROW
		invoke	SetCursor,eax
      invoke   ShowCursor,TRUE
               
      invoke	EndPaint,hwnd, addr ps
        
      ret
	.elseif message == WM_DESTROY
		invoke PostQuitMessage,NULL		
	.endif
UseDefWindowProc:
	invoke DefWindowProc,hwnd, message, wParam, lParam
	ret
WndProc endp

END START

        
CONNECT处理三个鼠标消息: 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -