消息傳遞在VB中的應用
有些窗體在設計時會定義一些特殊的功能消息,而當我們傳遞這些消息給這類窗體時,這類窗口就會執行某段程序,并返回執行的結果。為了讓程序可以送出消息,Windows提供了SendMessage API函數。
| Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long |
hWnd:接收消息的窗口;
wMsg:消息的編號;
wParam:消息的第一個參數;
lParam:消息的第二個參數。
wParam及lParam參數的意義會隨著wMsg參數而變,因此我們要傳遞消息給某一個窗體時,除了了解該消息的意義外,還要了解wParam及lparam的意義。
lParam參數在SendMessage定義句中為"lParam As Any",因此它有以下幾中寫法:
當數值為 0 時,寫成:ByVal 0&
當為字符串常數 時,寫成:ByVal "字符串的內容"
當為字符串變量時,寫成:ByVal S
第一個實例:對窗體進行操作
下面我們對窗體的幾個消息進行解釋和應用:WM_GETTEXT:讀取窗體的Caption屬性;WMSETTEXT:設置窗體的Caption屬性;WM_SYSCOMMAND(wParam=SC_MAXIMIZE):將窗體的屬性設置為2;WM_SYSCOMMAND(wParam=SC_MINIMIZE):將窗體的屬性設置為1;WM_SYSCOMMAND(wParam=SC_RESTORE):將窗體的屬性設置為0;WM_SYSCOMMAND(wParam=SC_CLOSE):Unload窗體.
下面我們在窗體上放置幾個Command控件和一個Text控件:
![]() |
我們先把所需要的參數和API函數定義到模塊里面:
| Public Const WM_SYSCOMMAND = &H112 Public Const SC_CLOSE = &HF060& '關閉窗體 Public Const SC_MINIMIZE = &HF020& '最小化窗體 Public Const SC_MAXIMIZE = &HF030& '最大化窗體 Public Const SC_RESTORE = &HF120& '恢復窗體大小 Public Const WM_SETTEXT = &HC '設置窗體的Caption Public Const WM_GETTEXT = &HD '取得窗體的caption Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long 雙擊Command中放入: Private Sub Command_Click(Index As Integer) Dim S As String S = String(80, Chr(0)) Select Case Index Case 0 SendMessage Me.hwnd, WM_GETTEXT, Len(S), ByVal S '讀出窗體的Caption Text1.Text = Left(S, InStr(S, Chr(0)) - 1) Case 1 '因為Text1.text屬于Variant類型,所以一定先要用CStr把它轉換成字符串 SendMessage Me.hwnd, WM_SETTEXT, 0, ByVal CStr(Text1.Text)'設置窗體的Caption Case 2 SendMessage Me.hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, ByVal 0&'使窗體最大化 Case 3 SendMessage Me.hwnd, WM_SYSCOMMAND, SC_MINIMIZE, ByVal 0&'使窗體最小化 Case 4 SendMessage Me.hwnd, WM_SYSCOMMAND, SC_RESTORE, ByVal 0&'使窗體恢復原來的大小 Case 5 SendMessage Me.hwnd, WM_SYSCOMMAND, SC_CLOSE, ByVal 0&'關閉窗體 End Select End Sub |
第二個實例:TextBox的消息
| 消息 | 用途 |
| EM_LINESCROLL | 以行為單位,卷動TexBox |
| EM_SCROLL | 以行或頁為單位,卷動TexBox |
| EM_GETLINECOUNT | 讀取TextBox的總行數 |
| EM_GETLINE | 讀取某一行的字符串 |
| EM_LINEINDEX | 讀取某一行的第一個字符在TextBox中的索引 |
| EM_LINELENGTH | 讀取某一字符索引所在行次的"行字符數" |
| EM_CHARFROMPOS | 讀取鼠標所在位置的字符索引 |
| EM_SETSEL | 設置選取區域 |
在窗體上放置好相應的控件,如下:
![]() |
在模塊中定義好所需要的變量和函數:
| Public Const EM_SCROLL = &HB5 '以行或頁為單位,卷動TexBox Public Const SB_LINEUP = 0 '上卷一行 Public Const SB_LINEDOWN = 1 '下卷一行 Public Const SB_PAGEUP = 2 '上卷一頁 Public Const SB_PAGEDOWN = 3 '下卷一頁 Public Const EM_LINESCROLL = &HB6 '以行為單位,卷動TexBox Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long |
雙擊Command,寫入以下代碼:
| Private Sub Command_Click(Index As Integer) Select Case Index Case 0 SendMessage Text1.hwnd, EM_SCROLL, SB_PAGEUP, ByVal 0&'上卷一頁 Case 1 SendMessage Text1.hwnd, EM_SCROLL, SB_LINEUP, ByVal 0&'上卷一行 Case 2 SendMessage Text1.hwnd, EM_SCROLL, SB_LINEDOWN, ByVal 0&'下卷一行 Case 3 SendMessage Text1.hwnd, EM_SCROLL, SB_PAGEDOWN, ByVal 0&'下卷一頁 Case 4 'Text1.text用來輸入水平方向行數的TextBox,Text2.text:用來輸入垂直方向行數的TextBox '因為lParam采用"As Any"的定義方式,所以我們傳入是一定要將參數強制設置成Long類型 SendMessage Text1.hwnd, EM_LINESCROLL, Val(Text1.text), ByVal CLng(Val(Text2.text)) End Select End Sub |
第三個實例:ListBox的消息
| 消息 | 用途 |
| LB_SELECTSTRING | 選取開頭含有某個字符串的選項 |
| LB_FINDSTRING | 搜尋開頭含有某個字符串的選項 |
| LB_FINDSTRINGEXACT | 搜尋完全相符的選項 |
| SETHORIZONTALEXTENT | 設置水平滾動條的寬度 |
| LB_ITEMFROMPOINT | 檢測鼠標所在位置的選項 |
下面我們用一個例子來說明這些消息的具體用法:
在窗體上放置好一個Lable,Text,List,三個Command控件.并在List控件中輸入字母,且最少有一行要超出List的水平寬度。
![]() |
在模塊中定義相應的參數和函數:
| Option Explicit Public Const LB_FINDSTRING = &H18F '搜尋開頭含有某個字符串的選項 Public Const LB_FINDSTRINGEXACT = &H1A2 ‘搜尋完全相同的字符串的選項 Public Const LB_ITEMFROMPOINT = &H1A9 '檢測鼠標所在的位置的選項 Public Const WM_USER = &H400 Public Const LB_GETITEMHEIGHT = (WM_USER + 34)'取得List的行間高度 Public Const LB_SETITEMHEIGHT = &H1A0 '設置得List的行間高度 Public Const WM_SETREDRAW = &HB Public Const LB_SETHORIZONTALEXTENT = &H194 '設置水平滾動條 Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long 在Text1_Change中加入如下代碼: Private Sub Text1_Change() Dim Search As String, Index As Long Search = Text1.Text If Len(Search) > 0 Then Index = SendMessage(List1.hwnd, LB_FINDSTRING, -1, ByVal Search) '搜尋開頭含有某個字符串的選項 List1.ListIndex = Index Else List1.ListIndex = 0 End If End Sub '下面的代碼為設置水平滾動條的寬度 Private Sub Command2_Click() Dim max As Long, f As Font, i As Integer Me.ScaleMode = vbPixels ' 以像素為單位 Set f = Me.Font ' 保留窗體的Font Set Me.Font = List1.Font ' 將List1的Font設置給窗體,便可用窗體的TextWidth方法來計算ListBox每一個選項的寬度 With List1 For i = 0 To .ListCount If Me.TextWidth(.List(i)) > max Then max = Me.TextWidth(.List(i)) End If Next End With max = max + 10 ' Set Me.Font = f ' 還原窗體的Font SendMessage List1.hwnd, LB_SETHORIZONTALEXTENT, max, ByVal 0& End Sub '當我們的鼠標在List中移動時可以檢測鼠標所在的位置,其代碼如下: Private Sub List1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single) Dim lXPoint As Long Dim lYPoint As Long Dim lIndex As Long If Button = 0 Then ' 如果沒有按鈕被按下 lXPoint = CLng(X / Screen.TwipsPerPixelX)'List的寬度(以Pixel為單位) lYPoint = CLng(Y / Screen.TwipsPerPixelY)'List的高度(以pixel為單位) With List1 ' 獲得當前的光標所在的的屏幕位置確定標題位置 lIndex = SendMessage(.hwnd, LB_ITEMFROMPOINT, 0, ByVal ((lYPoint * 65536) + lXPoint)) ' 顯示提示行或清除提示行 If (lIndex >= 0) And (lIndex <= .ListCount) Then .ToolTipText = .List(lIndex) Else .ToolTipText = "" End If End With End If '我們也可以設置List的行間高度,代碼如下: Private Sub Command1_Click() Dim i As Long '返回 listbox高度 i = SendMessage((List1.hwnd), LB_GETITEMHEIGHT, 0, &O0) '在原高度中增加一個值 i = i + 3 '設置高度 i = SendMessage((List1.hwnd), LB_SETITEMHEIGHT, 0, ByVal i) i = SendMessage((List1.hwnd), WM_SETREDRAW, True, 0&) End Sub |
![]() |



