Qt使用一个事件队列对所有发出的事件进行维护(QObject的event()函数相当于dispatch函数),用EventLabel 继承QLabel作为例子(简单明了) good
事件(event)是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件在对用户操作做出响应时发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件。
事件也就是我们通常说的“事件驱动(event drive)”程序设计的基础概念。事件的出现,使得程序代码不会按照原始的线性顺序执行。想想看,从最初的 C 语言开始,我们的程序就是以一种线性的顺序执行代码:这一条语句执行之后,开始执行下一条语句;这一个函数执行过后,开始执行下一个函数。这种类似“批处理”的程序设计风格显然不适合于处理复杂的用户交互。我们来想象一下用户交互的情景:我们设计了一堆功能放在界面上,用户点击了“打开文件”,于是开始执行打开文件的操作;用户点击了“保存文件”,于是开始执行保存文件的操作。我们不知道用户究竟想进行什么操作,因此也就不能预测接下来将会调用哪一个函数。如果我们设计了一个“文件另存为”的操作,如果用户不点击,这个操作将永远不会被调用。这就是所谓的“事件驱动”,我们的程序的执行顺序不再是线性的,而是由一个个事件驱动着程序继续执行。没有事件,程序将阻塞在那里,不执行任何代码。
在 Qt 中,事件的概念似乎同信号槽类似。的确如此,一般来说,使用 Qt 组件时,我们并不会把主要精力放在事件上。因为在 Qt 中,我们关心的更多的是事件关联的一个信号。比如,对于QPushButton
的鼠标点击,我们不需要关心这个鼠标点击事件,而是关心它的clicked()
信号的发出。这与其他的一些 GUI 框架不同:在 Swing 中,你所要关心的是JButton
的ActionListener
这个点击事件。由此看出,相比于其他 GUI 框架,Qt 给了我们额外的选择:信号槽。
但是,Qt 中的事件和信号槽却并不是可以相互替代的。信号由具体的对象发出,然后会马上交给由connect()
函数连接的槽进行处理;而对于事件,Qt 使用一个事件队列对所有发出的事件进行维护,当新的事件产生时,会被追加到事件队列的尾部。前一个事件完成后,取出后面的事件进行处理。但是,必要的时候,Qt 的事件也可以不进入事件队列,而是直接处理。信号一旦发出,对应的槽函数一定会被执行。但是,事件则可以使用“事件过滤器”进行过滤,对于有些事件进行额外的处理,另外的事件则不关心。总的来说,如果我们使用组件,我们关心的是信号槽;如果我们自定义组件,我们关心的是事件。因为我们可以通过事件来改变组件的默认操作。比如,如果我们要自定义一个能够响应鼠标事件的EventLabel
,我们就需要重写QLabel
的鼠标事件,做出我们希望的操作,有可能还得在恰当的时候发出一个类似按钮的clicked()
信号(如果我们希望让这个EventLabel
能够被其它组件使用)或者其它的信号。
在前面我们也曾经简单提到,Qt 程序需要在main()
函数创建一个QCoreApplication
对象,然后调用它的exec()
函数。这个函数就是开始 Qt 的事件循环。在执行exec()
函数之后,程序将进入事件循环来监听应用程序的事件。当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于QEvent
。在事件对象创建完毕后,Qt 将这个事件对象传递给QObject
的event()
函数。event()
函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler)。关于这一点,我们会在以后的章节中详细说明。
在所有组件的父类QWidget
中,定义了很多事件处理的回调函数,如keyPressEvent()
、keyReleaseEvent()
、mouseDoubleClickEvent()
、mouseMoveEvent()
、mousePressEvent()
、mouseReleaseEvent()
等。这些函数都是 protected virtual 的,也就是说,我们可以在子类中重新实现这些函数。下面来看一个例子:
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
|
class EventLabel : public QLabel
{
protected:
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
};
void EventLabel::mouseMoveEvent(QMouseEvent *event)
{
this->setText(QString("<center><h1>Move: (%1, %2)</h1></center>")
.arg(QString::number(event->x()), QString::number(event->y())));
}
void EventLabel::mousePressEvent(QMouseEvent *event)
{
this->setText(QString("<center><h1>Press: (%1, %2)</h1></center>")
.arg(QString::number(event->x()), QString::number(event->y())));
}
void EventLabel::mouseReleaseEvent(QMouseEvent *event)
{
QString msg;
msg.sprintf("<center><h1>Release: (%d, %d)</h1></center>",
event->x(), event->y());
this->setText(msg);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
EventLabel *label = new EventLabel;
label->setWindowTitle("MouseEvent Demo");
label->resize(300, 200);
label->show();
return a.exec();
}
|
我们编译运行上面的代码,就可以理解到有关事件的使用方法。
EventLabel
继承了QLabel
,覆盖了mousePressEvent()
、mouseMoveEvent()
和MouseReleaseEvent()
三个函数。我们并没有添加什么功能,只是在鼠标按下(press)、鼠标移动(move)和鼠标释放(release)的时候,把当前鼠标的坐标值显示在这个Label
上面。由于QLabel
是支持 HTML 代码的,因此我们直接使用了 HTML 代码来格式化文字。
QString
的arg()
函数可以自动替换掉QString
中出现的占位符。其占位符以 % 开始,后面是占位符的位置,例如 %1,%2 这种。
1
|
QString("[%1, %2]").arg(x, y);
|
语句将会使用 x 替换 %1,y 替换 %2,因此,这个语句生成的QString
为 [x, y]。
在mouseReleaseEvent()
函数中,我们使用了另外一种QString
的构造方法。我们使用类似 C 风格的格式化函数sprintf()
来构造QString
。
运行上面的代码,当我们点击了一下鼠标之后,label 上将显示鼠标当前坐标值。
为什么要点击鼠标之后才能在mouseMoveEvent()
函数中显示鼠标坐标值?这是因为QWidget
中有一个mouseTracking
属性,该属性用于设置是否追踪鼠标。只有鼠标被追踪时,mouseMoveEvent()
才会发出。如果mouseTracking
是 false(默认即是),组件在至少一次鼠标点击之后,才能够被追踪,也就是能够发出mouseMoveEvent()
事件。如果mouseTracking
为 true,则mouseMoveEvent()
直接可以被发出。知道了这一点,我们就可以在main()
函数中直接设置下:
1
2
3
4
5
|
EventLabel *label = new EventLabel;
label->setWindowTitle("MouseEvent Demo");
label->resize(300, 200);
label->setMouseTracking(true);
label->show();
|
这样子就没有这个问题了。
https://www.devbean.net/2012/09/qt-study-road-2-events/
这篇内容稍有不同,估计是早期版本:
http://blog.sina.com.cn/s/blog_a401a1ea0101e6y3.html
Qt使用一个事件队列对所有发出的事件进行维护(QObject的event()函数相当于dispatch函数),用EventLabel 继承QLabel作为例子(简单明了) good的更多相关文章
- 是否可从一个static方法内发出对非static方法的调用?
不可以.因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以直接调用.也就是说,当一个static方法被调用时, ...
- QT+信号和槽函数_自定义槽函数_一个信号对应多个槽函数
以下的代码里面有自定义槽函数的内容,同时也有信号实现的函数: #ifndef MAINWIDGET_H #define MAINWIDGET_H #include <QWidget> #i ...
- 是否可以从一个static方法内部发出对非static方法的调用
不可以.因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方 法调用,而static方法调用时不需要创建对象,可以直接调用.也就是说,当一个static方法被调用时 ...
- QT制作一个位图画图板程序
本文学习如何创建一个Qt绘制程序,用户将能够通过使用不同的尺寸和画笔的颜色来表达他们的创造力. 主要功能:保存画板内容为图片.清除画板内容.设置画板大小.设置画笔颜色 新建基于QMainWindow的 ...
- 使用QT实现一个简单的登陆对话框(纯代码实现C++)
使用QT实现一个简单的登陆对话框(纯代码实现C++) 效果展示 使用的QT控件 控件 描述 QLable 标签 QLineEdit 行文本框 QPushButton 按扭 QHBoxLayout 水平 ...
- 使用Qt实现一个必应壁纸客户端
概要 必应的每日壁纸很好看,但是看不到一周以前的壁纸图片,日前使用python开发了必应壁纸收集站,可惜这样的收集站只能在线浏览,我在想要是有一款软件能够下载每日必应壁纸,并应用到windows的桌面 ...
- Qt 学习之路 2(74):线程和 QObject
Home / Qt 学习之路 2 / Qt 学习之路 2(74):线程和 QObject Qt 学习之路 2(74):线程和 QObject 豆子 2013年12月3日 Qt 学习之路 2 2 ...
- Java-集合(没做出来)第四题 (List)写一个函数reverseList,该函数能够接受一个List,然后把该List 倒序排列。 例如: List list = new ArrayList(); list.add(“Hello”); list.add(“World”); list.add(“Learn”); //此时list 为Hello World Learn reverseL
没做出来 第四题 (List)写一个函数reverseList,该函数能够接受一个List,然后把该List 倒序排列. 例如: List list = new ArrayList(); list.a ...
- 一个DOM元素绑定多个事件时,先执行冒泡还是捕获
绑定在被点击元素的事件是按照代码顺序发生,其他元素通过冒泡或者捕获“感知”的事件,按照W3C的标准,先发生捕获事件,后发生冒泡事件.所有事件的顺序是:其他元素捕获阶段事件 -> 本元素代码顺序事 ...
随机推荐
- 指示灯组与3个复位按钮的介绍Arduino Yun快速入门教程
指示灯组与3个复位按钮的介绍Arduino Yun快速入门教程 1.4.2 指示灯组 指示灯组的放大图如图1.5所示. 图1.5 指示灯组 各个指示灯对应的功能如下: q RX:对应于0号端口, ...
- UVa11732 "strcmp()" Anyone?(Trie树+孩子兄弟表示法)
我的做法是先建字典树,统计每个结点出现次数和相同字符串个数,每个结点对答案的贡献就是2*C(次数,2),然后再分别讨论相同字符串和不同字符串对答案的贡献. 另外这题主要就是Trie树的孩子兄弟表示法: ...
- 一份spring配置文件及其详解
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/axu20/archive/2009/10/14/4668188.aspx 1.基本配置:<?xml versio ...
- 【SPOJ】694. Distinct Substrings
http://www.spoj.com/problems/DISUBSTR/ 题意:求字符串不同子串的数目. #include <bits/stdc++.h> using namespac ...
- HDU 4647 Another Graph Game(贪心)
题目链接 思路题.看的题解. #include <cstdio> #include <string> #include <cstring> #include < ...
- 【C语言】04-函数
一.函数的分类 前面已经说过,C语言中的函数就是面向对象中的"方法",C语言的函数可以大概分为3类: 1.主函数,也就是main函数.每个程序中只能有一个.也必须有一个主函数.无论 ...
- kvm安装
基础环境: 192.168.1.67 super67 硬件cpu需要支持:Intel VT-x 技术 本实验使用虚拟机VMware Workstation上的虚拟机 ...
- [转] - JAR文件包及jar命令详解 ( MANIFEST.MF的用法 )
常常在网上看到有人询问:如何把 java 程序编译成 .exe 文件.通常回答只有两种,一种是制作一个可执行的 JAR 文件包,然后就可以像. chm 文档一样双击运行了:而另一种是使用 JET 来进 ...
- zhcon安装过程记录
参考资料: 1. http://www.linuxdiyf.com/viewarticle.php?id=81796 需要下载的文件有两个:zhcon-0.2.5.tar.gz和zhcon-0.2.5 ...
- YII2.0 secruity
保存密码不能用明文保存,用MD5或者sha1哈希化是安全,但是随着硬件的发展,可能会暴力破解,目前能够对抗暴力破解的哈希算法是 bcrypt,Yii提供了两个帮助函数使用crypt进行安全的哈希加密 ...