其他语言

本类阅读TOP10

·基于Solaris 开发环境的整体构思
·使用AutoMake轻松生成Makefile
·BCB数据库图像保存技术
·GNU中的Makefile
·射频芯片nRF401天线设计的分析
·iframe 的自适应高度
·BCB之Socket通信
·软件企业如何实施CMM
·入门系列--OpenGL最简单的入门
·WIN95中日志钩子(JournalRecord Hook)的使用

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
仿制金山毒霸的标题栏

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

仿制金山毒霸的标题栏


  千变一律的界面总是让人觉得缺乏新意,在功能相当的一系列软件中大家肯定偏爱那些界面看起来赏心悦目的,如果我们能够给自己的软件加一个与众不同标题栏是不是也能为我们的软件增色不少呢!下面是我仿照金山毒霸的界面做的一个标题栏,运行效果如下。例子

  

原理

  要定制标题栏,我们可以在 Windows 提供的标题栏上绘制自己所要实现的效果。但因为总的框架在那,再怎么绘制也不过是加几个控件,写一些彩色的字,像上图这样的效果似乎很难实现。在这我采用的方法是:去掉缺省的标题栏,画一个自己的标题栏。

  在定制对话框模板时指定 WS_POPUP 风格就可以得到一个没有标题栏的对话框,也可以在对话框初始化时通过 SetWindowLong 设置窗口风格来去掉标题栏。

  缺省提供的标题栏没了我们就需要自己画一个标题栏。分为两个部分:外表的实现,功能的实现。通过在 Static 控件上加载位图就能够实现标题栏的外表显示,如上图,一共采用了三个 Static 控件来加载标题栏位图、最小化按钮位图、关闭按钮位图。

  功能的实现有:窗口的拖动,关闭按钮的响应,最小化按钮的响应。窗口的拖动我们只需要在鼠标左键按下时判断是否是在我们绘制的标题栏范围内,如果在,就给窗口发送 WM_NCLBUTTONDOWN 消息。按钮的响应有鼠标移到按钮上按钮变亮,鼠标按下时按钮产生按下效果等。首先子类化两个 Static 按钮控件,在其中处理 WM_LBUTTONDOWN、WM_MOUSEMOVE、WM_LBUTTONUP 等消息,根据不同的消息和鼠标是否按下等来加载不同的位图,从而产生按钮加亮、按钮按下等不同效果。

  标题栏画好后如果还继续采用窗口缺省的灰灰的界面势必会影响整体效果,所以我们通过处理 WM_CTLCOLORDLG 消息来改变背景颜色。

例子
.386
.model flat,stdcall
option casemap:none

;****************************************************************************************

include     c:\masm32\include\windows.inc
include     c:\masm32\include\user32.inc
include     c:\masm32\include\kernel32.inc
include     c:\masm32\include\gdi32.inc

includelib  c:\masm32\lib\user32.lib
includelib  c:\masm32\lib\kernel32.lib
includelib  c:\masm32\lib\gdi32.lib

;****************************************************************************************

RGB macro red,green,blue 
        xor eax,eax 
        mov ah,blue 
        shl eax,8 
        mov ah,green 
        mov al,red 
endm
;****************************************************************************************

DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD
CloseBtnProc proto :DWORD,:DWORD,:DWORD,:DWORD
MinBtnProc proto :DWORD,:DWORD,:DWORD,:DWORD

;****************************************************************************************

.data
DlgName      db "DLG_MAIN",0
szCaption    db "仿制金山毒霸的标题栏",0

.data?
hInstance    HINSTANCE ?
hBmp1        dd  ?
hBmp2        dd  ?
hBmp3        dd  ?
hBmp4        dd  ?
hBmp5        dd  ?
hBmp6        dd  ?
hBmp7        dd  ?
hCaption     dd  ?
hClose       dd  ?
hMin         dd  ?
bMouseDown   dd  ?

.const
IDI_MAIN                 equ     900
IDB_BITMAP1              equ     901
IDB_BITMAP2              equ     902
IDB_BITMAP3              equ     903
IDB_BITMAP4              equ     904
IDB_BITMAP5              equ     905
IDB_BITMAP6              equ     906
IDB_BITMAP7              equ     907
IDC_STATIC_CAPTION       equ     2001
IDC_STATIC_MIN           equ     2002
IDC_STATIC_CLOSE         equ     2003

;****************************************************************************************

.code
start:
	invoke GetModuleHandle, NULL
	mov    hInstance,eax
	invoke DialogBoxParam,hInstance,addr DlgName,NULL,addr DlgProc,0
	invoke ExitProcess,eax

;对话框窗口过程**************************************************************************

DlgProc  proc  hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
	local  pt:POINT
	local  rect:RECT
	local  hDC:HDC

	.IF     uMsg==WM_CLOSE
		invoke  EndDialog,hWnd,NULL

	.ELSEIF uMsg==WM_INITDIALOG
		invoke  SendMessage, hWnd, WM_SETTEXT, 0, addr szCaption

		;加载图像
		invoke  LoadBitmap, hInstance, IDB_BITMAP1
		mov     hBmp1, eax
		invoke  LoadBitmap, hInstance, IDB_BITMAP2
		mov     hBmp2, eax
		invoke  LoadBitmap, hInstance, IDB_BITMAP3
		mov     hBmp3, eax
		invoke  LoadBitmap, hInstance, IDB_BITMAP4
		mov     hBmp4, eax
		invoke  LoadBitmap, hInstance, IDB_BITMAP5
		mov     hBmp5, eax
		invoke  LoadBitmap, hInstance, IDB_BITMAP6
		mov     hBmp6, eax
		invoke  LoadBitmap, hInstance, IDB_BITMAP7
		mov     hBmp7, eax

		;子类化“关闭”和“最小化”按钮
		invoke  GetDlgItem, hWnd, IDC_STATIC_CAPTION
		mov     hCaption, eax
		invoke  GetDlgItem, hWnd, IDC_STATIC_CLOSE
		mov     hClose, eax
		invoke  SetWindowLong, hClose, GWL_WNDPROC, addr CloseBtnProc
		invoke  SetWindowLong, hClose, GWL_USERDATA, eax
		invoke  GetDlgItem, hWnd, IDC_STATIC_MIN
		mov     hMin, eax
		invoke  SetWindowLong, hMin, GWL_WNDPROC, addr MinBtnProc
		invoke  SetWindowLong, hMin, GWL_USERDATA, eax
		mov     bMouseDown, FALSE

		;重新设置窗口大小
		invoke  GetClientRect, hWnd, addr rect
		sub     rect.right, 2
		invoke  SetWindowPos, hWnd, 0, 0, 0, rect.right, rect.bottom, SWP_NOZORDER or SWP_NOMOVE

	;画出窗口的边缘线
	.ELSEIF uMsg==WM_PAINT
		invoke  GetDC, hWnd
		mov     hDC, eax
		invoke  GetClientRect, hWnd, addr rect
		sub     rect.right, 1
		sub     rect.bottom, 2
		invoke  MoveToEx, hDC, 0, 30, NULL
		invoke  LineTo, hDC, 0, rect.bottom
		invoke  MoveToEx, hDC, 0, rect.bottom, NULL
		invoke  LineTo, hDC, rect.right, rect.bottom
		invoke  MoveToEx, hDC, rect.right, rect.bottom, NULL
		invoke  LineTo, hDC, rect.right, 29
		mov     eax, FALSE
		ret

	;改变对话框的背景色,为了和标题栏协调起来
	.ELSEIF uMsg==WM_CTLCOLORDLG
		RGB     0F0h, 0F0h, 0F0h
		invoke  CreateSolidBrush, eax
		ret

	;拖动窗口
	.ELSEIF uMsg==WM_LBUTTONDOWN
		invoke  GetCursorPos, addr pt
		invoke  ScreenToClient, hWnd, addr pt
		.IF     pt.y<30 && pt.x<420
			invoke  SendMessage, hWnd, WM_NCLBUTTONDOWN, 2, 0
		.ENDIF

	.ELSE
		mov  eax,FALSE		
		ret
	.ENDIF
	mov  eax,TRUE
	ret
DlgProc endp

;“关闭”按钮窗口过程********************************************************************

CloseBtnProc  proc  hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
	local  pt:POINT

	.IF     uMsg==WM_NCHITTEST
		mov     eax, TRUE
		ret

	.ELSEIF uMsg==WM_LBUTTONDOWN
		invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp4                
		mov     bMouseDown, TRUE                                                    

	.ELSEIF uMsg==WM_MOUSEMOVE
		invoke  GetCursorPos, addr pt
		invoke  WindowFromPoint, pt.x, pt.y
		.IF     eax==hWnd                                                           
			invoke  SetCapture, hWnd                                            
			.IF     bMouseDown                                                  
				invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp4
			.ELSE                                                               
				invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp3
			.ENDIF
		.ELSE                                                                       
			invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp2        
			.IF	!bMouseDown                                                 
				invoke  ReleaseCapture                                      
			.ENDIF
		.ENDIF

	.ELSEIF uMsg==WM_LBUTTONUP
		invoke  GetCursorPos, addr pt
		invoke  WindowFromPoint, pt.x, pt.y
		.IF     eax==hWnd                                                           
			.IF     bMouseDown                                                  
				invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp3
				invoke  GetParent, hWnd
				invoke  SendMessage, eax, WM_CLOSE, 0, 0                    
			.ENDIF
		.ENDIF
		invoke  ReleaseCapture
		mov     bMouseDown, FALSE

	.ELSE
		invoke  GetWindowLong, hWnd, GWL_USERDATA
		invoke  CallWindowProc, eax, hWnd, uMsg, wParam, lParam
		ret
	.ENDIF
	xor     eax,eax
	ret
CloseBtnProc  endp

MinBtnProc  proc  hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
	local  pt:POINT

	.IF     uMsg==WM_NCHITTEST
		mov     eax, TRUE
		ret

	.ELSEIF uMsg==WM_LBUTTONDOWN
		invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp7
		mov     bMouseDown, TRUE

	.ELSEIF uMsg==WM_MOUSEMOVE
		invoke  GetCursorPos, addr pt
		invoke  WindowFromPoint, pt.x, pt.y
		.IF     eax==hWnd
			invoke  SetCapture, hWnd
			.IF     bMouseDown
				invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp7
			.ELSE
				invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp6
			.ENDIF
		.ELSE
			invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp5
			.IF	!bMouseDown
				invoke  ReleaseCapture
			.ENDIF
		.ENDIF

	.ELSEIF uMsg==WM_LBUTTONUP
		invoke  GetCursorPos, addr pt
		invoke  WindowFromPoint, pt.x, pt.y
		.IF     eax==hWnd
			.IF     bMouseDown
				invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp6
				invoke  GetParent, hWnd
				invoke  ShowWindow, eax, SW_MINIMIZE
			.ENDIF
		.ENDIF
		invoke  ReleaseCapture
		mov     bMouseDown, FALSE

	.ELSE
		invoke  GetWindowLong, hWnd, GWL_USERDATA
		invoke  CallWindowProc, eax, hWnd, uMsg, wParam, lParam
		ret
	.ENDIF
	xor     eax,eax
	ret
MinBtnProc  endp

end start
分析

invoke GetDlgItem, hWnd, IDC_STATIC_CAPTION
mov hCaption, eax
invoke GetDlgItem, hWnd, IDC_STATIC_CLOSE
mov hClose, eax
invoke SetWindowLong, hClose, GWL_WNDPROC, addr CloseBtnProc
invoke SetWindowLong, hClose, GWL_USERDATA, eax
invoke GetDlgItem, hWnd, IDC_STATIC_MIN
mov hMin, eax
invoke SetWindowLong, hMin, GWL_WNDPROC, addr MinBtnProc
invoke SetWindowLong, hMin, GWL_USERDATA, eax
mov bMouseDown, FALSE


首先取得“关闭”按钮和“最小化”按钮的句柄,然后分别子类化以截获消息处理消息。

invoke GetClientRect, hWnd, addr rect
sub rect.right, 2
invoke SetWindowPos, hWnd, 0, 0, 0, rect.right, rect.bottom, SWP_NOZORDER or SWP_NOMOVE


改变窗口的大小,主要是为了匹配标题栏的宽度。

.ELSEIF uMsg==WM_PAINT
    invoke GetDC, hWnd
    mov hDC, eax
    invoke GetClientRect, hWnd, addr rect
    sub rect.right, 1
    sub rect.bottom, 2
    invoke MoveToEx, hDC, 0, 30, NULL
    invoke LineTo, hDC, 0, rect.bottom
    invoke MoveToEx, hDC, 0, rect.bottom, NULL
    invoke LineTo, hDC, rect.right, rect.bottom
    invoke MoveToEx, hDC, rect.right, rect.bottom, NULL
    invoke LineTo, hDC, rect.right, 29
    mov eax, FALSE
    ret


处理 WM_PAINT 消息,分别在窗口的左边、下边和右边画上边界线,这样一来有一种平面效果正好匹配我们的标题栏。

.ELSEIF uMsg==WM_LBUTTONDOWN
    invoke GetCursorPos, addr pt
    invoke ScreenToClient, hWnd, addr pt
    .IF pt.y<30 && pt.x<420
        invoke SendMessage, hWnd, WM_NCLBUTTONDOWN, 2, 0
    .ENDIF


在鼠标按下时判断是不是在我们绘制的标题栏范围内,在这除去了右边“关闭”按钮和“最小化”按钮占去的位置。

.IF uMsg==WM_NCHITTEST
    mov eax, TRUE
    ret


返回 TRUE 从而实现鼠标消息的截获。
.ELSEIF uMsg==WM_LBUTTONDOWN
	invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp4                
	mov     bMouseDown, TRUE                                                    

.ELSEIF uMsg==WM_MOUSEMOVE
	invoke  GetCursorPos, addr pt
	invoke  WindowFromPoint, pt.x, pt.y
	.IF     eax==hWnd                                                           
		invoke  SetCapture, hWnd                                            
		.IF     bMouseDown                                                  
			invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp4
		.ELSE                                                               
			invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp3
		.ENDIF
	.ELSE                                                                       
		invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp2        
		.IF	!bMouseDown                                                 
			invoke  ReleaseCapture                                      
		.ENDIF
	.ENDIF

.ELSEIF uMsg==WM_LBUTTONUP
	invoke  GetCursorPos, addr pt
	invoke  WindowFromPoint, pt.x, pt.y
	.IF     eax==hWnd                                                           
		.IF     bMouseDown                                                  
			invoke  SendMessage, hWnd, STM_SETIMAGE, IMAGE_BITMAP, hBmp3
			invoke  GetParent, hWnd
			invoke  SendMessage, eax, WM_CLOSE, 0, 0                    
		.ENDIF
	.ENDIF
	invoke  ReleaseCapture
	mov     bMouseDown, FALSE
在鼠标按下时加载按下效果的位图,并设置标志位标志鼠标处在按下状态。在 WM_MOUSEMOVE 消息中先取得鼠标位置,判断是否在按钮上,如果在按钮上,则锁定鼠标消息,然后根据鼠标是否正按下来加载按钮按下的位图或按钮加亮的位图。如果不在按钮上,则加载正常的位图,然后判断鼠标是否正处在按下的状态,如果不是,则说明只是鼠标经过按钮上而已,可以释放鼠标;如果正处在按下状态,则不能释放鼠标,因为如果这时候释放鼠标,当鼠标移出按钮然后弹起时我们就接收不到消息,所以要留到 WM_LBUTTONUP 消息中释放鼠标。在 WM_LBUTTONUP 消息中也是先取得鼠标位置,判断是否在按钮上,如果在,再判断鼠标是否处在按下状态,接着就可以发送消息实现按钮的功能。最后释放鼠标,设置标志位标志鼠标已经弹起。

CopyRight (C) 2001-2002 一块三毛钱



相关文章

相关软件