有些窗體在設計時會定義一些特殊的功能消息,而當我們傳遞這些消息給這類窗體時,這類窗口就會執行某段程序,並返回執行的結果。為了讓程序可以送出消息,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