首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

在 Qt 中处理平台相关的底层事件(2)

在 Qt 中处理平台相关的底层事件(2)

3. QApplication::x11EventFilter() 如何工作        QApplication 类管理 Qt 应用程序的控制流和主要设置。        它包含了主事件循环,对来自窗口系统的所有事件进行处理和调度。        它也处理应用程序的初始化和结束,并且提供对话管理。      
        QApplication 中定义了针对 XWindow 平台的虚函数,如清单4所示:      
清单 4.
1
bool QApplication::x11EventFilter ( XEvent * )




        创建 QApplication 的子类,并且重新实现函数 x11EventFilter(),那么所有底层的 XEvent 会首先被函数 x11EventFilter() 截获。        如果希望在函数 x11EventFilter() 中针对某事件进行响应,那么在响应结束后返回 TRUE,表示该事件不会被分派到 QApplication 的 Qt 主事件循环中。        如果函数返回 FALSE,那么该事件会被继续分派到 QApplication 的 Qt 主事件循环中,由 Qt 包装成 Qt 事件。      
        此外,针对 Windows 平台,QApplication 定义了类似的虚函数,如清单5所示:      
清单 5.
1
bool QCoreApplication::winEventFilter ( MSG * msg, long * result )




        针对 Mac 平台,QApplication 定义了类似的虚函数,如清单6所示:      
清单 6.
1
bool QApplication::macEventFilter ( EventHandlerCallRef caller, EventRef event )




        下面通过一个例子说明,如何在 Qt 中处理 XEvent。        该例子包括两个可执行程序,一个是 xclient,另一个是 qtx11filter。        xclient 基于 Xlib,向 qtx11filter 发送 XClientMessageEvent。        qtx11filter 截获所有的 XEvent,但只对 XClientMessageEvent 进行处理,将其它所有类型的 XEvent 都分派到 QApplication 的 Qt 主事件循环中。      
3.1 xclient 的主要流程和源代码        xclient 的主要流程如下:      
  • 用户通过命令行输入16进制的window ID。
  • 向该window ID所在的窗口发送XClientMessageEvent。该事件所携带的数据是一个长度为4的字符串"2008"。
        xclient 的完整源代码 xclient.c 如清单7所示:      
清单 7.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h>

char line[80];
unsigned long winID, mask;
XEvent ev;
Display *disp;
Status status;

int main(int argc, char *argv[]){

  disp = XOpenDisplay(NULL);
  if(!disp){
    perror("Unable to open X display");
    exit(1);
  }

  do{
    printf("Enter a line: ");
    fgets(line, 80, stdin);
    if(line[0] != 'q'){
      winID = strtol(line, NULL, 16);
      printf("You entered %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("The XSendEvent returned: %d\n", status);
      XFlush(disp);
    }
    }while(line[0] != 'q');

}




        在 Fedora Core 6 中,利用如下命令编译 xclient:      
清单 8.
1
gcc xclient.c –o xclient –lX11




3.2 qtx11filter 的主要流程和源代码        qtx11filter 的主要流程如下:      
  • 创建 QApplication 的子类 App,并实现虚函数 x11EventFilter。注意使用宏定义 Q_WS_X11,因为 x11EventFilter 只适用于 XWindow。
  • 在 x11EventFilter 中,判断所截获的 XEvent,如果事件类型为 ClientMessage,那么打印出该事件发送者的 window ID,并且打印出该事件所携带的数据。
  • 在 main() 函数中,创建类 App 的实例,并且通过调用 app.exec(),启动 Qt 主事件循环。
        qtx11filter 的完整源代码 qtx11filter.c 如清单9所示:      
清单 9.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include <qapplication.h>
#include <qpushbutton.h>
#include <qdialog.h>
#include <X11/Xlib.h>

class App: public QApplication {
  public:
App(int argc, char **argv): QApplication(argc, argv) { }
#if defined(Q_WS_X11)
    bool x11EventFilter(XEvent *xe) {
      switch (xe->type) {
    case ClientMessage:
          printf("Caught ClientMessage XEvent from Window %d \n", xe->xclient.window);
      printf("Receive message: %s\n", xe->xclient.data.s);
      return true;  
      }
      return false;
}
  #endif
};

class Dialog: public QDialog {
  public:
    Dialog(QWidget *parent = 0): QDialog(parent) {
      QPushButton *done = new QPushButton("Done", this);
      connect(done, SIGNAL(clicked()), qApp, SLOT(quit()));
    }
};

int main(int argc, char **argv) {
  App app(argc, argv);
  Dialog dialog;
  app.setMainWidget(&dialog);
  dialog.show();
  return app.exec();
}




        在 Fedora Core 6 中,用以下命令编译 qtx11filter:      
清单 10.
1
2
g++ qtx11filter.c -L/usr/lib/qt-3.3/lib -I/usr/lib/qt-3.3/include
-lqt-mt –lX11 -o qtx11filter




3.3 演示 xclient 和 qtx11filter        1. 在终端启动 qtx11filter      
清单 11.
1
./qtx11filter




        弹出仅包含一个按钮的窗口,如图1所示:      
图 1. qtx11filter 窗口        2. 在终端启动 xwininfo,如图2所示:      
图 2. xwininfo 窗口        3. 将光标移动到窗口 qtx11filter,点击鼠标左键,xwininfo 可以获取 qtx11filter 的 window ID,如图3所示(截图中已经用红色方框标出)。      
图 3. 获取 qtx11filter 的 window ID        4. 在终端启动 xclient,并输入 qtx11filter 的 window ID,如图4所示。        然后,xclient 会向 qtx11filter 发送 XClientMessageEvent,该事件携带一个四字节的字符串"2008"。      
图 4. 输入 qtx11filter 的 window ID        5.打开运行 qtx11filter 的终端,qtx11filter 已经从 window ID 为 39845889 的窗口接收到一个 XClientMessageEvent,并读取出该事件所携带的数据"2008",如图5所示:      
图 5. qtx11filter 处理 XClientMessageEvent
返回列表