亚洲免费乱码视频,日韩 欧美 国产 动漫 一区,97在线观看免费视频播国产,中文字幕亚洲图片

      1. <legend id="ppnor"></legend>

      2. 
        
        <sup id="ppnor"><input id="ppnor"></input></sup>
        <s id="ppnor"></s>

        三級(jí)PC輔導(dǎo):超類化

        字號(hào):

        在這一講我們將學(xué)習(xí)什么是超類化以及它有什么作用;同時(shí)你還會(huì)學(xué)到怎樣在自己的窗口中用Tab鍵在控件中切換這一技巧。
            理論:
            在你的程序生涯中你肯定遇到過(guò)這樣的情況,你需要一系列的控件,但它們之間卻只有一點(diǎn)點(diǎn)的不同。例如,你可能需要10個(gè)只接受數(shù)字的 Edit 控件,當(dāng)然你可以通過(guò)多種方法來(lái)達(dá)到這個(gè)目的。
            創(chuàng)建自己的類并用它實(shí)例化為那些控件
            創(chuàng)建那些 Edit 控件并把它們?nèi)孔宇惢?BR>    超類化Edit 控件
            第一種方法太乏味了,因?yàn)槟惚仨氉约簩?shí)現(xiàn)Edit 控件的每個(gè)功能,但這項(xiàng)工作不是輕松就能完成的。第二種方法好于第一種,但仍然要做許多工作,子類化幾個(gè)Edit 控件還可以接受,但若要子類化十幾二十個(gè),這項(xiàng)工作簡(jiǎn)直就是一場(chǎng)惡夢(mèng)。在這種情況下就應(yīng)該使用超類化這個(gè)技巧,它是  用于控制某一個(gè)特定窗口類的特殊方法。通過(guò)這種控制就可以修改窗口類的特性使之符合你的要求,然后再創(chuàng)建那一堆控件就可以了。
            超類化有如下幾個(gè)步驟:
            通過(guò)調(diào)用 GetClassInfoEx 來(lái)獲得想要進(jìn)行超類化操作的窗口類的信息。函數(shù)GetClassInfoEx 需要一個(gè)指向 WNDCLASSEX 結(jié)構(gòu)的指針,用于當(dāng)成功返回時(shí)填入窗口類的信息。
            按需要修改 WNDCLASSEX 結(jié)構(gòu)的成員,其中有兩個(gè)成員必須修改:
            hInstance 存放程序的實(shí)例句柄
            lpszClassName 指向一個(gè)新類名的指針
            不必修改成員 lpfnWndProc,但大多數(shù)情況下還是需要的。但要記住如果要使用函數(shù) CallWindowProc 調(diào)用老窗口的過(guò)程,那就必須保存成員 lpfnWndProc 的原值。
            注冊(cè)修改完的 WNDCLASSEX 結(jié)構(gòu),得到一個(gè)具有舊窗口類某些特性的新窗口類。
            用新窗口類創(chuàng)建窗口
            如果要?jiǎng)?chuàng)建具有相同特性的多個(gè)控件,超類化就比子類化要好。
            舉例:
            .386
            .model flat,stdcall
            option casemap:none
            include \masm32\include\windows.inc
            include \masm32\include\user32.inc
            include \masm32\include\kernel32.inc
            includelib \masm32\lib\user32.lib
            includelib \masm32\lib\kernel32.lib
            WM_SUPERCLASS equ WM_USER+5
            WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
            EditWndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
            .data
            ClassName db "SuperclassWinClass",0
            AppName db "Superclassing Demo",0
            EditClass db "EDIT",0
            OurClass db "SUPEREDITCLASS",0
            Message db "You pressed the Enter key in the text box!",0
            .data?
            hInstance dd ?
            hwndEdit dd 6 dup(?) ;存放6個(gè)窗口句柄的數(shù)組
            OldWndProc dd ? ;原來(lái)的窗口過(guò)程
            .code
            start:
            invoke GetModuleHandle, NULL
            mov hInstance,eax
            invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
            invoke ExitProcess,eax
            WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
            LOCAL wc:WNDCLASSEX
            LOCAL msg:MSG
            LOCAL hwnd:HWND
            mov wc.cbSize,SIZEOF WNDCLASSEX
            mov wc.style, CS_HREDRAW or CS_VREDRAW
            mov wc.lpfnWndProc, OFFSET WndProc
            mov wc.cbClsExtra,NULL
            mov wc.cbWndExtra,NULL
            push hInst
            pop wc.hInstance
            mov wc.hbrBackground,COLOR_APPWORKSPACE
            mov wc.lpszMenuName,NULL
            mov wc.lpszClassName,OFFSET ClassName
            invoke LoadIcon,NULL,IDI_APPLICATION
            mov wc.hIcon,eax
            mov wc.hIconSm,eax
            invoke LoadCursor,NULL,IDC_ARROW
            mov wc.hCursor,eax
            invoke RegisterClassEx, addr wc
            invoke CreateWindowEx,WS_EX_CLIENTEDGE+WS_EX_CONTROLPARENT,ADDR ClassName,ADDR AppName,\
            WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,\
            CW_USEDEFAULT,350,220,NULL,NULL,\
            hInst,NULL
            mov hwnd,eax
            .while TRUE
            invoke GetMessage, ADDR msg,NULL,0,0
            .BREAK .IF (!eax)
            invoke TranslateMessage, ADDR msg
            invoke DispatchMessage, ADDR msg
            .endw
            mov eax,msg.wParam
            ret
            WinMain endp
            WndProc proc uses ebx edi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
            LOCAL wc:WNDCLASSEX
            .if uMsg==WM_CREATE
            mov wc.cbSize,sizeof WNDCLASSEX
            invoke GetClassInfoEx,NULL,addr EditClass,addr wc
            push wc.lpfnWndProc
            pop OldWndProc
            mov wc.lpfnWndProc, OFFSET EditWndProc
            push hInstance
            pop wc.hInstance
            mov wc.lpszClassName,OFFSET OurClass
            invoke RegisterClassEx, addr wc
            xor ebx,ebx
            mov edi,20
            .while ebx<6
            invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR OurClass,NULL,\
            WS_CHILD+WS_VISIBLE+WS_BORDER,20,\
            edi,300,25,hWnd,ebx,\
            hInstance,NULL
            mov dword ptr [hwndEdit+4*ebx],eax
            add edi,25
            inc ebx
            .endw
            invoke SetFocus,hwndEdit
            .elseif uMsg==WM_DESTROY
            invoke PostQuitMessage,NULL
            .else
            invoke DefWindowProc,hWnd,uMsg,wParam,lParam
            ret
            .endif
            xor eax,eax
            ret
            WndProc endp
            EditWndProc PROC hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
            .if uMsg==WM_CHAR
            mov eax,wParam
            .if (al>="0" && al<="9") || (al>="A" && al<="F") || (al>="a" && al<="f") || al==VK_BACK
            ;處理字符0~9,A~F,a~f,這幾個(gè)十六進(jìn)制數(shù)
            .if al>="a" && al<="f"
            sub al,20h
            如果是字符a~f,則把它們變?yōu)榇髮?BR>    .endif
            invoke CallWindowProc,OldWndProc,hEdit,uMsg,eax,lParam
            ret
            .endif
            .elseif uMsg==WM_KEYDOWN
            mov eax,wParam
            .if al==VK_RETURN
            invoke MessageBox,hEdit,addr Message,addr AppName,MB_OK+MB_ICONINFORMATION
            invoke SetFocus,hEdit
            .elseif al==VK_TAB
            invoke GetKeyState,VK_SHIFT
            test eax,80000000
            .if ZERO?
            invoke GetWindow,hEdit,GW_HWNDNEXT
            .if eax==NULL
            invoke GetWindow,hEdit,GW_HWNDFIRST
            .endif
            .else
            invoke GetWindow,hEdit,GW_HWNDPREV
            .if eax==NULL
            invoke GetWindow,hEdit,GW_HWNDLAST
            .endif
            .endif
            invoke SetFocus,eax
            xor eax,eax
            ret
            .else
            invoke CallWindowProc,OldWndProc,hEdit,uMsg,wParam,lParam
            ret
            .endif
            .else
            invoke CallWindowProc,OldWndProc,hEdit,uMsg,wParam,lParam
            ret
            .endif
            xor eax,eax
            ret
            EditWndProc endp
            end start
            分析
            這個(gè)程序創(chuàng)建了一個(gè)在其客戶區(qū)有六個(gè)被修改的 Edit 控件的簡(jiǎn)單窗口,這些 Edit控件只接受十六進(jìn)制的數(shù)字。實(shí)際上,這個(gè)例子是通過(guò)修改窗口了類化的例子得來(lái)的。這個(gè)程序開始和其它程序一樣,有趣的部分出現(xiàn)在主窗口被創(chuàng)建的時(shí)候:
            .if uMsg==WM_CREATE
            mov wc.cbSize,sizeof WNDCLASSEX
            invoke GetClassInfoEx,NULL,addr EditClass,addr wc
            必須用想進(jìn)行超類化操作的類數(shù)據(jù)填充 WNDCLASSEX 結(jié)構(gòu),在我們的例子中就是類 Edit ,記住在調(diào)用函數(shù) GetClassInfoEx 之前必須填寫成員 cbSize,否則函數(shù)調(diào)用 GetClassInfoEx不會(huì)在 WNDCLASSEX 結(jié)構(gòu)中填入正確的返回值。成功返回后,變量 wc中保存的就是想要?jiǎng)?chuàng)建一個(gè)新類所需要的所有信息。
            push wc.lpfnWndProc
            pop OldWndProc
            mov wc.lpfnWndProc, OFFSET EditWndProc
            push hInstance
            pop wc.hInstance
            mov wc.lpszClassName,OFFSET OurClass
            現(xiàn)在必須修改變量 wc 的一些屬性:第一個(gè)要修改的就是指向窗口過(guò)程的指針。因?yàn)樵谛麓翱谶^(guò)程中函數(shù) CallWindowProx 要用到老窗口過(guò)程,因此得把它保存到一個(gè)變量中以便使用。這個(gè)技巧和在子類化中用到的一樣,只不過(guò)不是調(diào)用 SetWindowLong 而是直接修改 WNDCLASSEX 結(jié)構(gòu)罷了。接下來(lái)必須得為這個(gè)新類取個(gè)名字。
            invoke RegisterClassEx, addr wc
            當(dāng)所有這些都完成時(shí),注冊(cè)這個(gè)新類就會(huì)得到一個(gè)具有舊類某些特征的新類了。
            xor ebx,ebx
            mov edi,20
            .while ebx<6
            invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR OurClass,NULL,\
            WS_CHILD+WS_VISIBLE+WS_BORDER,20,\
            edi,300,25,hWnd,ebx,\
            hInstance,NULL
            mov dword ptr [hwndEdit+4*ebx],eax
            add edi,25
            inc ebx
            .endw
            invoke SetFocus,hwndEdit
            注冊(cè)完新類就可以創(chuàng)建基于它的窗口了:
            在上面的程序片斷中,用寄存器 ebx 來(lái)保存已創(chuàng)建的窗口數(shù)目,用寄存器 edi 來(lái)保存窗口左上角的 y 坐標(biāo)。創(chuàng)建一個(gè)新窗口時(shí),把它的句柄保存在一個(gè)雙字的數(shù)組中,當(dāng)創(chuàng)建完所有的窗口后,設(shè)定輸入焦點(diǎn)為所創(chuàng)建的第一個(gè)窗口。
            這時(shí)已經(jīng)有6個(gè)只能接受十六進(jìn)制數(shù)字的 edit 窗口控件了,替換的窗口過(guò)程處理了字符過(guò)濾,這實(shí)際上和在子類化中的例子是一樣的。但不必做子類化那些窗口的額外工作了。
            在此程序中,通過(guò)使用 Tabs 鍵來(lái)在各個(gè) Edit 控件中切換來(lái)使得這個(gè)程序更加有趣。一般來(lái)說(shuō),如果使用對(duì)話框,對(duì)話框管理器會(huì)處理好所有這些問(wèn)題,即:
            按下 Tabs 輸入焦點(diǎn)切換到下一個(gè)控件窗口中,按下 Shift-Tabs 輸入焦點(diǎn)切換到上一個(gè)控件窗口中;但一個(gè)簡(jiǎn)單的窗口不具有這個(gè)功能,必須子類化它們以處理 Tabs 鍵。在這個(gè)例子中,不必一個(gè)一個(gè)去子類化已經(jīng)進(jìn)行過(guò)超類化操作的這些控件,可以使用一種集中控制切換策略。
            .elseif al==VK_TAB
            invoke GetKeyState,VK_SHIFT
            test eax,80000000
            .if ZERO?
            invoke GetWindow,hEdit,GW_HWNDNEXT
            .if eax==NULL
            invoke GetWindow,hEdit,GW_HWNDFIRST
            .endif
            .else
            invoke GetWindow,hEdit,GW_HWNDPREV
            .if eax==NULL
            invoke GetWindow,hEdit,GW_HWNDLAST
            .endif
            .endif
            invoke SetFocus,eax
            xor eax,eax
            ret
            上面是摘自于 EditWndClass 過(guò)程的程序片斷,它檢查用戶是否按下了 Tabs 鍵,若是就調(diào)用函數(shù) GetKeyState 來(lái)檢查 SHIFT 鍵是否也被同時(shí)按下了。函數(shù) GetKeyState 在寄存器 eax 中設(shè)立一個(gè)返回值,用于判斷某個(gè)特定的鍵是否被按下了,若按下了,則把 eax 的的位置1,否則把位清0。所以只要用 80000000h 來(lái)測(cè)試返回值就行了,若位是1則說(shuō)明用戶按下了 SHIFT-Tabs,這需要單獨(dú)處理;否則說(shuō)明只按下 Tabs 鍵,調(diào)用函數(shù) GetWindow 來(lái)獲得 hEdit 所指向窗口的下一個(gè)窗口句柄,若該函數(shù)返回 NULL ,說(shuō)明這是當(dāng)前窗口是窗口鏈中最后一個(gè)窗口了,應(yīng)該通過(guò)以參數(shù) GW_HWNDFIRST 調(diào)用函數(shù) GetWindow 來(lái)卷回到窗口鏈中的第一個(gè)窗口控件。SHIFT-Tabs 的處理過(guò)程和這正好相反。