在 Qt 中处理平台相关的底层事件.docx
- 文档编号:9754949
- 上传时间:2023-02-06
- 格式:DOCX
- 页数:15
- 大小:83.56KB
在 Qt 中处理平台相关的底层事件.docx
《在 Qt 中处理平台相关的底层事件.docx》由会员分享,可在线阅读,更多相关《在 Qt 中处理平台相关的底层事件.docx(15页珍藏版)》请在冰豆网上搜索。
在Qt中处理平台相关的底层事件
在Qt中处理平台相关的底层事件
文档选项
TopofForm
未显示需要JavaScript的文档选项
BottomofForm
级别:
中级
涂波(tubo@),软件开发工程师,IBM中国软件开发中心
田晓燕(tianxyan@),软件开发工程师,IBM中国软件开发中心
路绪清(luxuqing@),软件开发工程师,IBM中国软件开发中心
任谦(renqian@),软件开发工程师,IBM中国软件开发中心
2007年1月28日
事件是由窗口系统或Qt本身对各种事务的反应而产生的。
当用户按下一个键或者鼠标按钮,就会相应产生一个键盘或者鼠标事件。
当窗口第一次显示,会产生一个绘图事件,从而通知最新的可见窗口绘制自身。
使用Qt编程时,很少需要考虑事件,因为Qt的窗口组件会在事件发生的时候发送信号,然后利用Signal-Slot机制进行相应的事件处理。
但是,在编写自定义Widget或者需要修改现有Widget的特性时,或者需要处理平台相关的底层事件时,事件则变得很重要。
本文以XWindow平台为例,介绍Qt如何处理平台相关的底层事件。
1.Qt中与平台相关的宏定义
Qt提供了以下标识系统的宏定义,如表1所示:
表1.Qt提供的系统标识宏定义
系统标志
对应的平台
Q_WS_WIN
Windows
Q_WS_X11
XWindow
Q_WS_MAC
Mac
如果项目中调用了平台相关的APIs,那么利用条件编译,使得源程序不用修改,就可以适用于不同的平台。
对于XWindow平台,代码片断如清单1所示:
清单1.
#ifdefined(Q_WS_X11)
//与XWindow相关的nativeAPIs
#endif
对于Windows平台,代码片断如清单2所示:
清单2.
#ifdefined(Q_WS_WIN)
//与Windows相关的nativeAPIs
#endif
对于MAC平台,代码片断如清单3所示:
清单3.
#ifdefined(Q_WS_MAC)
//与Mac相关的nativeAPIs
#endif
2.Xlib与XEvent
Xlib是XWindow提供的API集合,Xlib之上是XtIntrinsicslibrary,Xt采用面向对象的设计方法,提供了大量的widgets。
在Xt之上则是各种各样的toolkits,最常用的是Motif。
Qt没有对Xt进行封装,而是直接建立在Xlib之上。
Xlib用一个叫"XEvent"的结构来保存从X服务器那里接收到的事件。
Xlib提供了大量的事件类型。
XEvent包括事件的类型,以及与事件相关的数据。
Qt也定义了一组事件类。
其中QEvent是基类。
其他具体事件类,例如QMouseEvent、QKeyEvent、QFocusEvent、QPaintEvent、QMoveEvent、QResizeEvent等都是从QEvent继承而来。
多数情况下,利用Qt的事件机制,能够满足我们的需求。
但是,在某些特定的情况,我们需要能够截获XWindow的底层事件,并对其进行处理。
本文介绍了两种截获XEvent的方法,一种是重载QApplication的x11EventFilter()方法;另一种是重载QWidget的x11Event()方法。
文中提供的例子基于Qt4.3,并在FedoraCore6上调试通过。
3.QApplication:
:
x11EventFilter()如何工作
QApplication类管理Qt应用程序的控制流和主要设置。
它包含了主事件循环,对来自窗口系统的所有事件进行处理和调度。
它也处理应用程序的初始化和结束,并且提供对话管理。
QApplication中定义了针对XWindow平台的虚函数,如清单4所示:
清单4.
boolQApplication:
:
x11EventFilter(XEvent*)
创建QApplication的子类,并且重新实现函数x11EventFilter(),那么所有底层的XEvent会首先被函数x11EventFilter()截获。
如果希望在函数x11EventFilter()中针对某事件进行响应,那么在响应结束后返回TRUE,表示该事件不会被分派到QApplication的Qt主事件循环中。
如果函数返回FALSE,那么该事件会被继续分派到QApplication的Qt主事件循环中,由Qt包装成Qt事件。
此外,针对Windows平台,QApplication定义了类似的虚函数,如清单5所示:
清单5.
boolQCoreApplication:
:
winEventFilter(MSG*msg,long*result)
针对Mac平台,QApplication定义了类似的虚函数,如清单6所示:
清单6.
boolQApplication:
:
macEventFilter(EventHandlerCallRefcaller,EventRefevent)
下面通过一个例子说明,如何在Qt中处理XEvent。
该例子包括两个可执行程序,一个是xclient,另一个是qtx11filter。
xclient基于Xlib,向qtx11filter发送XClientMessageEvent。
qtx11filter截获所有的XEvent,但只对XClientMessageEvent进行处理,将其它所有类型的XEvent都分派到QApplication的Qt主事件循环中。
3.1xclient的主要流程和源代码
xclient的主要流程如下:
1.用户通过命令行输入16进制的windowID。
2.向该windowID所在的窗口发送XClientMessageEvent。
该事件所携带的数据是一个长度为4的字符串”2008”。
xclient的完整源代码xclient.c如清单7所示:
清单7.
#include
#include
#include
charline[80];
unsignedlongwinID,mask;
XEventev;
Display*disp;
Statusstatus;
intmain(intargc,char*argv[]){
disp=XOpenDisplay(NULL);
if(!
disp){
perror("UnabletoopenXdisplay");
exit
(1);
}
do{
printf("Enteraline:
");
fgets(line,80,stdin);
if(line[0]!
='q'){
winID=strtol(line,NULL,16);
printf("Youentered%d:
0x%x\n",winID,winID);
ev.xclient.type=ClientMessage;
ev.xclient.window=winID;
ev.xclient.message_type=0;
ev.xclient.format=8;
ev.xclient.data.b[0]='2';
ev.xclient.data.b[1]='0';
ev.xclient.data.b[2]='0';
ev.xclient.data.b[3]='8';
ev.xclient.data.b[4]='\0';
mask=0l;
status=XSendEvent(disp,winID,False,mask,&ev);
printf("TheXSendEventreturned:
%d\n",status);
XFlush(disp);
}
}while(line[0]!
='q');
}
在FedoraCore6中,利用如下命令编译xclient:
清单8.
gccxclient.c–oxclient–lX11
3.2qtx11filter的主要流程和源代码
qtx11filter的主要流程如下:
1.创建QApplication的子类App,并实现虚函数x11EventFilter。
注意使用宏定义Q_WS_X11,因为x11EventFilter只适用于XWindow。
2.在x11EventFilter中,判断所截获的XEvent,如果事件类型为ClientMessage,那么打印出该事件发送者的windowID,并且打印出该事件所携带的数据。
3.在main()函数中,创建类App的实例,并且通过调用app.exec(),启动Qt主事件循环。
qtx11filter的完整源代码qtx11filter.c如清单9所示:
清单9.
#include
#include
#include
#include
#include
classApp:
publicQApplication{
public:
App(intargc,char**argv):
QApplication(argc,argv){}
#ifdefined(Q_WS_X11)
boolx11EventFilter(XEvent*xe){
switch(xe->type){
caseClientMessage:
printf("CaughtClientMessageXEventfromWindow%d\n",xe->xclient.window);
printf("Receivemessage:
%s\n",xe->xclient.data.s);
returntrue;
}
returnfalse;
}
#endif
};
classDialog:
publicQDialog{
public:
Dialog(QWidget*parent=0):
QDialog(parent){
QPushButton*done=newQPushButton("Done",this);
connect(done,SIGNAL(clicked()),qApp,SLOT(quit()));
}
};
intmain(intargc,char**argv){
Appapp(argc,argv);
Dialogdialog;
app.setMainWidget(&dialog);
dialog.show();
returnapp.exec();
}
在FedoraCore6中,用以下命令编译qtx11filter:
清单10.
g++qtx11filter.c-L/usr/lib/qt-3.3/lib-I/usr/lib/qt-3.3/include
-lqt-mt–lX11-oqtx11filter
3.3演示xclient和qtx11filter
1.在终端启动qtx11filter
清单11.
./qtx11filter
弹出仅包含一个按钮的窗口,如图1所示:
图1.qtx11filter窗口
2.在终端启动xwininfo,如图2所示:
图2.xwininfo窗口
3.将光标移动到窗口qtx11filter,点击鼠标左键,xwininfo可以获取qtx11filter的windowID,如图3所示(截图中已经用红色方框标出)。
图3.获取qtx11filter的windowID
4.在终端启动xclient,并输入qtx11filter的windowID,如图4所示。
然后,xclient会向qtx11filter发送XClientMessageEvent,该事件携带一个四字节的字符串”2008”。
图4.输入qtx11filter的windowID
5.打开运行qtx11filter的终端,qtx11filter已经从windowID为39845889的窗口接收到一个XClientMessageEvent,并读取出该事件所携带的数据”2008”,如图5所示:
图5.qtx11filter处理XClientMessageEvent
4.QWidget:
:
x11Event()如何工作
QWidget是Qt所有用户界面对象的基类。
它从窗口系统接收鼠标、键盘和其它事件,并且在屏幕上绘制自己。
QWidget定义了针对XWindow平台的虚函数:
清单12.
boolQWidget:
:
x11Event(XEvent*)
创建QWidget或者其已有派生类的子类,并且重新实现函数x11Event(),那么所有发送到该Widget的XEvent首先被函数x11Event()截获。
如果希望在函数x11Event()中针对某事件进行响应,那么在响应结束后返回TRUE。
如果函数返回FALSE,那么该事件会被包装成Qt事件,发送给Widget。
QWidget:
:
x11Event(XEvent*)和QApplication:
:
x11EventFilter(XEvent*)的区别在于:
前者在XEvent发送到特定QtWidget之前,被该Widget截获;后者在XEvent发送到整个程序的主事件循环之前,被QApplication截获。
5.Qt中其它与平台相关的APIs
在每个平台上,Qt都为QWidget提供了一个winId()函数,返回该QtWidget的windowID;QWidget还提供了一个静态函数find(),该函数可以返回一个特定windowID所对应的QtWidget。
我们可以将获得的windowID传递给NativeAPI来执行平台特定的操作。
此外,针对XWindow,Qt提供了类X11Info,用以获取XWindow平台的信息。
例如,通过调用静态成员函数X11Info:
:
display()可以获取Qt程序与Xserver建立的连接句柄。
参考资料
∙Qt官方网站
∙Xorg官方网站
∙Qt兴趣邮件列表
∙Qt的信号与槽机制介绍
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Qt 中处理平台相关的底层事件 处理 平台 相关 底层 事件