久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

自定義VB系統(tǒng)控件

 高高興興 2006-01-20
本篇文章面對的對象是初級VB程序員,,最好有些Windows系統(tǒng)應(yīng)用程序開發(fā)知識。在結(jié)束文章以前,,前邊任何內(nèi)容均有可能更改,,如果文中代碼有觸犯版權(quán)等問題,請與作者聯(lián)系,,如果作者本人同意,,將會署名發(fā)布,,如果不同意將予以刪除。



由于本人文筆欠佳,,所以還真不知能寫出什么文章,,本來打算寫些.net方面的文章,但是由于剛剛接觸.net不久,,還沒有什么經(jīng)驗體會,,對于我而言經(jīng)驗最多的應(yīng)該還是VB吧,畢竟已經(jīng)用了兩年多了,。但是這僅僅是我自身比較而言并不是和其他人比較,,因此決定將一些平時經(jīng)驗和技巧寫下來,也就算整理一下資料吧,,雖然是班門弄斧,,但是希望這篇文章能對一些VB初學(xué)者有些幫助。希望使用VB開發(fā)應(yīng)用的人能通過這篇文章得到一些啟發(fā),,能從另一個角度來看待VB程序開發(fā),。

先談?wù)勎业膫€人想法:

不管我們使用什么計算機(jī)語言開發(fā),VC,,VB,,BCB,JAVA,,NET你都脫離不開操作系統(tǒng),,它就是我們軟件的生存土壤,JAVA的跨平臺其實是因為它的虛擬機(jī),,實質(zhì)上虛擬機(jī)還是要依靠操作系統(tǒng),,.net可以說博大精深但是它最終還是調(diào)用操作系統(tǒng)提供的服務(wù),在Windows2003上運行.net程序和在windows95上運行效果肯定不同,,因此只要一種語言提供給我們一種直接調(diào)用操作系統(tǒng)服務(wù)的接口(API)我們就不能武斷的說它某些事做不了,。只不過是方便與否,難以程度有差別,,說這些話有些位VB申冤的嫌疑,,可以說我確實有這點私心,但是如果你選擇了VB你就要相信它,,想辦法了解到,,這樣才能充分發(fā)揮它的功能。

通常一種語言用久了就不知不覺中用它來思考,,這有好處也有壞處,,真正了解一門語言就要學(xué)會在使用中用它來思考,但是因此也會帶來思維定式,。很多時候局限的不是語言本身而是我們的思想,。因此我們需要不停的思考,,從不同角度思考,正如我的bLog的標(biāo)題“我思故我在”,,這句話有些唯心,,但實際上在沒有上學(xué)之前,在沒有接收唯物主義的哲學(xué)思想之前我應(yīng)該算是唯心主義者,。當(dāng)時我總是想我眼里的世界包括人,動物,,植物等所有的一切是否僅僅是在我眼里才呈現(xiàn)這個樣子而在別人的眼中,,是否這個世界是另一個模樣,這個我現(xiàn)在也不知道,,因為接觸的是用我的雙手,,我看到的是用的眼睛,我感知的是用我的心靈,,我無法代替別人,,別人無法代替我。話題好像扯遠(yuǎn)了,。

Visual Basic 是一種RAD工具,,之所以說它是RAD工具就是因為很多底層初級的東西已經(jīng)被IDE封裝好,我們只要直接用就好了,,因此我們可以用VB來進(jìn)行快速的應(yīng)用開發(fā),。

舉個例子:

如果用代碼創(chuàng)建一個正常工作的窗體至少需要調(diào)用如下幾個API:

RegisterClass或RegisterClassEx:該函數(shù)為隨后在調(diào)用Createwindow函數(shù)和CreatewindowEx函數(shù)中使用的窗口注冊一個窗口類

UnregisterClass:刪除一個窗口類,清空該類所需的內(nèi)存

DefWindowProc:該函數(shù)調(diào)用缺省的窗口過程來為應(yīng)用程序沒有處理的任何窗口消息提供缺省的處理,。該函數(shù)確保每一個消息得到處理,。調(diào)用DefWindowProc函數(shù)時使用窗口過程接收的相同參數(shù)

GetMessage:該函數(shù)從調(diào)用線程的消息隊列里取得一個消息并將其放于指定的結(jié)構(gòu)

TranslateMessage:該函數(shù)將虛擬鍵消息轉(zhuǎn)換為字符消息

DispatchMessage:該函數(shù)調(diào)度一個消息給窗口程序,通常調(diào)度從GetMessage取得的消息

ShowWindow:用于設(shè)置窗口的狀態(tài),,其中包括窗口的隱藏,、顯示、最小化,、最大化,、激活等

UpdateWindow: 立即更新窗口內(nèi)需要更新的任何部分

CreateWindowEx:該函數(shù)創(chuàng)建一個具有擴(kuò)展風(fēng)格的重疊式窗口、彈出式窗口或子窗口,,其他與CreateWindow函數(shù)相同

CallWindowProc:該函數(shù)CallWindowProc將消息信息傳送給指定的窗口過程,。

SetWindowLong,GetWindowLong:用于獲取或設(shè)置與窗口有關(guān)的信息

PostQuitMessage:將一條消息投遞到指定窗口的消息隊列

DestroyWindow:清除指定的窗口以及下屬所有子窗口與包容窗口.

進(jìn)行幾個繁瑣的操作才能創(chuàng)建一個窗體,。然后還有進(jìn)行各種消息處理等等,,但是有了VB這種RAD工具所有這些我們都可以不用關(guān)心,因為VB已經(jīng)為我們封裝好了,。

我們所要做的且關(guān)心的就是怎么設(shè)計我們自己的應(yīng)用,。

做個比喻就像我們已經(jīng)有了房子只需要按照自己的需要進(jìn)行裝修即可,,但是非RAD工具是從樓房的地基(地址有操作系統(tǒng)提供)開始。

但是,,凡事沒有絕對的優(yōu)點也沒有絕對的缺點,。站在不同的角度看待同一個事物卻會有不同的結(jié)果。

如果我想在VB中在反過來深入底層將是很麻煩的事,。

按照自己的想法蓋房子和將已經(jīng)建好的樓房進(jìn)行改建更麻煩(我這里用的是麻煩,,并不是困難),它的難點就是如何找到切入點,。

但是如果能夠靈活運用系統(tǒng)API,,能夠找到切入點,將會起到事半功倍的效果,。

下面用實際的例子進(jìn)行一些演示說明,,由于本人技術(shù)及篇幅有限,不事宜做復(fù)雜的說明,。那些做為專題討論,,寫這篇主要目的是起到拋磚引玉的作用。

嚴(yán)格說來操作系統(tǒng)只知道窗口控件(WinControl)的存在,,我這里說的窗口控件可以這么理解就是在VB中具有hWnd(窗口句柄)的控件,。他們都靠系統(tǒng)的消息驅(qū)動,因為我在這篇文章主要側(cè)重點是利用API來發(fā)掘VB,,因此涉及的對象基本都是指窗口控件,,非窗口控件的創(chuàng)建、更新,、銷毀又它的父窗口控件來負(fù)責(zé),。

使用VC++編程的人一定會熟悉很多窗體控件風(fēng)格常量,然后按照自己的需要創(chuàng)建窗體控件樣式,,而我們在VB中,,這些統(tǒng)統(tǒng)被IDE包裝起來的,我和根本看不到,,但是利用API我們可以重新定義窗體控件的樣式,,下面就用實際例子來演示一下:

(這里我沒有列出詳細(xì)的API和常量聲明,因為我主要想體現(xiàn)的是方法和思路)

 

  任何一個窗體控件,,我們都可以給它加上ControlBox(所謂ControlBox,,就是窗體的圖標(biāo)+最小化+最大化+關(guān)閉按鈕)

Public Sub ControlSysMenu(ControlName As Control, SetTrue As Boolean)

   Dim dwStyle As Long

   dwStyle = GetWindowLong(ControlName.hwnd, GWL_STYLE)

   If SetTrue Then

      dwStyle = dwStyle Or WS_SYSMENU

   Else

   dwStyle = dwStyle - WS_SYSMENU

   End If

   dwStyle = SetWindowLong(ControlName.hwnd, GWL_STYLE, dwStyle)

    SetWindowPos ControlName.hwnd, ControlName.Parent.hwnd, 0, 0, 0, 0, SWP_NOZORDER Or SWP_NOSIZE Or SWP_NOMOVE Or SWP_DRAWFRAME

End Sub



任何一個窗體組件,我們都可以給它加上標(biāo)題欄,,通過拖動標(biāo)題欄,,可以實現(xiàn)控件的運行時移動。



Public Sub ControlCaption(ControlName As Control, SetTrue As Boolean)

    Dim dwStyle As Long

    dwStyle = GetWindowLong(ControlName.hwnd, GWL_STYLE)

    If SetTrue Then

       dwStyle = dwStyle Or WS_CAPTION Or WS_THICKFRAME

    Else

       dwStyle = dwStyle - WS_CAPTION - WS_THICKFRAME

    End If

    dwStyle = SetWindowLong(ControlName.hwnd, GWL_STYLE, dwStyle)

     SetWindowPos ControlName.hwnd, ControlName.Parent.hwnd, 0, 0, 0, 0, SWP_NOZORDER Or SWP_NOSIZE Or SWP_NOMOVE Or SWP_DRAWFRAME

End Sub



任何一個窗體組件,我們都可以控制其顯示風(fēng)格為模式對話框的風(fēng)格



Public Sub ControlModal(ControlName As Control, SetTrue As Boolean)

    Dim dwStyle As Long

    dwStyle = GetWindowLong(ControlName.hwnd, GWL_STYLE)

    If SetTrue Then

       dwStyle = dwStyle Or WS_POPUP

    Else

       dwStyle = dwStyle - WS_POPUP

    End If

    dwStyle = SetWindowLong(ControlName.hwnd, GWL_STYLE, dwStyle)

     SetWindowPos ControlName.hwnd, ControlName.Parent.hwnd, 0, 0, 0, 0, SWP_NOZORDER Or SWP_NOSIZE Or SWP_NOMOVE Or SWP_DRAWFRAME

End Sub



任何一個窗體組件,,我們都可以控制其顯示風(fēng)格為對話框的風(fēng)格,。

Public Sub ControlDialog(ControlName As Control, SetTrue As Boolean)

   Dim dwStyle As Long

   dwStyle = GetWindowLong(ControlName.hwnd, GWL_STYLE)

   If SetTrue Then

      dwStyle = dwStyle Or WS_DLGFRAME

   Else

      dwStyle = dwStyle - WS_DLGFRAME

   End If

   dwStyle = SetWindowLong(ControlName.hwnd, GWL_STYLE, dwStyle)

   SetWindowPos ControlName.hwnd, ControlName.Parent.hwnd, 0, 0, 0, 0, SWP_NOZORDER Or SWP_NOSIZE Or SWP_NOMOVE Or SWP_DRAWFRAME

End Sub



只要有窗口,這是我們的前提,,你可以在運行時隨便更改它的大小,。

Public Sub ControlSize(ControlName As Control, SetTrue As Boolean)

   Dim dwStyle As Long

   dwStyle = GetWindowLong(ControlName.hwnd, GWL_STYLE)

   If SetTrue Then

      dwStyle = dwStyle Or WS_THICKFRAME

   Else

      dwStyle = dwStyle - WS_THICKFRAME

   End If

   dwStyle = SetWindowLong(ControlName.hwnd, GWL_STYLE, dwStyle)

   SetWindowPos ControlName.hwnd, ControlName.Parent.hwnd, 0, 0, 0, 0, SWP_NOZORDER Or SWP_NOSIZE Or SWP_NOMOVE Or SWP_DRAWFRAME

End Sub

通過以上幾個實例,我們知道了如何使用VB沒有提供的窗體風(fēng)格樣式,。下面將根據(jù)我的實際經(jīng)歷介紹幾個具體的窗體控件的某些比較使用的擴(kuò)展功能,。

有兩個知識點不能不說,消息機(jī)制,,子類(Subclass),。

Windows消息機(jī)制:

眾所周知,Windows系統(tǒng)是靠消息來驅(qū)動的,。一個應(yīng)用程序內(nèi)部的運行不是靠順序,而是靠事件的觸發(fā)來控制,,而各個事件與組件間的通訊就是靠消息來完成的,。

Windows是一個多任務(wù)的操作系統(tǒng),在同一時刻,,系統(tǒng)中有著多個應(yīng)用程序的實例在運行,。在這樣的一個操作系統(tǒng)中,不可能像過去的DOS那樣,,由一個應(yīng)用程序來享用所有的系統(tǒng)資源,,這些資源是由Windows統(tǒng)一管理的。那么,,系統(tǒng)如何協(xié)調(diào)各個應(yīng)用實例的運行,,如何為各個應(yīng)用實例分配CPU時間呢?如何相應(yīng)用戶的輸入呢,?事實上,,Windows時刻監(jiān)視著用戶的一舉一動,并分析用戶的動作與哪一個應(yīng)用程序相關(guān),,然后,,將用戶的動作以消息的形式發(fā)送到系統(tǒng)中的消息隊列,這個消息隊列就是應(yīng)用程序正常運行的基礎(chǔ),,也是一條紐帶,,將應(yīng)用程序中各個部分連接成一個整體來完成特定的任務(wù)。直到應(yīng)用程序終止它會不停的檢測系統(tǒng)的消息隊列,,對隊列中未處理的消息進(jìn)行分析,,根據(jù)消息所包含的內(nèi)容采取適當(dāng)?shù)膭幼鱽眄憫?yīng)用戶所作的操作。

舉個簡單的例子:

假設(shè)我們的應(yīng)用程序的某個窗體有個File菜單,,那么,,在運行該應(yīng)用程序的時候,,如果用戶單擊了File菜單,這個動作將被Windows (而不是應(yīng)用程序本身,!)所捕獲,,Windows經(jīng)過分析得知這個動作應(yīng)該由上面所說的那個應(yīng)用程序去處理,因此,,Windows就發(fā)送了個叫做WM_COMMAND的消息給應(yīng)用程序,,該消息所包含的信息告訴應(yīng)用程序:“用戶單擊了File菜單”,應(yīng)用程序得知這一消息之后,,采取相應(yīng)的動作來響應(yīng)它,,在VB中默認(rèn)會去執(zhí)行File Click事件。這個過程被稱為消息處理,。Windows為每一個應(yīng)用程序(確切地說是每一個線程)維護(hù)了相應(yīng)的消息隊列,,應(yīng)用程序的任務(wù)就是不停的從它的消息隊列中獲取消息,分析消息和處理消息,,直到一條接到叫做WM_QUIT消息為止,,這個過程通常是由一種叫做消息循環(huán)的程序結(jié)構(gòu)來實現(xiàn)的。

   Do While GetMessage(wMsg, 0&, 0&, 0&)

     Call TranslateMessage(wMsg)’翻譯消息

      Call DispatchMessage(wMsg)’ 撤去消息

   Loop

其中wMsg就是一個消息結(jié)構(gòu),,它可以這樣定義:

Public Type Msg

    hwnd As Long

    message As Long

    wParam As Long

    lParam As Long

    time As Long

    pt As POINTAPI

End Type

參數(shù)1:hwnd是消息要發(fā)送到的那個窗口的句柄,這個窗口就是咱們用CreateWindows函數(shù)創(chuàng)建的那一個,。如果是在一個有多個窗口的應(yīng)用程序中,用這個參數(shù)就可決定讓哪個窗口接收消息,。

參數(shù)2:message是一個數(shù)字,,它唯一標(biāo)識了一種消息類型。每種消息類型都在Windows文件中定義了,,這些常量都以WM_開始后面帶一些描述了消息特性的名稱,。比如說當(dāng)應(yīng)用程序退出時,Windows就向應(yīng)用程序發(fā)送一條WM_QUIT消息,。

參數(shù)3:一個32位的消息參數(shù),,這個值的確切意義取決于消息本身。

參數(shù)4:同上,。

參數(shù)5:消息放入消息隊列中的時間,,在這個域中寫入的并不是日期,而是從Windows啟動后所測量的時間值,。Windows用這個域來使用消息保持正確的順序,。

參數(shù)6:消息放入消息隊列時的鼠標(biāo)坐標(biāo).



消息循環(huán)以GetMessage調(diào)用開始,它從消息隊列中取出一個消息:

GetMessage(&msg,NULL,0,0),,第一個參數(shù)是要接收消息的MSG結(jié)構(gòu)的地址,,第二個參數(shù)表示窗口句柄,NULL則表示要獲取該應(yīng)用程序創(chuàng)建的所有窗口的消息;第三,四參數(shù)指定消息范圍,。后面三個參數(shù)被設(shè)置為默認(rèn)值,,這就是說你打算接收發(fā)送到屬于這個應(yīng)用程序的任何一個窗口的所有消息。在接收到除WM_QUIT之外的任何一個消息后,,GetMessage()都返回TRUE,。如果GetMessage收到一個WM_QUIT消息,則返回FALSE,,如收到其他消息,,則返回TRUE。因此,,在接收到WM_QUIT之前,,帶有GetMessage()的消息循環(huán)可以一直循環(huán)下去。只有當(dāng)收到的消息是WM_QUIT時,,GetMessage才返回FALSE,,結(jié)束消息循環(huán),從而終止應(yīng)用程序,。 均為NULL時就表示獲取所有消息,。

消息用GetMessage讀入后(注意這個消息可不是WM_QUIT消息),它首先要經(jīng)過函數(shù)TranslateMessage()進(jìn)行翻譯,,這個函數(shù)會轉(zhuǎn)換成一些鍵盤消息,它檢索匹配的WM_KEYDOWN和WM_KEYUP消息,,并為窗口產(chǎn)生相應(yīng)的ASCII字符消息(WM_CHAR),它包含指定鍵的ANSI字符.但對大多數(shù)消息來說它并不起什么作用,,所以現(xiàn)在沒有必要考慮它。

下一個函數(shù)調(diào)用DispatchMessage()要求Windows將消息傳送給在MSG結(jié)構(gòu)中為窗口所指定的窗口過程,。我們在講到登記窗口類時曾提到過,,登記窗口類時,我們曾指定Windows把函數(shù)WindosProc作為咱們這個窗口的窗口過程(就是指處理這個消息的東東),。就是說,,Windows會調(diào)用函數(shù)WindowsProc()來處理這個消息。在WindowProc()處理完消息后,,代碼又循環(huán)到開始去接收另一個消息,,這樣就完成了一個消息循環(huán)。

因此,,從某種角度上來看,,Windows應(yīng)用程序是由一系列的消息處理代碼來實現(xiàn)的。這和傳統(tǒng)的過程式編程方法很不一樣,,編程者只能夠預(yù)測用戶所利用應(yīng)用程序用戶界面對象所進(jìn)行的操作以及為這些操作編寫處理代碼,,卻不可以這些操作在什么時候發(fā)生或者是以什么順序來發(fā)生,也就是說,我們不可能知道什么消息會在什么時候以什么順序來臨,。那么windows是如何解決這個問題的呢,?windows采用一種叫做回調(diào)函數(shù)(callback function)的特殊函數(shù),這個函數(shù)由Windows直接調(diào)用,。實際上每個窗口類都必須有一個回調(diào)函數(shù),。在Windows中消息循環(huán)和窗口類的回調(diào)函數(shù)已經(jīng)都被封裝起來,我們一般情況不會接觸,,如果我們想重新注冊窗口過程函數(shù)WindowProc(就是這個回調(diào)函數(shù)),,我們必須使用子類(Subclass)的技術(shù)。

(這部分說的可能比較多,,而且都是開發(fā)Windows應(yīng)用程序的基礎(chǔ)部分(基礎(chǔ)的東西雖然難度不大,,但是非常重要)。但是因為對于部分VB程序員來說可能接觸不多,,因此說的多了點,。)

子類(Subclass):

按照上文提到的因為對于正常的VB通常不能直接處理Windows系統(tǒng)的消息,但是我們可以通過子類的方法截獲Windows消息并且自定義其處理方法(而如果想截獲其他應(yīng)用程序的消息就需要使用鉤子(Hook)技術(shù)),。

應(yīng)用程序可以用過SetWindowLong API 函數(shù)為具有窗口句柄(hWnd)的窗體,、控件或其他對象安裝新的消息處理(Message handler)過程函數(shù)WindowProc。這個新的WindowProc過程必須被定義在模塊(.BAS)文件中,。

Private Sub Form_Load()

    OldWindowProc = SetWindowLong( _

        hwnd, GWL_WNDPROC, _

        AddressOf NewWindowProc)

End Sub

現(xiàn)在,,如果窗體收到Windows消息,系統(tǒng)將調(diào)用新的WindowProc 過程(NewWindowProc),,這個新的窗口過程函數(shù)將檢查當(dāng)前的消息行為是否被指定,,如果沒有指定具體的行為,將被傳遞給源窗口過程函數(shù)WindowProc,,有源WindowProc進(jìn)行默認(rèn)的處理,。這個過程是非常重要的,否則因為當(dāng)前窗口可能會因為消息遺失,,造成不能進(jìn)行重繪,、更新等其他窗口默認(rèn)的標(biāo)準(zhǔn)行為。而且新的窗口過程必須返回源過程函數(shù)返回的結(jié)果,。

下面用一個實際代碼例子演示處理WM_SYSCOMMAND消息的過程:

WM_SYSCOMMAND: 當(dāng)用戶選擇“窗口菜單”的一條命令是觸發(fā),。



Public Function NewWindowProc( _

    ByVal hwnd As Long, ByVal msg As Long, _

    ByVal wParam As Long, lParam As WINDOWPOS) As Long

Const WM_SYSCOMMAND = &H112

Const SC_SIZE = &HF000&



    ‘ 檢查是否是WM_SYSCOMMAND消息

    If msg = WM_SYSCOMMAND Then

        ‘ 如果收到的消息是WM_SYSCOMMAND ,進(jìn)一步檢查命令參數(shù)是否是SC_SIZE, 如果是就忽略它,,不進(jìn)行任何處理,。

        If (wParam And &HFFF0) = SC_SIZE Then Exit Function

    End If



    ‘*其余的消息傳遞給源窗口過程函數(shù)*非常重要

    NewWindowProc = CallWindowProc( _

        OldWindowProc, hwnd, msg, wParam, _

        lParam)

End Function



上面的過程函數(shù)首先檢查收到的消息是否是WM_SYSCOMMAND消息,如果是,,那么再進(jìn)一步檢查參數(shù)(wParam)是否是SC_SIZE命令,。如果是表示窗體想要調(diào)整大小,。但是我們自定義的窗口過程函數(shù)已經(jīng)對它進(jìn)行了處理,因此這個消息將不會被傳遞到源窗口過程函數(shù),。而我們自定義的這個窗口過程沒有處理的消息將全部進(jìn)一步傳遞給源窗口過程函數(shù)(它的地址保存在OldWindowProc中),。

需要注意的是,當(dāng)我們卸載我們子類的對象前,,我們必須恢復(fù)它的窗口過程函數(shù),。

Private Sub Form_Unload(Cancel As Integer)

    SetWindowLong hwnd, GWL_WNDPROC, OldWindowProc

End Sub



因為我們卸載一個窗口對象,系統(tǒng)會發(fā)送WM_NCDESTROY消息給對象,,因此我們可以通過檢測這個消息來自動恢復(fù)對象的源窗口過程,。

Public Function NewWindowProc( ByVal hwnd As Long, ByVal msg As Long, _

    ByVal wParam As Long, lParam As WINDOWPOS) As Long

Const WM_NCDESTROY = &H82

Const WM_SYSCOMMAND = &H112

Const SC_SIZE = &HF000&



    ‘ 如果組件被銷毀,恢復(fù)源窗口過程處理函數(shù)

    If msg = WM_NCDESTROY Then

        SetWindowLong   hwnd, GWL_WNDPROC,OldWindowProc

    End If



    If msg = WM_SYSCOMMAND Then

        If (wParam And &HFFF0) = SC_SIZE Then Exit Function

    End If

    NewWindowProc = CallWindowProc( _

        OldWindowProc, hwnd, msg, wParam, _

        lParam)

End Function



需要注意的一點是,,這種方式很容易造成VB IDE的崩潰,。不要在調(diào)試模式中途暫停或終于應(yīng)用程序,,因為這樣可能不能恢復(fù)源窗口過程函數(shù),,造成無法處理正常的消息,變得異?;騃DE崩潰,,因此切記調(diào)試前一定存盤。

除了使用子類的方法,,我沒還可以使用幾個API函數(shù)向?qū)ο笾鲃影l(fā)消息,。我們可以用SendMessage和PostMessage:

PostMessage將消息直接加入到應(yīng)用程序的消息隊列中,不等程序返回就退出,;而SendMessage()則剛好相反,,應(yīng)用程序處理完此消息后,它才返回,,可以參考下圖:



下面就對具體實際應(yīng)用舉幾個例子:

TextBox控件:

a.   控制Textbox輸入格式,,我想大多人都遇到這個問題,,在TextBox作為輸入接口時,,有時我們希望用戶只能輸入數(shù)字、大寫,、字母等,,一般的做法是對用戶輸入的字符這個檢查。但是如果我們使用API,,將很容易實現(xiàn)這些功能,,比如:

   只允許輸入數(shù)字:

Public Function NumbersOnly(tBox As TextBox)

    Dim DefaultStyle As Long

    DefaultStyle = GetWindowLong(tBox.hwnd, GWL_STYLE)

    NumbersOnly = SetWindowLong(tBox.hwnd, GWL_STYLE, DefaultStyle Or ES_NUMBER)

End Function

   只允許大寫:

Public Function UpperCaseOnly(tBox As TextBox)

    Dim DefaultStyle As Long

    DefaultStyle = GetWindowLong(tBox.hwnd, GWL_STYLE)

    UpperCaseOnly = SetWindowLong(tBox.hwnd, GWL_STYLE, DefaultStyle Or ES_UPPERCASE)

End Function

   只允許小寫:

Public Function LowerCaseOnly(tBox As TextBox)

    Dim DefaultStyle As Long

    DefaultStyle = GetWindowLong(tBox.hwnd, GWL_STYLE)

    LowerCaseOnly = SetWindowLong(tBox.hwnd, GWL_STYLE, DefaultStyle Or ES_LOWERCASE)

End Function

當(dāng)然上邊三個函數(shù)可以合成一個函數(shù),因為他們方法是一樣的,,只是風(fēng)格參數(shù)不同而已,。

b.外觀風(fēng)格:



VB本身提供兩種風(fēng)格:Flat和3D,,但是也許你想改變一下外觀,比如讓TextBox的邊界介于Flat和3D之間那種效果,,如圖:



怎么做呢,?在VC中我們在創(chuàng)建一個窗口對象時可以制定它的風(fēng)格,但是在VB中,,IDE已經(jīng)按照它自己的想法給我創(chuàng)建好了,,如果我們想要改變它只能把已經(jīng)存在的進(jìn)行修改,這時我們就需要借助的GetWindowLong和SetWindowLong兄弟的幫助來完成這個任務(wù)了,。



Public Sub FlatBorder(ByVal hwnd As Long)

Dim TFlat As Long

‘首先將原始的窗口屬性讀出來

    TFlat = GetWindowLong(hwnd, GWL_EXSTYLE)

‘進(jìn)行適當(dāng)修改

    TFlat = TFlat And Not WS_EX_CLIENTEDGE Or WS_EX_STATICEDGE

‘寫回去

    SetWindowLong hwnd, GWL_EXSTYLE, TFlat

‘這個函數(shù)能為窗口指定一個新位置和狀態(tài),。它也可改變窗口在內(nèi)部窗口列表中的位置。該函數(shù)與DeferWindowPos函數(shù)相似,,只是它的作用是立即表現(xiàn)出來的(在vb里使用:針對vb窗體,,如它們在win32下屏蔽或最小化,則需重設(shè)最頂部狀態(tài),。如有必要,,請用一個子類處理模塊來重設(shè)最頂部狀態(tài))

    SetWindowPos hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE Or SWP_NOZORDER Or SWP_FRAMECHANGED Or SWP_NOSIZE Or SWP_NOMOVE

End Sub

*當(dāng)然上邊的函數(shù)可以用在所有窗口對象上,只不夠有些窗口對象不需要這么做,。





如果窗體中有很多TextBox需要這樣設(shè)置,,而且不都是控件數(shù)組,那么可以在包裝一下上面的函數(shù):

Public Sub AddBorderToAllTextBoxes(frmX As Form)

   Dim X As Control

   On Error Resume Next

   For Each X In frmX.Controls

        If TypeOf X Is TextBox Then

                FlatBorder X.hWnd

        End If

   Next



End Sub



b.   改變文字布局:

VB 中可以設(shè)置TextBox中文本水平方向居左,、居右,、居中,但是不能設(shè)置垂直方向,,也不能微調(diào)文本距離左邊界的距離,,但是我們還是可以借助API的幫助來完成這個需求:

   文本垂直居中:

Public Sub VerMiddleText(mText As TextBox)

   Dim rc As RECT

   Dim tmpTop As Long

   Dim tmpBot As Long

   ‘實現(xiàn)這個效果首先TextBox的MultiLine屬性必須為True(多行文本,其實這個屬性關(guān)系創(chuàng)建TextBox內(nèi)部使用哪個類,,因此一旦創(chuàng)建就不能修改這個屬性,,所以不能在代碼中修改這個屬性)

   If mText.MultiLine = False Then Exit Sub

   ‘獲得沒個窗口區(qū)域的邊界我們可以通過發(fā)送EM_GETRECT消息來獲得

   Call SendMessage(mText.hwnd, EM_GETRECT, 0, rc)

   ‘進(jìn)行位置數(shù)據(jù)計算

   With Me.Font

      .Name = mText.Font.Name

      .Size = mText.Font.Size

      .Bold = mText.Font.Bold

   End With

   tmpTop = ((rc.Bottom - rc.Top) - (mText.Parent.TextHeight("H") \ Screen.TwipsPerPixelY)) \ 2

   tmpBot = ((rc.Bottom - rc.Top) + (mText.Parent.TextHeight("H") \ Screen.TwipsPerPixelY)) \ 2

   rc.Top = tmpTop

   rc.Bottom = tmpBot

   mText.Alignment = vbCenter

   ‘?dāng)?shù)據(jù)計算完畢,再發(fā)送EM_SETRECTNP消息(為一個編輯控件設(shè)置格式化矩形,,與EM_SETRECT類似,,只是控件此時不會重畫)

   Call SendMessage(mText.hwnd, EM_SETRECTNP, 0&, rc)

   mText.Refresh



End Sub

這樣我們就達(dá)到了文本垂直居中的目的,其實只要用的熟了,,找到切入點,,還是很容易實現(xiàn)的。

   調(diào)整邊距:

如果你查看TextBox中常用的消息,,你會發(fā)現(xiàn)有這樣一對消息:EM_GETMARGINS 和EM_SETMARGINS,,MSDN的解釋是:獲取和設(shè)置編輯控件的左、右邊距(不得用于NT3.51),。具體是左還是右由該消息的參數(shù)決定,。

看到這些也許你就知道我們可以用這兩個消息完成我們的需求,,好下面實際著手進(jìn)行驗證:

Private Sub SetMargin(nLeft As Integer, nRight As Integer, lhWnd As Long)

Dim lLongValue As Long



    ‘高四位表示右邊距,低四位為左邊距

    lLongValue = nRight * &H10000 + nLeft



    SendMessage lhWnd, EM_SETMARGINS, _

        EC_LEFTMARGIN Or EC_RIGHTMARGIN, lLongValue

End Sub

好經(jīng)過測試目的達(dá)到,,但是這樣做有什么意義呢,?有的時候如果你想在texebox中放入其他對象,而又不希望文本被覆蓋掉,,你就需要用到這個方法,。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多