事件处理示例代码(二)

来源:互联网 发布:dvrnet监控软件 编辑:程序博客网 时间:2024/05/22 23:07

三、SendMessage函数应用(EM_/ LVM_开头的消息)

介绍关于RichTextBox(简称RTF)控件的消息和ListView控件的消息控制。

1.EM_开头的消息

Windows消息中,以EM_开头的消息是专门控制TextBox类控件和RTF类控件的。下面介绍的是如何利用 EM_ 消息实现向 RichTextBox 中粘贴文本和位图。在 EM_消息中,有一个 EM_PASTESPECIAL消息可以从剪贴板中获取文本或者位图类数据并拷贝到 RTF上。

运行程序,点击Command1,可以将剪贴板中的数据(位图或者文本)拷贝到RichTextBox1上。

EM_PASTESPECIAL消息中,wParam定义剪贴板数据类型,lParam定义一个 repastespecial类型的数据,其中的 dwAspect说明数据以何种方式显示到 RTF对象上,如果是 DVASPECT_CONTENT,则将整个数据显示在 RTF上,如果是 DVASPECT_ICON,则只在 RTF 上显示一个图标。

经试,repastespecial格式没有作用,因此参数4设为0即可。

Private Type repastespecialdwAspect As Long '显示方式dwParam As LongEnd TypeConst WM_USER = &H400Const EM_PASTESPECIAL = 1088Const CF_BITMAP = 2Const CF_TEXT = 1Const DVASPECT_CONTENT = 1Const DVASPECT_ICON = 4Private Sub Command1_Click()Dim re As repastespecialre.dwAspect = DVASPECT_CONTENTIf Clipboard.GetFormat(vbCFText) Then ''剪贴板中为文本信息Call SendMessage(RichTextBox1.hwnd, EM_PASTESPECIAL, CF_TEXT, re)ElseIf Clipboard.GetFormat(vbCFBitmap) Then ''剪贴板中为位图信息Call SendMessage(RichTextBox1.hwnd, EM_PASTESPECIAL, CF_BITMAP, re)End IfEnd Sub


 

2. LVM_开头的消息

ListView控件也是Windows界面开发中重要的控件,典型的应用就是Windows资源管理器中的文件列表。而在VB中,ListView控件包含在Microsoft Windows Common Control 6.0(也可能是5.0,视你的VB或者系统版本而定)中。在 Windows API中,有一系列的以 LVM_开头的消息值,这些消息就是扩展ListView控件所特定的消息值,下面的范例介绍如何通过LVM_消息设置ListView控件中图标的间距。范例如下:

Private Type RECTLeft As LongTop As LongRight As LongBottom As LongEnd TypeConst LVM_FIRST = &H1000Const LVM_SETWORKAREA = LVM_FIRST + 65Const LVM_SETICONSPACING = LVM_FIRST + 53Private Sub Form_Load()Dim xn As ListItemMe.ShowListView1.Width = 4500ListView1.Height = 3000ListView1.RefreshSet xn = ListView1.ListItems.Addxn.Text = "List1"Set xn = ListView1.ListItems.Addxn.Text = "List2"Set xn = ListView1.ListItems.Addxn.Text = "List3"Set xn = ListView1.ListItems.Addxn.Text = "List4"Set xn = ListView1.ListItems.Addxn.Text = "List5"Set xn = ListView1.ListItems.Addxn.Text = "List6"ListView1.RefreshCall SendMessage(ListView1.hwnd, LVM_SETICONSPACING, 0, ByVal (60 * 65536 + 190&))End Sub


    要运行上面的程序,首先要确保ListView1Arrange属性为1View属性为0。在上面的程序中,我们利用了 VM_SETICONSPACING 消息来控制图标间距。其中SendMessage中的参数lParam定义图标间距,高位为纵向间距,低位为横向间距,在上面的范例中,我们将图标的纵向间距定义为60像素,横向间距定义为190像素

 

四、SendMessage函数的应用

1,获得光标位置和字符个数.

Cpos = SendMessage(Text1.hwnd, 187, -1, 0) '光标所在行的首字符在文本中的位置
Lpos = SendMessage(Text1.hwnd, 201, Cpos, 0) '
光标所在的行号
Line = SendMessage(Text1.hwnd, 193, Cpos, 0) '
这行的字符数.

2.获取第N行的文本

Dim ST As String
ST = Space(110) '
必须要事先赋空格

Line=SendMessage(text1.hwnd,196, N-1, ByVal ST 'ST
返回获取到的文本,Line返回文本的长度字节数
'
下面的未成功
Dim str(256) As Byte, K As Integer
str(1) = 1 '
最大允许存放256个字符
K = SendMessage(Text1.hwnd, 196, 2, str(0)) '
获取第3行的数据放在str
Text1.Text = StrConv(str, vbUnicode) '
转换为字符串后显示

说明:在调用SendMessage获取第N行字符串时,lParam需要说明为字节数组,在调用完成后,再将字节数组转换为字符串;另外,调用前必须在lParam的前两个字节指明允许存放的最大长度,其中第一个字节为低位,第二个字节为高位,本例将高位(即str(1))置1.说明最大允许存放256个字符。

3.开关显示器.

SendMessage Handle, WM_SYSCOMMAND, SC_MONITORPOWER, 0 '关闭显示器.
SendMessage Handle, WM_SYSCOMMAND, SC_MONITORPOWER, -1 '
打开显示器

4.程序控制拉下或收起组合框的下拉列表

一般情况下,为了拉下或收起组合框的下拉列表,需要用键盘或鼠标进行操作,而有时我们希望程序运行的某个时刻自动拉出下拉列表(比如在一些演示程序中),为了实现这个目的,我们也只有借助于SendMessage函数,方法是发一个CB_SHOWDROPDOWN(&H14F)消息给组合框。

在发CB_SHOWDROPDOWN消息时,wParam参数决定了是拉下列表(=True)还是收起表(=False),lParam无用(设为0)。

为说明具体的使用方法,下面提供简单的程序片段:

Const CB_SHOWDROPDOWN = &H14F

当程序中某处需要拉下组合框Combol的列表时,调用如下语句:

SendMessage Combol.hwnd, CB_SHOWDROPDOWN, True, 0

当需要收起组合框Combol的列表时,调用如下语句:

SendMessage Combol.hwnd, CB_SHOWDROPDOWNN, False, 0

5.返回控件中显示的第一行的行号。

LineNo = SendMessageBynum(CTextBox.hwnd, EM_GETFIRSTVISIBLELINE, 0, 0)

6.下面的函数能够滚动控件,不过在滚动之前最好判断控件的文本行数和能够显示的行数,以免滚动时发生混乱的函数SendMessageBynumSendMessage函数的安全声明函数 , 其定义与SendMessage函数完全相同 , 只是函数名不同

Function ScrollTextBox(CTextBox As TextBox, nVal As Long, Optional nVertical As Boolean = True) As Long
If nVertical Then
ScrollTextBox = SendMessageBynum(CTextBox.hwnd, EM_LINESCROLL, 0, nVal)
Else
ScrollTextBox = SendMessageBynum(CTextBox.hwnd, EM_LINESCROLL, nVal, 0)
End If
End Function

7.下面的函数将返回控件能显示的行数:(经试,总是引起程序崩溃)

'获取当前字体的矩形区域(即字体的高度与平均宽度等信息)
Private Declare Function GetTextMetrics Lib "gdi32" Alias "GetTextMetricsA" (ByVal hDC As Long, lpMetrics As TEXTMETRIC) As Long
Private Type TEXTMETRIC
tmHeight As Long '
字符高度
tmAscent As Long '
字符上部高度(基线以上)
tmDescent As Long '
字符下部高度(基线以下
)
tmInternalLeading As Long '
tmHeight定义的字符高度的顶部空间数目

tmExternalLeading As Long '
加在两行之间的空间数目
tmAveCharWidth As Long '
平均字符宽度
tmMaxCharWidth As Long '
最宽字符的宽度
tmWeight As Long '
字体的粗细轻重程度
tmOverhang As Long '
加入某些拼接字体上的附加高度
tmDigitizedAspectX As Long '
字体设计所针对的设备水平方向
tmDigitizedAspectY As Long '
字体设计所针对的设备垂直方向
tmFirstChar As String '
为字体定义的第一个字符
tmLastChar As String '
为字体定义的最后一个字符
tmDefaultChar As String '
字体中所没有字符的替代字符
tmBreakChar As String '
用于拆字的字符
tmItalic As Byte '
字体为斜体时非零
tmUnderlined As Byte '
字体为下划线时非零
tmStruckOut As Byte '
字体被删去时非零
tmPitchAndFamily As Byte '
字体间距(4)和族(4)
tmCharSet As Byte '
字体的字符集

End Type
Type RECT
Left As Long
Top As Long
Right As Long
bottom As Long
End Type
Public ST As String
Function GetVisibleLines(CTextBox As TextBox) As Long
Dim rc As RECT '
以象素为单位
Dim tm As TEXTMETRIC
Dim hDC&, lfont&, oldfont&
Dim di&, lc&
lc = SendMessage(CTextBox.hwnd, EM_GETRECT, 0, rc)
lfont = SendMessage(CTextBox.hwnd, WM_GETFONT, 0, 0)
hDC = GetDC(CTextBox.hwnd)
If lfont <> 0 Then oldfont = SelectObject(hDC, lfont)
di = GetTextMetrics(hDC, tm)
If lfont <> 0 Then lfont = SelectObject(hDC, oldfont)
GetVisibleLines = (rc.bottom - rc.Top) / tm.tmHeight
di = ReleaseDC(CTextBox.hwnd, hDC)
End Function

8.设置控件的左边距。

Public Const EM_SETMARGINS& = &HD3
Public Const EC_LEFTMARGIN& = &H1
Function SetMargins(CTextBox As TextBox, nVal As Long) As Long
SetMargins = SendMessageBynum(CTextBox.hwnd, EM_SETMARGINS, EC_LEFTMARGIN, nVal)
End Function

9.利用SendMessage函数还可以实现一些有趣的效果:

例如在按钮的Click事件中加入如下语句:

SendMessage(Command1.hWnd,BM_SETSTYLE,BS_RADIOBUTTON,1)'BM_SETSTYLE = &HF4,BS_RADIOBUTTON = &H4

运行后点击按钮,就可以把按钮变成一个收音机按钮(经试,变成一个圆孔,有点象单选按纽)。

如要得到圆形或椭圆形按纽可使用另外2API函数:

hDC = CreateEllipticRgn(3, 3, 25, 25) '试验成功,这两个函数也用于创建圆形窗体
SetWindowRgn Command1.hwnd, hDC, True
DeleteObject hDC

10.窗体操作

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
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: Text1 = Left(S, InStr(S, Chr(0)) - 1) '
读出窗体的
Caption
Case 1: SendMessage Me.hwnd, WM_SETTEXT, 0, ByVal CStr(Text1.Text) '
设置窗体的Caption,由于Text1.text属于Variant类型,所以一定先要用CStr把它转换成字符串

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

11.文本垂直居中:

实现这个效果,首先TextBoxMultiLine属性必须为True(多行文本,其实这个属性关系创建了TextBox内部使用的是哪个类。因此它一旦创建就不能在代码中修改这个属性)

Public Sub VerMiddleText(mText As TextBox)
Dim rc As RECT '
以象素为单位

Dim tmpTop As Long
Dim tmpBot As Long
If mText.MultiLine = False Then Exit Sub
Call SendMessage(mText.hwnd, EM_GETRECT, 0, rc) '
获得窗口区域的边界
'
进行位置数据计算
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
'
数据计算完毕,再发送EM_SETRECTNP消息(为一个编辑控件设置格式化矩形,EM_SETRECT类似,只是控件此时不会重画)
Call SendMessage(mText.hwnd, EM_SETRECTNP, 0&, rc)
mText.Refresh
End Sub

12.调整边距:

如果你查看TextBox中常用的消息,你会发现有这样一对消息:EM_GETMARGINS EM_SETMARGINSMSDN的解
释是:获取和设置编辑控件的左、右边距(不得用于NT351)。具体是左还是右由该消息的参数决定。

这样做有什么意义呢有的时候如果你想在texebox中放入其他对象,而又不希望文本被覆盖掉,你就需要用到这个方法

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

五、SendMessage函数应用(RichEdit控件)

RichEdit控件的正文操作

A正文搜索

RichEdit控件具有几种正文操作,搜索指定正文就是其中的一种。搜索正文是通过发送EM_FINDTEXT或者 EM_FINDTEXTEX消息来完成的。这两个消息有一点很小的不同点。

1.EM_FINDTEXT

wParam=搜索选项,可以是下面3个参数的任意组合值(这些选项对 EM_FINDTEXT EM_FINDTEXTEX都是一样的)

FR_DOWN(&H1):搜索方向。如果指定了这个标志值,搜索操作从当前选定的 end 位置开始,直到控件中正文的 end位置结束(向下搜索)。这个标志影响 RichEdit 2.0 和以后版本,是 RichEdit 1.0的缺省行为。RichEdit 2.0或以后版本的缺省行为是:在当前选定正文内的从结尾搜索到开始位置(向前搜索)。概括来说就是,如果你使用 RichEdit 1.0, 无论你做什么都没法影响搜索的方向,它总使用向后搜索。但是如果你使用 RichEdit 2.0而且你想使用向后搜索的话,你必须指定这个标志值,否则使用的是向前搜索了。

FR_MATCHCASE (&H4):区分大小写

FR_WHOLEWORD (&H2):匹配指定搜索串的整个词

lParam = FINDTEXT结构的指针。
Type FINDTEXT 'STRUCT
chrg As CHARRANGE '
lpstrText As Long
End Type
chrg
是一个 CHARRANGE结构,其定义如下:
Type CHARRANGE 'STRUCT
cpMin As Long '
包含字符数组中第一个字符的字符索引
cpMax As Long '
包含紧跟在字符数组中最后一个字符的字符的字符索引
End Type

基本上,要搜索一个正文串,你必须指定要搜索的字符范围。cpMin cpMax的具体意义根据搜索是向后还是向前是不同的

如果是向后搜索,cpMin指定搜索的开始字符索引,而 cpMax则是结束字符索引。

如果是向前搜索,则反过来才对,也就是说 cpMin包含结束字符索引而cpMax包含开始字符索引。

lpstrText是要搜索的正文串的指针

2.EM_FINDTEXTEX

返回控件中跟搜索串匹配的的正文串的一个字符的索引。如果没找到匹配的则返回 -1

wParam =搜索选项,跟 EM_FINDTEXT的一样。

lParam = FINDTEXTEX结构的指针。

Type FINDTEXTEX 'STRUCT
chrg As CHARRANGE '
lpstrText As Long
chrgText CHARRANGE 'CHARRANGE
End Type

FINDTEXTEX中开始的两个成员是跟 FINDTEXT结构中的一样的。

chrgText是一个 CHARRANGE结构,如果搜索到匹配串的话,其开始/结束字符索引会被填入这个结构中。

EM_FINDTEXTEX的返回值跟 EM_FINDTEXT的是一样的。

EM_FINDTEXT EM_FINDTEXTEX的不同处:

FINDTEXTEX结构有一个另外的chrgText成员,如果搜索到匹配串的话,其开始/结束字符索引会被填入这个成员中。如果我们想对这个正文串进行更多的正文操作的话,有这个就方便多了。

B替换/插入正文

RichEdit控件提供了 EM_SETTEXTEX来进行正文替换/插入操作。这个消息混合了 WM_SETTEXT EM_REPLACESEL的功能.它具有以下语法:

wParam = SETTEXTEX结构的指针。

Type SETTEXTEX 'STRUCT
flags As Long
codepage As Long
End Type

flags可以是以下值的组合:

ST_DEFAULT删除Undo堆栈,丢弃RTF格式,替换所有的正文。

ST_KEEPUNDO保留Undo堆栈

ST_SELECTION替换选定正文并且保留RTF格式

codepage是一个常量,指定你的正文想要的代码页。我们通常简单的使用 CP_ACP

C正文选择

我们可以使用消息 EM_SETSEL或者 EM_EXSETSEL来编程选择正文.其中任意的一个都可以工作的很好。

要使用哪一个消息要根据可用的字符索引格式来选择。如果它们保存在一个 CHARRANGE结构中,则使用EM_EXSETSEL更容易实现

EM_EXSETSEL

wParam =没有使用,必须为 0

lParam = CHARRANGE结构的指针,包含想要选定的正文字符范围。

D事件通知

在使用多行Edit控件时,你必须子类化它以便得到输入信息象鼠标/键盘事件等。RichEdit控件提供了一个更好的方案,它可以把这些消息通知父窗口。为了注册得到通知消息,父窗口发送 EM_SETEVENTMASK消息

RichEdit控件,指定它对哪些消息感兴趣。

EM_SETEVENTMASK具有以下的语法:

wParam没有使用,必须为 0
lParam =
事件掩码值,可以是以下标志值的任意组合:
ENM_CHANGE
发送 EN_CHANGE通知
ENM_CORRECTTEXT
发送 EN_CORRECTTEXT通知
ENM_DRAGDROPDONE
发送 EN_DRAGDROPDONE通知
ENM_DROPFILES
发送 EN_DROPFILES通知
ENM_KEYEVENTS
为键盘消息发送 EN_MSGFILTER 通知
ENM_LINK Rich Edit 2.0
或以后版本:当鼠标在具有 CFE_LINK风格的正文上面移过,而且执行了一个
或几个鼠标动作时,就发送 EN_LINK通知。
ENM_MOUSEEVENTS
为鼠标消息发送 EN_MSGFILTER通知。
ENM_OBJECTPOSITIONS
发送 EN_OBJECTPOSITIONS通知
ENM_PROTECTED
发送 EN_PROTECTED通知
ENM_REQUESTRESIZE
发送 EN_REQUESTRESIZE通知
ENM_SCROLL
发送 EN_HSCROLL EN_VSCROLL通知
ENM_SCROLLEVENTS
为鼠标滑轮发送 EN_MSGFILTER通知。
ENM_SELCHANGE
发送 EN_SELCHANGE通知
ENM_UPDATE
发送 EN_UPDATE通知
Rich Edit 2.0
和以后版本:这个标志值会被忽略,而经常发送 EN_UPDATE通知。然而如果 RichEdit
3.0
模拟 RichEdit 1.0的话,你必须使用这个标志值来发送 EN_UPDATE 通知

上面的所有通知都被做为 WM_NOTIFY消息来发送:你必须检查 NMHDR结构的 code成员来得到通知消
息。譬如,如果你想注册得到鼠标消息(也就是说,你想提供一给上下文相关的弹出菜单)