Qt 信号和槽 事件处理

一:Qt信号和槽概述              

信号与槽作为QT的核心机制在QT编程中有着广泛的应用,本章介绍了信号与槽的一些基本概念、元对象工具以及在实际使用过程中应注意的一些问题。

信号和槽机制是QT的核心机制,要精通QT编程就必须对信号和槽有所了解。信号和槽是一种高级接口,应用于对象之间的通信,它是QT的核心特性,也是QT区别于其它工具包的重要地方。信号和槽是QT自行定义的一种通信机制,它独立于标准的C/C++语言,因此要正确的处理信号和槽,必须借助一个称为 moc (Meta Object Compiler)的QT工具,该工具是一个C++预处理程序,它为高层次的事件处理自动生成所需要的附加代码。

在所有从 QObject或其子类(例如Qwidget)派生的类都能够包含信号和槽。当对象改变其状态时,信号就由该对象发射(emit)出去,这就是对象所要做的全部事情,它不知道另一端是谁在接收这个信号。这就是真正的信息封装,它确保对象被当作一个真正的软件组件来使用。槽用于接收信号,但它们是普通的对象成员函数。一个槽并不知道是否有任何信号与自己相连接。而且,对象并不了解具体的通信机制。

二:信号和槽示意图

三:信号

当某个信号对其客户或所有者发生的内部状态发生改变,信号被一个对象发射。

只有定义过这个信号的类及其派生类能够发射这个信号。当一个信号被发射时,与其相关联的槽将被立刻执行,就象一个正常的函数调用一样。

信号-槽机制完全独立于任何GUI事件循环。

如果存在多个槽与某个信号相关联,那么,当这个信号被发射时,这些槽将会一个接一个地执行,但是它们执行的顺序将会是随机的、不确定的,我们不能人为地指定哪个先执行、哪个后执行。

四:如何编写信号

信号的声明是在头文件中进行的,QT的signals关键字指出进入了信号声明区,随后即可 声明自己的信号。

下面定义了三个信号:

signals:

  void mySignal();

  void mySignal(int x);

  void mySignalParam(int x,int y);

在上面的定义中,signals是QT的关键字,而非C/C++的。接下来的一行void mySignal() 定义了信号mySignal,这个信号没有携带参数;接下来的一行void mySignal(int x)定义 了重名信号mySignal,但是它携带一个整形参数,这有点类似于C++中的虚函数。从形式上 讲信号的声明与普通的C++函数是一样的,但是信号却没有函数体定义,另外,信号的返回 类型都是void

五:槽

槽是普通的C++成员函数,可以被正常调用,它们唯一的特殊性就是很多信号可以与其相关联。当与其关联的信号被发射时,这个槽就会被调用。槽可以有参数,但槽的参数不能有缺省值。

同普通的C++成员函数一样,槽函数也分为三种类型,即public slots、private slots和protected slots。

槽也能够声明为虚函数,这也是非常有用的。

六:槽函数类型

public slots:在这个区内声明的槽意味着任何对象都可将信号与之相连接。这对于组件编程非常有用,你可以创建彼此互不了解的对象,将它们的信号与槽进行连接以便信息能够正确的传递。

protected slots:在这个区内声明的槽意味着当前类及其子类可以将信号与之相连接。这适用于那些槽,它们是类实现的一部分,但是其界面接口却面向外部。

private slots:在这个区内声明的槽意味着只有类自己可以将信号与之相连接。这适用于联系非常紧密的类。

七:如何编写槽

槽的声明也是在头文件中进行的。例如,

下面声明了三个槽:

public slots:

  void mySlot();

  void mySlot(int x);

          void mySignalParam(int x,int y);

八:QObject::connect

通过调用QObject对象的connect函数来将某个对象的信号与另外一个对象的槽函数相关联,这样当发射者发射信号时,接收者的槽函数将被调用。该函数的定义如下:

bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * member ) [static]

这个函数的作用就是将发射者sender对象中的信号signal与接收者receiver中的member槽函数联系起来。当指定信号 signal时必须使用QT的宏SIGNAL(),当指定槽函数时必须使用宏SLOT()。

如果发射者与接收者属于同一个对象的话,那么在connect 调用中接收者参数可以省略。

九:带有信号和槽的类

class TsignalApp:public QMainWindow
{Q_OBJECT//信号声明区signals: //声明信号mySignal()void mySignal();//声明信号mySignal(int)void mySignal(int x);//声明信号mySignalParam(int,int)void mySignalParam(int x,int y);//槽声明区public slots: //声明槽函数mySlot()void mySlot();//声明槽函数mySlot(int)void mySlot(int x);//声明槽函数mySignalParam (int,int)void mySignalParam(int x,int y);
}

十:一个信号与另一个信号相关联

class MyWidget : public QWidget{ public: MyWidget(); ... signals: void aSignal();... private:... QPushButton *aButton; 
}; 
MyWidget::MyWidget() 
{ aButton = new QPushButton( this ); 
connect( aButton, SIGNAL(clicked()), SIGNAL(aSignal()) ); 
} 

十一:信号和槽例子

下面定义了两个对象:标签对象label和滚动条对象scroll,并将valueChanged()信号与标签对象的setNum()相关联,另外信号还携带了一个整形参数,这样标签总是显示滚动条所处位置的值。

QLabel     *label  = new QLabel;
QScrollBar *scroll = new QScrollBar;
QObject::connect( scroll, SIGNAL(valueChanged(int)),label,  SLOT(setNum(int)) );

 十二:QObject::disconnect

当信号与槽没有必要继续保持关联时,我们可以使用disconnect函数来断开连接。

bool QObject::disconnect ( const QObject * sender, const char * signal, const Object * receiver, const char * member ) [static]

十三:槽和信号限制

限制1:类型宏不能被用于信号和槽的参数

#ifdef ultrix 
#define SIGNEDNESS(a) unsigned a 
#else 
#define SIGNEDNESS(a) a 
#endif 
class Whatever : public QObject 
{ ... signals: void someSignal( SIGNEDNESS(int) );//错误... 
}; 

限制2:构造函数不能用于信号部分和槽部分

class SomeClass : public QObject 
{ Q_OBJECT public slots: SomeClass( QObject *parent, const char *name ) : QObject( parent, name ) //错误... }; 

限制3:函数指针不能作为信号或槽的参数。 

class SomeClass : public QObject{ Q_OBJECT... public slots:void apply( void (*apply)(List *, void *), char * ); //错误}; 

限制4:信号和槽不能被升级  public  protected private

             QButtonGroup::buttonPressed()槽是保护的。

class Whatever : public QButtonGroup
{ ... public slots: void QButtonGroup::buttonPressed; // 错的 ... 
}; 

其他限制如下:

如果一个信号与多个槽相联系的话,那么,当这个信号被发射时,与之相关的槽被激活的顺序将是随机的。

信号与槽也不能携带模板类参数。

嵌套的类不能位于信号或槽区域内也不能有信号或者槽。

友元声明不能位于信号或者槽声明区内。

十四:元对象工具

元对象编译器moc(meta object compiler)对C++文件中的类声明进行分析并产生用于初始化元对象的C++代码,元对象包含全部信号和槽的名字以及指向这些函数的指针。

元对象代码是signal/slot机制所必须的。用moc产生的C++源文件必须与类实现一起进行编译和连接,或者用#include语句将其包含到类的源文件中。moc并不扩展#include或者#define宏定义,它只是简单的跳过所遇到的任何预处理指令。

十五:moc编译

Moc元对象编译器的功能是把包含有信号和槽的源文件编译成特殊的文件名为moc_+实际源文件名称

它的具体使用格式如下:

moc – [option] <filename>

moc   mysingal.h  -o moc_mysingal.h

 option包含如下参数:

-o <file> 
•把编译结果写到一个文件中而不是标志输出
-p  -p path
•使元对象编译器生成的(如果有生成的)#include声明的文件名称中预先考虑到 path/。
-q path
•使元对象编译器在生成的文件中的qt #include文件的名称中预先考虑到 path/。         

十六:类声明位置

类的声明放在一个头文件(.h文件)中

如果在上述的文件myclass.h中发现类的声明,元对象编译器的输出文件将会被放在一个叫moc_myclass.cpp的文件中。这个文件将会像通常情况一样被编译,作为对象文件的结果是moc_myclass.o

类的声明放在一个实现文件(.cpp文件)中

如果上述的文件myclass.cpp中发现类的声明,元对象编译器的输出文件将会被放在一个叫myclass.moc的文件中。这个文件需要被实现文件包含(#include),也就是说myclass.cpp需要包含下面这行 #include "myclass.moc" 放在所有的代码之后。

十七:事件机制

Qt中定义的事件是一个从QEvent类继承下来的,它表示应用程序内部或者外部发生某些应用程序必须知道的事情

Qt 使用一个事件队列对所有发出的事件进行维护,当新的事件产生时,会被追加到事件队列的尾部。前一个事件完成后,取出后面的事件进行处理。但是,必要的时候,Qt 的事件也可以不进入事件队列,而是直接处理

在Qt内部,Qt通过由函数QApplication::exec()函数启动的主事件循环从系统事件队列中抓取属于本程序事件并转化为QEvent对象

十八:事件类图

十九:事件来源分类

基于事件如何被产生与分发,可以把事件分为三类:

1. Spontaneous 事件,由窗口系统产生,它们被放到系统队列中,通过事件循环逐个处理

    鼠标,键盘,移动

2. Posted 事件,由Qt或是应用程序产生,它们被Qt组成队列,再通过事件循环处理。update(),paintEvent()

3. Sent  事件,由Qt或是应用程序产生,但它们被直接发送到目标对象。 repaint()

二十:QEvent对象

QEvent对象是所有事件对象的基类,因此有必要了解该对象构成函数:

enum Type :标识事件类型

Type type () const   :调用该函数,返回事件发生事件的类型(该类型为枚举)

二十一:常用的事件类型

通过调用QEvent::type函数可以返回具体事件类型,Qt已经为具体的事件类型事先定义了:

QEvent::MouseButtonPress - 鼠标按下,QMouseEvent。

QEvent::MouseButtonRelease - 鼠标抬起,QMouseEvent。

QEvent::MouseButtonDblClick - 鼠标再次按下

QEvent::MouseMove - 鼠标移动,QMouseEvent。

QEvent::Close - 窗口部件被关闭(永久性地) QCloseEvent。

QEvent::KeyPress - 键按下(举例,包括Shift)QKeyEvent。

QEvent::KeyRelease - 键抬起,QKeyEvent。

QEvent::FocusIn - 窗口部件获得键盘焦点,QFocusEvent。

QEvent::FocusOut - 窗口部件失去键盘焦点,QFocusEvent。

 QEvent::Timer - 规则的定时器事件,QTimerEvent。

二十二:常用的Qt事件类

Qt为多数事件定义了特殊的类:

QMouseEvent 鼠标事件
QKeyEvent  键盘事件
QResizeEvent窗体宿放事件
QPaintEvent 窗体重绘事件
QCloseEvent 窗体关闭事件
QFocusEvent 部件获得焦点事件

二十三:事件处理方法

Qt提供了几种处理事件的方法:

重新实现特定的事件处理器
重新实现QObject::event()函数
继承QApplication并重新实现notify()函数

二十四:实现特定的事件处理器

最常见的事件处理办法就是重载象mousePressEvent(), keyPressEvent(), paintEvent() 这样的特定事件处理函数. 以按键事件为例  

二十五:QKeyEvent对象

QKeyEvent对象是Qt的键盘事件的包装对象,我们也经常需要捕获键盘事件.下面是该对象主要成员函数:

int key () const
int ascii () const
ButtonState state () const
ButtonState stateAfter () const
bool isAccepted () const
QString text () const
bool isAutoRepeat () const
int count () const
void accept ()

                 void ignore ()

二十六:Qt键盘常量

为了方便程序员捕获特殊键.qt已经对所有的键盘都进行了宏定义,下面列出常用的键值:

二十七:QMouseEvent对象

在Qt系统中对所有鼠标事件都被封装为QMouseEvent对象,有必要了解下该对象成员函数

Qt::MouseButton button () const

返回发生鼠标事件时按下的鼠标按钮

const QPoint & globalPos () const
返回发生鼠标事件时,鼠标在屏幕上的位置指针
int globalX () const
返回发生鼠标事件时,鼠标在屏幕上x轴位置
int globalY () const
返回发生鼠标事件时,鼠标在屏幕上y轴位置
int x () const
返回发生鼠标事件时,相对与本窗体的x轴位置
int y () const

                            返回发生鼠标事件时,相对与本窗体的x轴位置

二十八:事件处理器实现

void imageView::keyPressEvent(QKeyEvent * event)
{switch (event->key()) {case Key_Plus:zoomIn();break;case Key_Minus:zoomOut();break;case Key_Left:// … default:QWidget::keyPressEvent(event);}
}

二十九:重载event()函数

通过重载event()函数,我们可以在事件被特定的事件处理函数处理之前(象keyPressEvent())处理它. 比如, 当我们想改变tab键的默认动作时,一般要重载这个函数. 在处理一些不常见的事件当我们重载event()函数时, 需要调用父类的event()函数来处理我们不需要处理或是不清楚如何处理的事件

三十:重载event实现

下面这个例子演示了如何重载event()函数, 改变Tab键的默认动作: (默认的是键盘焦点移动到下一个控件上)

bool CodeEditor::event(QEvent * event)
{if (event->type() == QEvent::KeyPress){QKeyEvent *keyEvent = (QKeyEvent *) event;if (keyEvent->key() == Key_Tab){insertAtCurrentPosition('\t');return true;}}
return QWidget::event(event);
}

三十一:QApplication::notify()

Qt是用QApplication::notify()函数来分发事件的.想要在任何事件过滤器查看任何事件之前先得到这些事件,重载这个函数是唯一的办法. 通常来说事件过滤器更好用一些, 因为不需要去继承QApplication类. 而且可以给QApplication对象安装任意个数的事件过滤器, 相比之下, notify()函数只有一个

三十二:事件过滤器

Qt事件模型中有一项非常强大的功能是一个Object实例可以监视另外一个QObject实列中的事件.实现方法就是在目标对象安装事件过滤器.这样事件到打目标对象之前首先获得该事件.从而起到监视作用

三十三:安装事件过滤器

安装事件过滤器有两个步骤: (假设要用A来监视过滤B的事件)

首先调用B的installEventFilter( const QOject *obj ), 以A的指针作为参数. 这样所有发往B的事件都将先由A的eventFilter()处理.
然后, A要重载QObject::eventFilter()函数, 在eventFilter() 中书写对事件进行处理的代码

三十四:事件过滤器实现                 

MainWidget::MainWidget()
{  // …CodeEditor * ce = new CodeEditor( this, “code editor”);ce->installEventFilter( this );// …
}
bool MainWidget::eventFilter( QOject * target , QEvent * event )
{if( target == ce ){if( event->type() == QEvent::KeyPress ) {QKeyEvent *ke = (QKeyEvent *) event;if( ke->key() == Key_Tab ){ce->insertAtCurrentPosition('\t');return true;}} }return false;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/70582.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt无故卡死关闭解决办法

关于Qt无故卡死崩溃的解决办法 网上找了很多原因&#xff0c;但是最终定位到的是显卡不兼容&#xff0c;只需要以下设置一下就行。 . 方法1&#xff1a; 查看本机是不是有启用“网易有道词典”&#xff0c;关闭即可&#xff0c;QT与其他软件冲突导致。 方法2&#xff1a; 删…

【记录】有道词典导致Qt程序卡死,并且内存泄漏问题

原文链接&#xff1a;http://blog.csdn.net/oLuoJinFanHua12/article/details/100667592 有道词典导致Qt程序卡死的问题我已经发现了一段时间&#xff0c;之前以为是自己程序的问题&#xff0c;后面多方验证才发现这个问题是我更新到Qt5.12后产生的。 下面是该bug的重现条件&a…

qt 子窗口写到线程就卡死_深入了解QT消息循环及线程相关性

一、什么是Qt消息循环 Qt消息循环,就是从一个队列中不断取出消息,并响应消息的过程。窗体的鼠标、键盘、输入法、绘制,各种消息,都来自于Qt的消息循环。以Windows操作系统为例,Qt接管Windows原生窗口消息,并翻译成Qt的消息,派发给程序下的各个子对象、子QWidget等,通过…

QT编程过程中遇到的问题

QT编程过程中遇到的问题 &#xff08;一&#xff09;QT卡死&#xff08;二&#xff09;mingw转msvc编码问题&#xff08;三&#xff09;内存泄漏问题1. vld检查内存泄漏问题2. QTextEdit造成内存泄漏 &#xff08;四&#xff09;文件路径问题&#xff08;5&#xff09;快速生成…

QT 界面在linux下调试时卡死的问题

文章目录 一、问题描述二、解决方法&#xff08;1&#xff09;强杀进程&#xff08;2&#xff09;安装xnest&#xff08;3&#xff09;qt creater配置 一、问题描述 xnest是一个虚拟的X服务端&#xff0c;其窗口可以运行界面程序&#xff0c;电脑在调试弹窗时界面容易冻住&…

3月9日 19:30 | 首场大模型专场来袭

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 哔哩哔哩直播通道 扫码关注AI TIME哔哩哔哩官方账号预约直播 2023年3月9日 19:30-21:30 谢天宝&#xff1a; 香港大学一年级博士生&#xff0c;由余涛教授&#xff08;主要&#xff09;和孔令鹏教授指导&#…

AGI—从GPT和大型语言模型中汲取的经验教训

点击蓝字 关注我们 关注并星标 从此不迷路 计算机视觉研究院 公众号ID&#xff5c;计算机视觉研究院 学习群&#xff5c;扫码在主页获取加入方式 论文地址&#xff1a;https://arxiv.org/pdf/2306.08641.pdf 计算机视觉研究院专栏 Column of Computer Vision Institute 人工智能…

走向计算机视觉的通用人工智能:从GPT和大型语言模型中汲取的经验教训 (下)...

点击蓝字 关注我们 关注并星标 从此不迷路 计算机视觉研究院 公众号ID&#xff5c;计算机视觉研究院 学习群&#xff5c;扫码在主页获取加入方式 论文地址&#xff1a;https://arxiv.org/pdf/2306.08641.pdf 计算机视觉研究院专栏 Column of Computer Vision Institute 人工智能…

自动化系列(五)Python实现企业微信机器人

自动化系列&#xff08;五&#xff09;Python实现企业微信机器人 上期介绍了如何定时推送数据到钉钉群&#xff0c;这次介绍如何定时推送数据到企业微信群。 添加自定义机器人 创建群聊&#xff1a;企业微信没有场景群&#xff0c;可以拉三五好友进群&#xff0c;然后再给他…

企业微信机器人 api 使用

key 来自&#xff1a; 一、发送消息 function sendText(key , text , mentioned []) {try {axios({method: post,url: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key key,data: {msgtype: text,text: {content: text,mentioned_list: mentioned}}})} catch (er…

每个人都可以用的开源微信机器人

经历过UOS web协议的重放荣光&#xff0c;又经过一段时间的封禁&#xff0c;又有大神把UOS web协议救回来了。免费的快乐又重新回来了&#xff0c;不是吗? 这意味着每个人都可以用Wechaty搞事情了&#xff0c;什么服务器通知&#xff0c;定时给女友发微信&#xff0c;群发消息…

WorkTool(一)企业微信群管理机器人实现

简介 WorkTool 主程序是一个开源的安卓应用 APP&#xff0c;不需要 root 权限就可以直接安装。 源码友情链接 测试发送消息 API 使用 WorkTool APP 来自动执行一个自己企微里的账号&#xff0c;并通过后台调用对应的 API 来驱动机器人自动执行任务&#xff0c;如收发消息、自…

用企业微信机器人搞事情

从把办公通信工具从微信迁移到企业微信后&#xff0c;群组里面多了一个叫“群聊机器人”的功能&#xff0c;如下图&#xff0c;我在某个群建了一个叫“测试”的机器人。 听名字会让人以为群里面有个能自动答复的机器人&#xff0c;它就能跟他对话。其实并不能&#xff0c;他的功…

VX线报机器人的使用

使用步骤&#xff1a; 1. 下载上面的压缩包&#xff0c;并解压到同一个文件夹&#xff0c;没有解压是使用不了的 2. 双击Update.exe来下载机器人框架核心文件 3. 把com.bbs.weiququ.vlw.dll文件移到Plugin文件夹下 4.双击【我的框架.exe】来启动机器人框架 5.在我的帐号页…

AI热潮来袭||网友:AI会不会抢自己的饭碗啊~~~

ChatGPT还没搞懂&#xff0c;平地一声雷&#xff0c;GPT-4重磅发布&#xff01;瑟瑟发抖的吃瓜群众逐渐变多&#xff1a;AI会不会抢自己的饭碗啊~~~ 答案是&#xff1a;会&#xff01; 人工智能助手“阿里小蜜”承担95%的客服咨询&#xff1b; 机器人“天巡”接替运维人员以…

用友助力中核集团建设财务共享中心新华发电分中心,实现业财融合

企业在进行决策时需要大量的财务信息作为依据&#xff0c;财务共享中心的建设可以帮助企业将财务和业务分离后重新有序融合&#xff0c;使得决策数据更有价值&#xff0c;也帮助企业的管理和决策更加贴合实际。 新华水力发电有限公司&#xff08;简称“新华发电”&#xff09;…

【占星学】天蝎座女生性格特点

一、性格特点 天蝎座女的个性非常细腻&#xff0c;拥有非常敏锐的观察能力&#xff0c;外表总是一副冷漠的样子&#xff0c;但其实她们内心非常希望能够有一个人懂自己&#xff0c;天蝎座的女生其实是典型的外冷内热。此外&#xff0c;天蝎座的女生骨子里有争强好胜的性格&…

html星座代码,各星座详细页面.html

&#xfeff;各星座详细页面 $axure.utils.getTransparentGifPath function() { return resources/images/transparent.gif; }; $axure.utils.getOtherPath function() { return resources/Other.html; }; $axure.utils.getReloadPath function() { return resources/reload…

如何搭建产品知识库?让产品知识库管理更有序高效!

任何一款成功的产品&#xff0c;都需要将自己的产品知识&#xff08;内部制作和外部搜集&#xff09;进行汇总和整理&#xff0c;帮助用户可以运用产品知识库中的内容&#xff0c;去解决实际应用中存在的问题。 有序高效的知识库管理 当一款产品从研发到投入使用&#xff0c;整…

基于GPT搭建私有知识库聊天机器人(一)实现原理

文章链接&#xff1a; 基于GPT搭建私有知识库聊天机器人&#xff08;二&#xff09;环境安装 基于GPT搭建私有知识库聊天机器人&#xff08;三&#xff09;向量数据训练 基于GPT搭建私有知识库聊天机器人&#xff08;四&#xff09;问答实现 1、成品演示 支持微信聊天支持网…