对诸如 PowerBuilder (后文简写为 PB )、 Visual Basic 和 Dephi 等大多数可视化程序设计语言来讲,程序设计的核心是对象的事件、属性和方法,但对 Windows 系统本身而言,却是以消息处理为其控制机制。 Windows 把系统中的对象都作为窗口来对待,每个窗口都有一个用来标识其身份的句柄。 Windows 通过向窗口发送消息,在开发语言中转化为对象的事件,然后驱动对象,响应用户的动作。在许多面向对象的可视化程序设计语言中, Windows 的众多消息已经演变成了对象的属性或方法。本章内容包括 Windows 系统的消息机制、消息的发送、消息的应用实例等。
全面地讨论 Windows 的内部工作机制需要很大的篇幅,对于一般的 PB 用户当然没有必要深入了解所有的技术细节。 Windows 系统的工作机制,简单地说就是 3 个关键的概念:窗口、事件和消息。
不妨简单地将窗口看做带有边界的矩形区域。读者也许已经了解多种不同类型的窗口,如 Windows 系统的“资源管理器”窗口、文字处理程序中的文档窗口或者弹出提示有约会信息的消息对话框窗口等。除了这些最普通的窗口外,实际上还有许多其他类型的窗口。命令按钮是一个窗口,图标、文本框、选项按钮和菜单条也都是窗口。
Windows 操作系统通过给每一个窗口指定一个惟一的标识号(窗口句柄,常用 hWnd 表示)来管理所有的窗口。操作系统连续地监视每一个窗口的活动或事件的信号。事件可以通过诸如单击鼠标或按下按键的操作而产生,也可以通过程序的控制而产生,甚至可以由另一个窗口的操作而产生。
每发生一次事件,将引发一条消息发送至操作系统。操作系统处理该消息并广播给其他窗口。然后,每一个窗口才能根据自身处理该条消息的指令而采取适当的操作(例如,当窗口解除了其他窗口的覆盖时,重新绘制自身窗口)。
可以想象,处理各种窗口、事件和消息的所有可能的组合将有惊人的工作量。幸运的是, PB 使用户摆脱了所有的低层消息处理。许多消息由 PB 自动处理了,其他的作为事件过程由编程者自行处理,这样可以快速创建强大的应用程序,而毋需涉及不必要的细节。
在解释消息之前,首先了解系统如何准确地将消息发送到指定的窗口。当一个应用或多个应用运行后,会同时创建许多个窗口, Windows 作为系统的“大总管”,那么它又是如何识别每一个窗口呢?在程序设计时,通过窗口的名称属性,为每个窗口命名,然后在程序其他部分把窗口名作为识别窗口的标识。这种通过为窗口命名来识别不同窗口的方法,对 Windows 系统来讲显然是不现实的。 Windows 系统是通过称之为句柄的标识符来识别每一个窗口。
句柄是系统动态分配给窗口的 32 位整型数标识值,常用 hWnd 表示,即英文 handle to a window 的缩写。大量 API 函数都需要窗口句柄作参数,或返回一个窗口或设备场境的句柄。句柄可以通俗地理解为 Windows 为系统中所有存在的窗口动态分配的身份识别号码。
在 PB 中,可以通过 handle 函数来取得窗口和控件的句柄,当声明 API 函数时,常把保存句柄的变量声明为 Long 或 Ulong 长整型数据类型。 Windows 为窗口和控件分配句柄标识是动态,同样的程序每次运行时和在不同计算机上运行时所分配的窗口句柄标识可能是完全不一样的。
窗口的句柄属性仅能在运行时访问,该属性对窗口的外观并没有任何影响,它仅作为 API 函数调用的参数或返回值,或其他需识别窗口或对象的地方。在后面章节中,读者将会看到几乎所有涉及窗口的 API 函数都需要传递 hWnd 参数,以便函数准确获得用户要处理的窗口或对象。
句柄作为由操作系统定义的惟一的长整型值,可以用它来引用窗体和控件等对象。在 Windows 系统中, API 函数的调用常用的句柄包括窗口句柄,菜单句柄、设备对象句柄、设备场景句柄,等等。如果函数需要用句柄作为参数,则应该把参数声明为传值,对于返回句柄的 API 函数,应将返回的句柄值声明为 Long 或 Ulong 类型数据类型。句柄是一种标识符( ID )编号,而不是指针或者数值,不要试图对它们进行任何数学运算。
Windows 系统是以消息处理为其控制机制,系统通过消息为窗口过程( windows procedure )传递输入。系统和应用两者都可以产生消息。对于每个输入事件,例如用户按下了键盘上的某个键、移动了鼠标、单击了一个控件上的滚动条,等等,系统都将产生一系列消息。此外,对于应用带给系统的变化,如字体资源的改变、应用本身窗口的改变,系统都将通过消息以响应这种变化。应用通过产生消息指示应用的窗口完成特定的任务,或与其他应用的窗口进行通信。
每个窗口都有一个处理 Windows 系统发送消息的处理程序,称为窗口程序。它是隐含在窗口背后的一段程序脚本,其中包含对事件进行处理的代码。
Windows 系统为每条消息指定了一个消息编号,例如当一个窗口变为活动窗口时,它事实上是收到一条来自 Windows 系统的 WM_ACTIVATE 消息,该消息的编号为 6 ,它对应于 PB 窗口的 Activate 事件。对于窗口来说,诸如 Open 、 Activate 、 MouseDown 、 Resize 等事件,实际上对应的是窗口内部的消息处理程序,这些程序对于用户来讲是不可见的。类似地,命令按钮也有消息处理程序,它的处理程序响应诸如 WM_LBUTTONDOWN 和 WM_RBUTTONDOWN 之类的消息,即激活命令按钮的 MouseDown 事件。
系统向窗口发送的消息通常包含 3 个参数,分别是:
( 1 )窗口句柄( a window handle ):窗口句柄用来标识消息将要发送到的窗口对象,系统使用窗口句柄来确定哪一个窗口句柄应该接收该消息。
( 2 )消息标识符( a message identifier ):消息标识符是用来区分不同消息的命名常量,当窗口过程接收到一个消息时,它使用消息标识符来确定如何处理该消息。例如,消息标识符 WM_PAINT 告诉窗口过程“窗口的客户区已经发生变化,窗口必须进行重新绘制”。
( 3 )消息参数( message parameters ):消息参数用来表述窗口过程处理消息时所使用的数据或数据的位置,通常用一对参数表示。消息参数的意义和取值取决于消息。消息参数取值可以是整型数、 Bit 位标识、指向结构的指针,等等,当不需要使用消息参数时,通常将其设置为 NULL 。窗口过程必须通过检查消息标识符来确定如何对消息参数进行解释。
有关消息标识符、消息参数的具体使用,将在后面介绍 Sendmessage 函数时给予进一步 解释。
当系统与应用进行通信时,系统将发送或邮寄消息。系统通过这些消息控制应用的运行,并为应用的进程提供输入或其他信息。应用内部也可发送或邮寄系统定义的消息,应用通常使用这些消息控制由预先注册的窗口类创建的窗口的操作。
每一个系统定义的消息都有一个惟一的消息标识符(值),并用一个表明消息用途标识符常量表示(这些在 SDK 的头文件中定义)。如 WM_PAINT 消息标识符表示要求窗口进行重绘的消息。
消息标识符常量前缀表示消息所属的消息类别,如 WM_ 表示窗口类消息, BM_ 表示按钮类消息,表 1-1 给出了不同类别消息的前缀。
在 PB 中, 消息标识符常量通常声明为窗口或对象的实例常量,例如:
CONSTANT long WM_MOUSEMOVE = 512
CONSTANT long WM_LBUTTONDOWN = 513
CONSTANT long WM_LBUTTONUP = 514
CONSTANT long WM_LBUTTONDBLCLK = 515
CONSTANT long WM_RBUTTONDOWN = 516
CONSTANT long WM_RBUTTONUP = 517
CONSTANT long WM_RBUTTONDBLCLK = 518
表 1-1 Windows 系统定义的消息类别
消息标识符前缀 |
消息分类 |
ABM |
应用桌面工具栏消息 |
BM |
按钮控件消息 |
CB |
组合框控件消息 |
CBEM |
扩展组合框控件消息 |
CDM |
通用对话框消息 |
DBT |
设备消息 |
DL |
拖曳列表框控件消息 |
DM |
默认按钮控件消息 |
DTM |
日期时间选取控件消息 |
续表
消息标识符前缀 |
消息分类 |
EM |
编辑控件消息 |
HDM |
头控件消息 |
HKM |
热键控件消息 |
IPM |
IP 地址控件消息 |
LB |
列表框控件消息 |
LVM |
列表视图控件消息 |
MCM |
月历控件消息 |
PBM |
进度条控件消息 |
PGM |
Pager 控件消息 |
PSM |
属性页面消息 |
RB |
Rebar 控件消息 |
SB |
状态栏窗口消息 |
SBM |
滚动条控件消息 |
STM |
静态控件消息 |
TB |
工具栏消息 |
TBM |
跟踪条控件消息 |
TCM |
Tab 控件消息 |
TTM |
Tooltip 控件消息 |
TVM |
树形控件消息 |
UDM |
Up-down 控件消息 |
WM |
普通窗口消息 |
Windows 系统使用了成千上万条消息。从窗口到控件都有一组可接收和响应的消息。在 Visual Basic 的 API 浏览器中,以常量的方式列出了 Windows 的大部分消息。
据粗略统计,微软在 MSDN 中列出的消息约有数千种,全部弄清楚这么多种消息是不现实的,也是没有必要的。这是因为 PB 已经将很多消息封装为了对象的“属性”(例如窗口的 Title 和 WindowState 属性)和“方法(函数)”(例如关闭窗口函数 Close )。可以发现,消息可能演变成 PB 对象的属性、方法(函数)和事件。既然 PB 已经对消息进行了封装,那么又何必使用消息来进行程序设计呢?这时因为, PB 提供的事件、属性和方法并未完全涵盖所有消息,为了弥补 PB 在某些功能的不足,常使用系统消息或应用自定义的消息来强化 PB 的程序设计。
应用也可以创建自己的消息,并将消息应用于它的窗口或与其他窗口的进程进行通信。如果应用创建了自己的消息,接收消息的窗口过程必须解释消息,同时对消息进行恰当的处理。
系统保留的消息标识符的取值范围为 0x0000 ~ 0x03FF ( 0 ~ 1023 ),专门用于系统定义的消息;应用定义的消息不能使用这些值,应用定义的消息取值范围为 0x0400 ~ 0x7FFF ( 0 ~ 32767 )。
RegisterWindowMessage 函数提供了分配消息编号的功能,该函数用一个消息名称作为参数,并为这个名称分配一个惟一的、尚未使用过的编号。
Windows 应用程序允许应用程序向自己或其他应用程序发送消息,甚至可以向 Windows 操作系统本身发送消息(比如要求关闭操作系统或重新启动操作系统)。 Windows 提供了 2 个专门 用于发送消息的 API 函数 SendMessage 和 PostMessage 。
SendMessage 函数发送指定的消息到窗口或 Windows 系统,然后函数调用窗口的处理消息的过程,并等待窗口过程处理完消息后返回。
C 原型
LRESULT SendMessage (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam );
PB 声明
FUNCTION Long SendMessage (Long hwnd, Long wMsg, Long wParam, Long lParam) LIBRARY "user32.dll" ALIAS FOR "SendMessageA"
参 数
hWnd 为接收消息窗口的句柄;
wMsg 指定要发送的消息;
wParam 依赖于消息 wMsg 的其他信息;
lParam 依赖于消息 wMsg 的其他信息。
返回值
函数返回消息的处理结果,该值取决于消息的类型。
wParam 和 lParam 两个参数的含义随消息 wMsg 参数不同而改变,因此每当向窗口传递某种消息时,除了要了解该消息的含义外,还要注意 wParam 和 lParam 的含义和设置。
SendMessage 函数会返回一个 Long 值,由于这个函数是直接调用窗口程序,因此窗口程序可以返回一个值,把它作为 SendMessage 函数的返回值,这个返回值的具体含义由消息决定。不过,除非在 MSDN 明确列出了该消息的返回值,否则,返回值就没有具体意义,应该忽略。此外,在使用返回值时,通常调用 SendMessageTimeOut 函数检 查是否超时,因为只有在消息完全处理完毕后,才能得到一个有效返回值。
前面曾提到默认的窗口过程函数 DefWindowProc 用来处理应用程序无法处理的消息,该函数确保所有消息都要处理,无论这些消息是否对窗口有用。调用 DefWindowProc 函数时,需要传入与窗口消息处理过程相同的参数。
C 原型
LRESULT DefWindowProc ( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
PB 声明
FUNCTION Long DefWindowProc (Long hwnd,Long wMsg,Long wParam,Long lParam) LIBRARY "user32.dll" ALIAS FOR "DefWindowProcA"
参 数
hWnd 窗口句柄;
wMsg 指定要发送的消息;
wParam 依赖于消息 wMsg 的其他信息;
lParam 依赖于消息 wMsg 的其他信息。
返回值
函数返回消息的处理结果,该取决于消息的类型。
PostMessage 函数同 SendMessage 类似,它把消息放在指定窗口创建的线程的消息队列中,然后不等消息处理完就返回,而不像 SendMessage 那样必须等到消息处理完毕才返回。目标窗口通过 GetMessage 或 PeekMessage 从消息队列中取出并处理。
C 原型
LRESULT PostMessage ( HWND hWnd , UINT Msg , WPARAM wParam , LPARAM lParam );
PB 声明
FUNCTION Long PostMessage (Long hwnd,Long wMsg,Long wParam,Long lParam) LIBRARY "user32.dll" ALIAS FOR " PostMessageA"
参 数
hWnd 为接收消息窗口的句柄;
Msg 指定要发送的消息;
wParam 依赖于消息 Msg 的其他信息;
lParam 依赖于消息 Msg 的其他信息。
返回值
如果函数调用成功,函数返回值为非 0 ;如果调用失败,函数返回 0 。
示 例
下面代码演示了如何通过发送消息,在 PB 应用中关闭另外运行的第三方程序。
( 1 )运行 Windows 的系统的记事本程序 NotePad ,并创建一个未命名的文档。
( 2 )在 PB 中新建一个窗口,为窗口声明如下对象级外部函数和实例变量:
FUNCTION Long FindWindow(String lpClassName, String lpWindowName) LIBRARY "user32.dll" ALIAS FOR "FindWindowA"
FUNCTION Long PostMessage(Long hwnd, Long wMsg, Long wParam, Long lParam) LIBRARY "user32.dll" ALIAS FOR "PostMessageA"
Constant long WM_QUIT = 18
( 3 )在窗口上放置一个按钮控件,为按钮的 Clicked 事件加入如下脚本:
String ls_sTitle, pbNullString
Long ll_iHwnd, ll_ihTask
Long ll_iReturn
SetNull(pbNullString)
ls_sTitle = " 未定标题 – 记事本 "
ll_iHwnd = FindWindow(SetNull, ls_sTitle)
ll_iReturn = PostMessage(ll_iHwnd, WM_QUIT, 0, 0)
MessageBox(" 提示信息 "," 记事本已经关闭! ")
上述代码运行后,使用 FindWindow 函数获取 Windows 记事本程序窗口的句柄,然后向记事本窗口发送 WM_QUIT 消息,记事本程序将被关闭。
虽然在前面提到 Windows 系统会产生事件来驱动对象,但更严格的讲 Windows 先产生消息,然后由 PB 将其转化为驱动对象的事件。那么 PB 是如何将消息转换为事件呢?
1.1 节介绍了消息的概念。也可以通俗地将消息理解为由 Windows 操作系统送往程序的事件。它是系统中各个控件(窗口)沟通的方式。举例来说,当移动鼠标、按下鼠标键、改变窗口视窗大小时, Windows 都会送出消息以通知程序。当然,为了要辨别事件的内容, Windows 系统中预定义了许多的消息,如 WM_PAINT , WM_CHAR 等。
当事件发生时, Windows 系统根据窗口的身份码——句柄 hWnd ,判断该事件必须由哪个窗口接收,然后将事件以消息的方式送往程序的窗口中。虽然在 Windows 系统中包含了数以百计的事件,但是操作系统并没有为各个事件设计不同的消息结构,而是以一个一般性的结构来描述消息,
Windows 使用了一个特殊的函数来实现这一过程,这个函数的名称叫做“窗口处理函数”或者叫做“窗口消息处理函数”,该函数就是 WindowProc 。
LRESULT CALLBACK WindowProc(HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam ) ;
从函数的定义可以看出,任何要发送的消息都有 4 个参数,其中:
HWND hwnd ——发送窗口的句柄
UINT uMsg ——消息代码
Windows 中每一个消息都有惟一的一个代码。在 Visual Basic 的 API 文本浏览器中以常量的格式列出了所有消息名和代码,在 PB 中也可以直接利用 Visual Basic 的 API 文本浏览器列出的这些消息,惟一需要做的就是将 Visual Basic 十六进制消息代码转换为 PB 的十进制,如在 Visual Basic 声明定义的有关鼠标移动的消息:
Public Const WM_MOUSEMOVE = &H200
在 PB 中应声明为:
Constant Long WM_MOUSEMOVE = 512
WPARAM wParam 和 LPARAM lParam 为两个 32 位的长整型值,用来指定当前发送消息时所带信息,如在鼠标移动时返回鼠标的位置等。
当 Windows 有消息需要通知程序的时候,它就会调用该函数,然后自己的程序就从中检测发送的消息。 Windows 中消息的种类是很多的,不可能也没有必要检测所有的消息,只需要检测感兴趣的消息即可。检测消息的程序其实就是一个条件判断组合,如图 1.1 所示。
那么未处理的消息到那里去了? Windows 系统为窗口提供了默认的窗口过程 DefWindowProc ,这个窗口过程将负责处理那些不需要的消息。正因为有了这个默认窗口过程,才可以利用 Windows 的窗口进行开发,而不必过多关注窗口各种消息的处理。例如,窗口在被拖动时会有很多消息发送,可以不予理睬让系统自己去处理。
图 1.1 消息处理流程
从上面分析可以看出,事件驱动机制是针对诸如 PB 、 Visual Basic 这类面向对象的开发环境而言,在其背后隐含的是 Windows 系统的消息驱动机制,但 Windows 系统的消息驱动应用范围要比高级开发语言定义的事件驱动范围广泛的多。
在 PB 中,除了为窗口和控件预置的事件外, PB 还将 Windows 系统的许多消息封装为用户自选事件,根据与 Windows 系统的消息的对应关系,为每个事件定义了 EventID ,如图 1.2 所示。
当窗口或控件的预置事件无法满足程序设计要求时,可以使用这些自选事件。如在设备场景中绘制的位图,当窗口大小改变时,位图并不会自动重绘。这时就需要使用窗口的事件 ID 号位 pbm_paint 事件,该事件与窗口的 WM_PAINT 消息相对应,当窗口发生变化时强迫窗口重绘。在 PB 中,事件 ID 的作用是把 PB 的事件与系统消息联系起来,被用户的动作或其他系统活动触发的事件必须具有 ID 号。对于 PB 的系统对象,如窗口、按钮等控件,定义好的系统事件通常都使用 ID 号。
当用户使用自选事件时,可以使用如图 1.2 所示列在 Event Declaration 对话框中的事件 ID 号,用来响应某个系统消息。如果定义被系统消息触发的用户自选事件,可以从 ID 号列表中选择事件 ID 号。其中,列在 Event 对话框中的所有以 pbm_ 前缀开始的 ID 号,为映射到 PB 中的系统消息。在定义用户自选事件时,不能修改与事件 ID 号相关的参数及返回值,因为这些是整个事件 ID 号的具体组成部分。如果与事件 ID 号相应的系统消息发生时, PB 触发该事件,并为事件的参数赋值。如果用户自定义事件,并且与系统消息无关,则不为事件选择 ID 号。这样事件将不会被用户的动作或系统的活动触发,只能在应用中用脚本来触发。
图 1.2 PB 的用户自选事件
由于 PB 的技术开发文档中并未列出每个事件 ID 的具体含义及与 Windows 系统消息的对应关系,用户在使用这些自选事件时常常感到困惑。为此,笔者将这些事件与 Windows 系统的消息的对应关系及具体含义逐一进行了分析,这些 PB 的自选事件 ID 涵盖了窗口消息,以及按钮、组合框、列表框、编辑掩码等控件的消息,下面逐一列在表 1-2 ~ 1-8 中,供读者参考。
( 1 ) PB 的按钮自选事件及对应的系统消息,如表 1-2 所示。
( 2 ) PB 的组合框控件( ComBox )自选事件及对应的系统消息,如表 1-3 所示。
表 1-2 按钮事件及对应的系统消息
PB 的事件 ID |
对应的系统消息 |
消息作用 |
pbm_bmgetstate |
BM_GETSTATE |
按钮是否加亮 |
pbm_bmsetcheck |
BM_SETCHECK |
设置按钮的选中或未选中状态 |
pbm_bmsetstate |
BM_SETSTATE |
加亮或不加亮按钮 |
pbm_bnclicked |
BN_CLICKED |
按钮控件被单击 |
pbm_bndisable |
BN_DISABLE |
使按钮控件无效 |
pbm_bndoubleclicked |
BN_DOUBLECLICKED |
按钮控件被双击 |
pbm_bndragdrop |
BN_DRAGDROP |
一个对象被放到按钮控件 |
pbm_bndragenter |
BN_DRAGENTER |
一个对象被拖到按钮控件 |
pbm_bndragleave |
BN_DRAGLEAVE |
一个对象被拖离按钮控件 |
pbm_bndragover |
BN_DRAGOVER |
一个对象被拖经按钮控件 |
pbm_bnhilite |
BN_HILITE |
按钮控件被加亮 |
pbm_bnpaint |
BN_PAINT |
按钮控件被绘制 |
pbm_bnsetfocus |
BN_SETFOCUS |
按钮控件获得焦点 |
pbm_bnunhilite |
BN_UNHILITE |
按钮控件不被加亮 |
表 1-3 组合框事件及对应的系统消息
PB 的事件 ID |
对应的系统消息 |
消息作用 |
pbm_cbaddstring |
CB_ADDSTRING |
将字符串加到组合框 |
pbm_cbdeletestring |
CB_DELETESTRING |
从组合框删除一个字符串 |
pbm_cbdir |
CB_DIR |
加一个目录列表到组合框 |
pbm_cbfindstring |
CB_FINDSTRING |
搜索以一组字符开头的字符串 |
pbm_cbfindstringexact |
CB_FINDSTRINGEXACT |
搜索与所提供的字符完全匹配的字符串 |
pbm_cbgetcount |
CB_GETCOUNT |
列表框中的项数 |
pbm_cbgetcursel |
CB_GETCURSEL |
当前被选项的数目 |
pbm_cbgetdroppedcontrolset |
CB_GETDROPPEDCONTROLSET |
列表框在屏幕上的坐标位置 |
pbm_cbgeteditsel |
CB_GETEDITSEL |
编辑器控件中被选字符的范围 |
pbm_cbgetextendedui |
CB_GETEXTENDEDUI |
默认或扩展的用户界面 |
pbm_cbgetitemdata |
CB_GETITEMDATA |
重画的列表框中的 4 字节( 32 位)项 |
pbm_cbgetitemheight |
CB_GETITEMHEIGHT |
列表框中某一项的高度 |
pbm_cbgetlbtext |
CB_GETLBTEXT |
列表框中的文本 |
pbm_cbgetlbtextlen |
CB_GETLBTEXTLEN |
列表框中文本的长度 |
pbm_cbinsertstring |
CB_INSERTSTRING |
向列表框中插入新的字符串项 |
pbm_cblimittext |
CB_LIMITTEXT |
限制能被输入到列表框中的字符数 |
pbm_cbresetcontent |
CB_RESETCONTENT |
删除列表框中所有内容 |
pbm_cbselectstring |
CB_SELECTSTRING |
搜索匹配的字符串并显示 |
pbm_cbsetcursel |
CB_SETCURSEL |
在列表框中选择并显示一项 |
pbm_cbseteditsel |
CB_SETEDITSEL |
在列表框的编辑区域中选择一块文本 |
pbm_cbsetextendedui |
CB_SETEXTENDEDUI |
设置默认或扩展的用户界面 |
pbm_cbsetitemdata |
CB_SETITEMDATA |
在列表框中设定 4 字节( 32 位)项 |
pbm_cbsetitemheight |
CB_SETITEMHEIGHT |
设置列表框中项的高度 |
pbm_cbshowdropdown |
CB_SHOWDROPDOWN |
显示或隐藏列表框中下拉列表区域 |
pbm_cbndblclk |
CBN_DBLCLK |
用户在列表中某一项上双击鼠标 |
pbm_cbndragdrop |
CBN_DRAGDROP |
一个对象被放到组合框控件上 |
pbm_cbndragenter |
CBN_DRAGENTER |
一个对象被拖到组合框控件上 |
pbm_cbndragleave |
CBN_DRAGLEAVE |
一个对象被拖离组合框控件 |
pbm_cbndragover |
CBN_DRAGOVER |
一个对象被拖经组合框控件 |
pbm_cbndropdown |
CBN_DROPDOWN |
列表框的下拉区域即将被显示 |
pbm_cbneditchange |
CBN_EDITCHANGE |
编辑器控件中的文本发生变化 |
pbm_cbneditupdate |
CBN_EDITUPDATE |
列表框编辑器控件中的文本即将被改变 |
pbm_cbnerrspace |
CBN_ERRSPACE |
列表框满,不能再向其中加入项 |
pbm_cbnkillfocus |
CBN_KILLFOCUS |
通用列表框失去焦点 |
pbm_cbnselchange |
CBN_SELCHANGE |
列表框中被选文本被改变 |
pbm_cbnselendcancel |
CBN_SELENDCANCEL |
用户按下了“取消”按钮 |
pbm_cbnselendok |
CBN_SELENDOK |
用户按下了“确认”按钮 |
pbm_cbnsetfocus |
CBN_SETFOCUS |
通用对话控件拥有焦点 |
( 3 ) PB 的编辑控件( EditMask )自选事件及对应的系统消息,如表 1-4 所示。
( 4 ) PB 的列表框控件( ListBox )自选事件及对应的系统消息,如表 1-5 所示。
表 1-4 编辑控件事件及对应的系统消息
PB 的自选事件 ID |
对应的系统消息 |
消息作用 |
pbm_emcanundo |
EM_CANUNDO |
编辑器控件是否能撤消上一次修改 |
pbm_ememptyundobuffer |
EM_EM_PTYUNDOBUFFER |
清空由 Windows 管理的取消操作的缓冲区 |
pbm_emfmtlines |
EM_FMTLINES |
在多行编辑器控件的行尾增加或删除回车换行 |
pbm_emgetfirstvisibleline |
EM_GETFIRSTVISIBLELINE |
返回编辑器控件中可见的第一行的行号 |
pbm_emgethandle |
EM_GETHANDLE |
获得编辑器控件使用的内存句柄 |
pbm_emgetline |
EM_GETLINE |
从编辑器控件中复制一行到内存缓冲区 |
pbm_emgetlinecount |
EM_GETLINECOUNT |
返回多行编辑器控件的行数 |
pbm_emgetmodify |
EM_GETMODIFY |
文本是否被用户修改 |
pbm_emgetrect |
EM_GETRECT |
返回控件的长方形域 |
pbm_emgetsel |
EM_GETSEL |
返回被选文本的起始位置 |
pbm_emlimittext |
EM_LIMITTEXT |
限制用户键入的文本长度 |
pbm_emlinefromchar |
EM_LINEFROMCHAR |
返回被选文本的行号 |
pbm_emlineindex |
EM_LINEINDEX |
返回控件中被选行第一个字符在编辑串中的位置 |
pbm_emlinelength |
EM_LINELENGTH |
返回编辑器控件中被选行中的字符数 |
pbm_emlinescroll |
EM_LINESCROLL |
水平或垂直卷滚编辑器控件 |
pbm_emreplacesel |
EM_REPLACESEL |
从剪贴板或从键盘上用新文本替换被选文本 |
pbm_emsethandle |
EM_SETHANDLE |
设置编辑器控件的句柄 |
pbm_emsetmodify |
EM_SETMODIFY |
设置编辑器控件的 modified 标志 |
pbm_emsetpasswordchar |
EM_SETPASSWORDCHAR |
设置用户输入任何文本时显示的字符,在输入密码时的显示 |
pbm_emsetrect |
EM_SETRECT |
设置 / 重置编辑器控件所在的长方形区域 , 编辑器控件中的文本被重画 |
pbm_emsetrectnp |
EM_SETRECTNP |
除了不重画文本,大致与 setrect 相同 |
pbm_emsetsel |
EM_SETSEL |
选择字符 |
pbm_emsettabstops |
EM_SETTABSTOPS |
在多行编辑器控件中设置 tabstops |
pbm_emsetwordbreak |
EM_SETWORDBREAK |
设置新的词拆分函数 |
pbm_emsetwordbreakproc |
EM_SETWORDBREAKPROC |
设置新的词拆分过程 |
pbm_emundo |
EM_UNDO |
撤消最近的编辑操作 |
pbm_enchange |
EN_CHANGE |
编辑器控件中的文本发生改变 |
pbm_enerrspace |
EN_ERRSPACE |
编辑器控件内存缓冲区溢出 |
pbm_enhscroll |
EN_HSCROLL |
用户点中上水平滚动条 |
pbm_enmaxtext |
EN_MAXTEXT |
用户试图输入比允许更多的文本 |
pbm_enupdate |
EN_UPDATE |
编辑器控件即将显示用户的修改 |
pbm_envscroll |
EN_VSCROLL |
用户点中垂直滚动条 |
表 1-5 列表框控件事件及对应的系统消息
PB 的事件 ID |
对应的系统消息 |
消息作用 |
pbm_lbaddstring |
LB_ADDSTRING |
向列表框控件中增加一项或一个字符串 |
pbm_lbdeletestring |
LB_DELETESTRING |
从列表框中删除一项或一个字符串 |
pbm_lbdir |
LB_DIR |
用目录列表填充列表框 |
pbm_lbfindstring |
LB_FINDSTRING |
在列表框中搜索与所给字符串匹配的项 |
pbm_lbfindstringexact |
LB_FINDSTRINGEXACT |
在列表框中搜索与所给字符串精确匹配的项 |
pbm_lbgetcaretindex |
LB_GETCARETINDEX |
在列表框中搜索拥有焦点的项 |
pbm_lbgetcount |
LB_GETCOUNT |
确定列表框中的项数 |
pbm_lbgetcursel |
LB_GETCURSEL |
确定所选项是第几项 |
pbm_lbgethorizontalextent |
LB_GETHORIZONTALEXTENT |
获得列表框的宽度、计算水平卷滚 |
pbm_lbgetitemheight |
LB_GETITEMHEIGHT |
确定列表框控件中项的高度 |
pbm_lbgetitemrect |
LB_GETITEMRECT |
确定列表框的尺寸 |
pbm_lbgetsel |
LB_GETSEL |
获得列表框中当前所选的项 |
pbm_lbgetselcount |
LB_GETSELCOUNT |
在多选列表框中获得所选项的数目 |
pbm_lbgetselitems |
LB_GETSELITEMS |
用列表框中各自的项号填充给定的整数数组 |
pbm_lbgettext |
LB_GETTEXT |
获得列表框中当前所选项的文本 |
pbm_lbgettextlen |
LB_GETTEXTLEN |
获得列表框中当前所选项的文本中的字符数 |
pbm_lbgettopindex |
LB_GETTOPINDEX |
确定列表框中可见的最上面一项的项号 |
pbm_lbinsertstring |
LB_INSERTSTRING |
向列表框中加入一个新字符串 |
pbm_lbresetcontent |
LB_RESETCONTENT |
重置(消除)列表框中的内容 |
pbm_lbselectstring |
LB_SELECTSTRING |
搜索并加亮与所给字符匹配的字符串 |
pbm_lbselitemrange |
LB_SELITEMRANGE |
选择 / 取消列表框中某一范围中的项 |
pbm_lbsetcaretindex |
LB_SETCARETINDEX |
设置列表框中的某一项拥有焦点 |
pbm_lbsetcolumnwidth |
LB_SETCOLUMNWIDTH |
设置列表框中列的宽度 |
pbm_lbsetcursel |
LB_SETCURSEL |
在列表框中选择并加亮一项 |
pbm_lbsethorizontaltext |
LB_SETHORIZONTALTEXT |
设置列表框中被水平卷滚的单元数 |
pbm_lbsetitemdata |
LB_SETITEMDATA |
设置与列表框相关的 32 位 /4 字节值 |
pbm_lbsetitemheight |
LB_SETITEMHEIGHT |
设置列表框中项的高度 |
pbm_lbsetsel |
LB_SETSEL |
在列表框中选择一个字符串 |
pbm_lbsettabstops |
LB_SETTABSTOPS |
设置列表框控件中 tabstops 的位置 |
pbm_lbsettopindex |
LB_SETTOPINDEX |
滚动列表框使特定的项成为可见的最上面项 |
pbm_endblclk |
LBN_DBLCLK |
用户在列表框控件中的某一项上双击 |
pbm_enerrspace |
LBN_ERRSPACE |
用户试图超越可在列表框中输入字符的最大限制 |
pbm_enselcancel |
LBN_SELCANCEL |
当前选取文本被取消 |
pbm_enselchange |
LBN_SELCHANGE |
用户在列表框中选择或取消了一项 |
( 5 ) PB 的窗口自选事件及对应的系统消息,如表 1-6 所示。
表 1-6 窗口事件及对应的系统消息
PB 的事件 ID |
对应的系统消息 |
消息作用 |
|
pbm_activateapp |
WM_ACTIVATEAPP |
被激活的窗口属于另外一个应用 |
|
pbm_askcbformatname |
WM_ASKCBFORMATNAME |
要求剪贴板中的内容被复制到一个使用自定义格式的文本缓冲区中 |
|
pbm_char |
WM_CHAR |
传送键盘上按下的键 |
|
pbm_chartoitem |
WM_CHARTOITEM |
通过转换键盘来的字符,帮助列表框定位其中的项 |
|
pbm_childactivate |
WM_CHILDACTIVATE |
一个子窗口被移动或激活 |
|
pbm_clear |
WM_CLEAR |
用户要删除当前编辑器控件中的内容 |
|
pbm_command |
WM_COMMAND |
用户选择了一个菜单项、控件或使用了加速键 |
|
pbm_compacting |
WM_COMPACTING |
系统内存资源不足;当 Windows 占用了多于 1/8 的 CPU 时间紧缩内存时,产生这条消息 |
|
pbm_compareitem |
WM_COMPAREITEM |
当新项被加入列表框或组合框时产生此消息,系统用这条消息进行项之间的比较 |
|
pbm_ctlcolor |
WM_CTLCOLOR |
一个控件即将被绘制,可在此时改变控件的颜色 |
|
pbm_deadchar |
WM_DEADCHAR |
用户选择了一种非英语字符集或其他特殊字符集,这将改变下面将要输入的字符 |
|
pbm_deleteitem |
WM_DELETEITEM |
从列表框或组合框中移去一项 |
|
pbm_destroyclipboard |
WM_DESTROYCLIPBOARD |
剪贴板内容被清除 |
|
pbm_devmodechanged |
WM_DEVMODECHANGED |
WIN.INI 中的一个设备名被修改 |
|
pbm_drawclipboard |
WM_DRAWCLIPBOARD |
剪贴板内容发生改变 |
|
pbm_drawitem |
WM_DRAWITEM |
列表框或组合框的一项内容被改变 |
|
pbm_dropfiles |
WM_DROPFILES |
当鼠标左键在一个注册为拖放文件接受器的应用上释放时,发出该消息 |
|
pbm_erasebkgnd |
WM_ERASEBKGND |
窗口的客户区需要重画 |
|
pbm_fontchange |
WM_FONTCHANGE |
应用可用的字体数改变 |
|
pbm_getdlgcode |
WM_GETDLGCODE |
通知消息,说明当前使用哪种类型的键盘 |
|
pbm_getfont |
WM_GETFONT |
获取当前激活的字体 |
|
pbm_getminmaxinto |
WM_GETMINMAXINTO |
检索窗口可设置的最小或最大尺寸 |
|
pbm_gettext |
WM_GETTEXT |
从一个控件 ( 如按钮或编辑器控件 ) 中复制文本到一个内存缓冲区 |
|
pbm_gettextlength |
WM_GETTEXTLENGTH |
用来确定一个控件中的字符数 |
|
pbm_hscrollclipboard |
WM_HSCROLLCLIPBOARD |
剪贴板的水平滚动条被使用 |
|
pbm_iconerasebkgnd |
WM_ICONERASEBKGND |
一个最小化窗口需要重画背景 |
|
pbm_initdialog |
WM_INITDIALOG |
一个对话框即将被显示 |
|
pbm_initmenu |
WM_INITMENU |
一个菜单即将被显示 |
|
pbm_initmenupopup |
WM_INITMENUPOPUP |
一个弹出式窗口即将被显示 |
|
pbm_keydown |
WM_KEYDOWN |
键盘上的一个键被按下 |
续表
PB 的事件 ID |
对应的系统消息 |
消息作用 |
|
pbm_keyup |
WM_KEYUP |
键盘上的一个键被释放 |
|
pbm_mdiactive |
WM_MDIACTIVE |
一个 MDI 子窗口(窗口)被激活 |
|
pbm_mdicascade |
WM_MDICASCADE |
以重叠的形式重排所有的窗口 |
|
pbm_mdicreate |
WM_MDICREATE |
创建一个窗口 |
|
pbm_mdidestroy |
WM_MDIDESTROY |
从 MDI 框架中移去一个窗口 |
|
pbm_mdigetactive |
WM_MDIGETACTIVE |
获得当前活动的 MDI 窗口的句柄 |
|
pbm_mdiiconrange |
WM_MDIICONRANGE |
在一个 MDI 框架中重排最小化窗口的图标 |
|
pbm_mdimaximize |
WM_MDIMAXIMIZE |
最大化一个 MDI 子窗口 |
|
pbm_mdinext |
WM_MDINEXT |
激活下一个 MDI 子窗口(紧接着活动窗口的窗口) |
|
pbm_mdirestore |
WM_MDIRESTORE |
把 MDI 窗口恢复到它原来的大小 |
|
pbm_mdisetmenu |
WM_MDISETMENU |
将一个菜单与一个 MDI 窗口联系起来 |
|
pbm_mdifitle |
WM_MDIFITLE |
平铺所有的 MDI 窗口 |
|
pbm_measureitem |
WM_MEASUREITEM |
这个消息被送给即将创建的、内有按钮或其他控件的窗口 |
|
pbm_menuchar |
WM_MENUCHAR |
用户使用了一个快捷键 , 但系统不支持该快捷键 |
|
pbm_menuselect |
WM_MENUSELECT |
用户选择了一个菜单项 |
|
pbm_mouseactivate |
WM_MOUSEACTIVATE |
用户在一个非活动窗口中单击了鼠标 |
|
pbm_mousemove |
WM_MOUSEMOVE |
用户移动了鼠标 |
|
pbm_ncactivate |
WM_NCACTIVATE |
窗口的非客户区即将被激活 |
|
pbm_nccalcsize |
WM_NCCALCSIZE |
窗口的尺寸需要重新计算 |
|
pbm_nccreate |
WM_NCCREATE |
窗口即将创建它的非客户区 |
|
pbm_ncdestroy |
WM_NCDESTROY |
窗口的非共享区被析构 |
|
pbm_nchittest |
WM_NCHITTEST |
每次非客户区被移动时都发送该消息 |
|
pbm_nclbuttondblclk |
WM_NCLBUTTONDBLCLK |
用户在非客户区双击了鼠标 |
|
pbm_ncpaint |
WM_NCPAINT |
非客户需要画出 |
|
pbm_nextdlgctl |
WM_NEXTDLGCTL |
在对话框中将焦点转给另一个控件 |
|
pbm_paintclipboard |
WM_PAINTCLIPBOARD |
剪贴板应用有剪贴操作,剪贴板查看器需重画 |
|
pbm_paint |
WM_PAINT |
窗口的客户区需要被画出 |
|
PB 的事件 ID |
对应的系统消息 |
消息作用 |
|
pbm_palettechanged |
WM_PALETTECHANGED |
系统调色板被改变 |
|
pbm_paletteischanging |
WM_PALETTEISCHANGING |
系统调色板即将被改变 |
|
pbm_parentnotify |
WM_PARENTNOTIFY |
通知父窗口一个子窗口即将被创建 |
|
pbm_querydragicon |
WM_QUERYDRAGICON |
用户要拖动一个最小化窗口 |
|
pbm_queryendsession |
WM_QUERYENDSESSION |
通知消息,说明窗口即将被关闭 |
|
pbm_querynewpalette |
WM_QUERYNEWPALETTE |
应用即将收到输入焦点,应该执行必要的颜色调整 |
|
pbm_queryopen |
WM_QUERYOPEN |
一个最小化窗口即将被恢复 |
|
pbm_quit |
WM_QUIT |
应用处理的最后一个消息 |
续表
PB 的事件 ID |
对应的系统消息 |
消息作用 |
pbm_renderallformats |
WM_RENDERALLFORMATS |
通知一个剪贴板格式的拥有者,应用将失去所有的格式 |
pbm_renderformats |
WM_RENDERFORMATS |
通知消息,说明放在剪贴板中的数据应该用一种特殊格式传送 |
pbm_setcursor |
WM_SETCURSOR |
通知消息,说明鼠标指针在一个窗口中 移动 |
pbm_setfont |
WM_SETFONT |
用来设置对话框中的字体 |
pbm_setredraw |
WM_SETREDRAW |
设置窗口是否重绘 |
pbm_settext |
WM_SETTEXT |
用来设置窗口的标题栏文本 |
pbm_sizeclipboard |
WM_SIZECLIPBOARD |
剪贴板查看器应用改变尺寸 |
pbm_spoolerstatus |
WM_SPOOLERSTATUS |
一个打印管理器任务被添加或删除 |
pbm_syschar |
WM_SYSCHAR |
ALT 键和其他某键同时被按下 |
pbm_syscolorchange |
WM_SYSCOLORCHANGE |
一种或多种系统颜色被改变 |
pbm_syscommand |
WM_SYSCOMMAND |
窗口系统菜单控制消息 |
pbm_sysdeadchar |
WM_SYSDEADCHAR |
通知消息,说明一种非英语字符集被选定 |
pbm_syskeydown |
WM_SYSKEYDOWN |
用户按下某键的同时按下了 ALT 键 |
pbm_syskeyup |
WM_SYSKEYUP |
用户释放了 ALT 组合键 |
pbm_timechange |
WM_TIMECHANGE |
系统时钟被修改 |
pbm_undo |
WM_UNDO |
从 undo 缓冲区复制文本到编辑器控件 |
pbm_vkeytoitem |
WM_VKEYTOITEM |
当一个列表框拥有焦点时,用户按下了一个键 |
pbm_vscroll |
WM_VSCROLL |
用户单击了垂直滚动条 |
pbm_vscrollclipboard |
WM_VSCROLLCLIPBOARD |
剪贴板查看器的垂直滚动条被单击 |
pbm_windowposchanged |
WM_WINDOWPOSCHANGED |
窗口位置发生改变 |
pbm_windowposchanging |
WM_WINDOWPOSCHANGING |
窗口位置即将发生改变 |
pbm_wininichange |
WM_WININICHANGE |
WIN.INI 文件被修改 |
( 6 )数据窗口( datawindow )控件自选事件:数据窗口控件是 PB 特有的一种控件对象。该控件的自选事件对窗口或其他控件许多消息进行了封装,包括列表框消息、窗口鼠标消息、滚动条消息,等等。由于 Sybase 公司并未公布数据窗口的内部机制,因此与系统消息的对应关系不得而知,但从事件 ID 的名称可以略知一二,如 pbm_dwnlbuttondown 事件与鼠标的 WM_LBUTTONDOWN 消息相对应 。数据窗口具体自选事件及其作用如表 1-7 所示。
表 1-7 数据窗口事件
PB 的事件 ID |
消息作用 |
pbm_dwclosedropdown |
关闭下拉式数据窗口 |
pbm_dwscrollend |
在数据窗口中卷滚到最后一行 |
pbm_dwscrollhome |
在数据窗口中卷滚到第一行 |
续表
PB 的事件 ID |
消息作用 |
pbm_dwscrolllineend |
卷滚到当前行的行尾(水平方向) |
pbm_dwscrolllinehome |
卷滚到当前行的行首(水平方向) |
pbm_dwnbacktabout |
即将通过 Shift+Tab 组合键离开该控件 |
pbm_dwnchanging |
控件即将被改变 |
pbm_dwndropdown |
下拉式列表框的下拉部分即将可见 |
pbm_dwngraphcreate |
即将创建图形 |
pbm_dwnitemchangefocus |
数据窗口控件中当前项的焦点改变 |
pbm_dwnitemvalidationerror |
对当前项的修改引起了一个合法性检查错误 |
pbm_dwnkey |
有键被按下。使用 KeyDown() 处理键盘值 |
pbm_dwnlbuttondown |
鼠标左键被按下 |
pbm_dwnlbuttonup |
鼠标左键被松开 |
pbm_dwnmbuttonclk |
鼠标中键单击 |
pbm_dwnmbuttondbclk |
鼠标中键双击 |
pbm_dwnmousemove |
鼠标移动 |
pbm_dwnprintmarginchange |
打印边界被改变 |
pbm_dwnprocessenter |
回车键被按下 |
pbm_dwnrowchange |
数据窗口中焦点从一行转向另一行 |
pbm_dwntabdownout |
用户在数据窗口最后一行按了下箭头键 |
pbm_dwntabout |
用户在数据窗口的最后一行 / 列中按了 Tab 键 |
pbm_dwntabupout |
用户在数据窗口第一行中按了上箭头键 |
( 7 )动态数据交换( DDE )事件及对应的系统消息,如表 1-8 所示。
表 1-8 动态数据交换 (DDE) 事件及对应的系统消息
PB 的事件 ID |
对应的系统消息 |
消息作用 |
pbm_ddeddeack |
WM_DDE_ACK |
收到一个 DDE 消息 |
pbm_ddeddeinitiate |
WM_DDE_INITIATE |
开始一个 DDE 会话 |
pbm_ddeddeterminate |
WM_DDE_TERMINATE |
终止一个 DDE 会话 |