仿制金山毒霸的标题栏

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

  

原理

  要定制标题栏,我们可以在 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 一块三毛钱

本文地址:http://com.8s8s.com/it/it29546.htm