文章目录
1、事件
事件是由程序内部或外部产生的事情或某种动作的通称。
比如用户按下键盘或鼠标,就会产生一个键盘事件或鼠标事件(这是由程序外部产生的事件);再如,当窗口第一次显示时,会产生一个绘制事件,以通知窗口需要重新绘制其自身,从而使该窗口可见(这是由程序内部产生的事件)。
它反映了包括Qt在内的GUI应用程序的消息处理模型:
(1) 用户操作界面,被操作系统内核空间中的设备驱动程序感知
(2) 设备驱动程序向操作系统的用户空间的GUI应用程序发出系统消息
(3) GUI应用程序将系统消息转换为信号,进而触发槽函数
在GUI应用程序中,一个核心且关键的操作就是将系统消息转换为信号,涉及到Qt的事件处理机制:
(1) Qt平台将系统底层发来的消息转换为Qt事件,并将其Qt事件产生后立即被分发到QWidget对象
(2) QWidget对象中的event(QEvent* )函数对事件进行处理,即根据不同的事件,调用不同的事件处理函数
(3) 在事件处理函数中发送Qt中预定义的对应事件的Qt信号,进而调用到信号关联的槽函数
Qt事件是一个QEvent对象,用于描述程序内部(如定时器超时)和外部发生的动作,任何QObject对象都具备事件处理能力。
从上图也可以明显看出,Qt信号是由继承自QObject的QWidget对象中的event()函数调用的事件处理函数发来的。
事件的出现,使得程序代码不会按照原始的线性顺序执行。
线性顺序的程序设计风格不适合处理复杂的用户交互
用户交互过程中进行什么样的操作是由用户决定的,程序设计时无法事先预测,同时用户的操作都会发出相应的事件,因此用户交互的程序设计中程序的执行顺序不再是线性的,而是由一个个事件驱动着程序继续执行,如果没有事件,程序将阻塞,不执行任何代码。
2、 事件和信号的区别
2.1 信号是由对象产生的
而事件则不一定是由对象产生的(比如由鼠标产生的事件),事件通常来自底层的窗口系统,但也可以手动发送自定义的事件,可见信号和事件的来源是不同的。
2.2 事件既可以同步使用,也可以异步使用
(取决于调用sendEvent()还是 postEvents()),而使用信号和槽总是同步的。事件的另一个好处是可以被过滤。
3、 Qt事件的分类
3.1 根据何时发生,一般分为两类
①与用户交互时发生。比如按下鼠标(mousePressEvent),敲击键盘(keyPressEvent)等。
②系统自动发生,比如计时器事件(timerEvent)等。
3.2 根据事件的来源和传递方式,事件可分为以下三大类
①自发事件:这是由窗口系统生成的,这些事件置于系统队列中,并由事件循环一个接一个地处理。
②发布的事件(Posted events):该类事件由Qt或应用程序生成,这些事件由Qt排队,并由事件循环处理。入队列
③发送的事件(Sent events):该类事件由Qt或应用程序生成,这些事件直接发送到目标对象,不经过事件循环处理。直接处理
4 、事件的传递和处理
postevent将事件交给事件队列
sendevent将事件交给目标对象
4.1 事件的传递过程
在Qt中有一个事件循环,该循环负责从可能产生事件的地方捕获各种事件,并把这些事件转换为带有事件信息的对象,然后由Qt的事件处理流程分发给需要处理事件的对象来处理事件。
①调用QCoreApplication::exec()函数启动事件主循环。
②调用QCoreApplication::notify()函数对事件进行传递(或分发)
③QObject对象调用QObject::event()函数接收事件
④event()函数负责把事件传递给目标对象并调用对应的事件处理函数处理事件,比如调用QWidget::keyPressEvent()函数处理键盘按下事件等
4.2 事件的处理
①、重新实现各部件内部默认的事件处理函数
②、重新实现QObject::event()函数(需继承QObject类)
③、在QObject对象上安装(或称为注册)事件过滤器(见后文)
④、在QApplication上安装(或称为注册)事件过滤器。
⑤、子类化QApplication,并重新实现QCoreApplication::notify()函数
bool event(QEvent *event) 所有派发集合函数;
virtual void mousePressEvent(QMouseEvent *event);鼠标按下
virtual void mouseReleaseEvent(QMouseEvent *event);鼠标释放
virtual void mouseDoubleClickEvent(QMouseEvent *event);鼠标双击
virtual void mouseMoveEvent(QMouseEvent *event);鼠标移动(按下)
#if QT_CONFIG(wheelevent)
virtual void wheelEvent(QWheelEvent *event);滚轮
#endif
virtual void keyPressEvent(QKeyEvent *event);按键按下
virtual void keyReleaseEvent(QKeyEvent *event);按键释放
virtual void focusInEvent(QFocusEvent *event);获取焦点
virtual void focusOutEvent(QFocusEvent *event);失去焦点
virtual void enterEvent(QEvent *event);鼠标进入
virtual void leaveEvent(QEvent *event);鼠标退出
virtual void paintEvent(QPaintEvent *event);绘图
virtual void moveEvent(QMoveEvent *event);移动
virtual void resizeEvent(QResizeEvent *event);尺寸变化
virtual void closeEvent(QCloseEvent *event);关闭窗口
4.3 基本事件的使用
bool EventWin::event(QEvent *e)
{
//记录事件发生的次数
static int num = 0;
qDebug()<<"times:"<<num++;
//如果没有返回父类事件处理函数,该事件在本函数中被拦截
return QMainWindow::event(e);
}
void EventWin::mousePressEvent(QMouseEvent *e)
{
qDebug()<<"mouserEvent"<<e->pos();
}
void EventWin::mouseDoubleClickEvent(QMouseEvent *event)
{
if(this->isFullScreen())//判断是否全屏
this->showNormal();
else
this->showFullScreen();
}
void EventWin::keyPressEvent(QKeyEvent *e)
{
if(e->key() == Qt::Key_Enter)
{
if(this->isFullScreen())//判断是否全屏
this->showNormal();
else
this->showFullScreen();
}
}
void EventWin::enterEvent(QEvent *event)
{
this->setStyleSheet("background-color:#123456");
}
void EventWin::leaveEvent(QEvent *event)
{
this->setStyleSheet("background-color:#654321");
}
5 、事件过滤
事件过滤器可以对其他组件接收到的事件进行监控,改变事件分发路径,经过过滤器
任意的QObject对象都可以作为事件过滤器使用
事件过滤器对象需要重启eventFilter() 函数
组件通过installEventFilter() 函数安装事件过滤器
事件过滤器在组件之前接收到事件
事件过滤器能够决定是否将事件转发到组件对象
//给按钮安装过滤器
ui->button->installEventFilter(this);
//控件事件过滤器函数
bool EventFilterWin::eventFilter(QObject *obj, QEvent* e)
{
if(obj == ui->button)
{
QPushButton *button = dynamic_cast<QPushButton*>(obj);
//qDebug()<<" Event filter";
if(e->type() == QEvent::Enter)//进入窗口(按钮)
{
rect = button->geometry();
button->setGeometry(rect.x()-10, rect.y()-10, rect.width()+20, rect.height()+20);
}
else if(e->type() == QEvent::Leave)//退出窗口
{
button->setGeometry(rect);
}
}
return QMainWindow::eventFilter(obj, e);
}
6、 重新实现按键按下事件
6.1 自定义按钮类:(继承于按钮类)
#ifndef HDBUTTON_H
#define HDBUTTON_H
#include <QObject>
#include <QPushButton>
class HDButton : public QPushButton
{
public:
explicit HDButton(QWidget *parent = nullptr);
explicit HDButton(const QString &text, QWidget *parent = nullptr);
HDButton(const QIcon& icon, const QString &text, QWidget *parent = nullptr);
//实现鼠标点击事件
void mousePressEvent(QMouseEvent *e);
};
#endif // HDBUTTON_H
6.2 构造函数实现与功能函数实现
#include "hdbutton.h"
#include <QDebug>
HDButton::HDButton(QWidget *parent):QPushButton(parent){}
HDButton::HDButton(const QString &text, QWidget *parent):QPushButton (text, parent){}
HDButton::HDButton(const QIcon &icon, const QString &text, QWidget *parent):QPushButton (icon,text, parent){}
void HDButton::mousePressEvent(QMouseEvent *e)
{
qDebug()<<"自定义按钮, 鼠标点击事件";
}
6.3 使用按钮
1、要现实的窗口类构造函数中直接创建
#include "eventfilterwin.h"
#include "hdbutton.h"
#include "ui_eventfilterwin.h"
#include <QDebug>
EventFilterWin::EventFilterWin(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::EventFilterWin)
{
ui->setupUi(this);
//给按钮安装过滤器
ui->button->installEventFilter(this);
HDButton *bt = new HDButton(this);
}
2、使用designer设计器来提升控件(使用)
3、保存编译执行
7、 软键盘实现
取消按钮焦点:
如果不取消焦点,在多行输入时就无法确定输入的数据时放在哪一行。
模拟键盘,利用事件完成
(1)A、B键:
void SendEventWin::on_pushButton_clicked()
{
//获取按钮的字符
QString str = ui->pushButton->text();
char ch = str.at(0).toLatin1();
//创建按钮事件
QKeyEvent *key = new QKeyEvent(QKeyEvent::KeyPress, ch,Qt::NoModifier,str);
//发送事件
QApplication::postEvent(QApplication::focusWidget(), key);//发送事件给获取焦点的窗口
}
void SendEventWin::on_pushButton_2_clicked()
{
//获取按钮的字符
QString str = ui->pushButton_2->text();
char ch = str.at(0).toLatin1();
//创建按钮事件
QKeyEvent *key = new QKeyEvent(QKeyEvent::KeyPress, ch,Qt::NoModifier,str);
//发送事件
QApplication::postEvent(QApplication::focusWidget(), key);//发送事件给获取焦点的窗口
}
(2)自定义按键类
#ifndef HDBUTTON_H
#define HDBUTTON_H
#include <QObject>
#include <QPushButton>
#include <QApplication>
#include <QDebug>
#include <QKeyEvent>
class HDButton : public QPushButton
{
public:
explicit HDButton(QWidget *parent = nullptr);
explicit HDButton(const QString &text, QWidget *parent = nullptr);
HDButton(const QIcon& icon, const QString &text, QWidget *parent = nullptr);
//实现鼠标点击事件
void mousePressEvent(QMouseEvent *e);
};
#endif // HDBUTTON_H
#include "hdbutton.h"
HDButton::HDButton(QWidget *parent):QPushButton(parent){}
HDButton::HDButton(const QString &text, QWidget *parent):QPushButton (text, parent){}
HDButton::HDButton(const QIcon &icon, const QString &text, QWidget *parent):QPushButton (icon,text, parent){}
void HDButton::mousePressEvent(QMouseEvent *e)
{
//获取按钮的字符
QString str = this->text();
char ch = str.at(0).toLatin1();
//创建按钮事件
QKeyEvent *key = new QKeyEvent(QKeyEvent::KeyPress, ch,Qt::NoModifier,str);
//发送事件
QApplication::postEvent(QApplication::focusWidget(), key);//发送事件给获取焦点的窗口
}
8 、截屏实现
参考:(301条消息) 基于QT的截图_samson_samson的博客-优快云博客
#include <QApplication>
#include <QPixmap>
#include <QScreen>
//截屏
// QPixmap mmp = QApplication::screens().at(0)->grabWindow(this->winId());//截取当前窗口
//QPixmap mmp = QApplication::screens().at(0)->grabWindow(0);//截取桌面
QPixmap mmp = QApplication::screens().at(0)->grabWindow(0, 100, 100, 800, 480);//截取部分桌面
mmp.save("./my.jpg");
ui->label->setPixmap(mmp);
/details/79975619)
```c++
#include <QApplication>
#include <QPixmap>
#include <QScreen>
//截屏
// QPixmap mmp = QApplication::screens().at(0)->grabWindow(this->winId());//截取当前窗口
//QPixmap mmp = QApplication::screens().at(0)->grabWindow(0);//截取桌面
QPixmap mmp = QApplication::screens().at(0)->grabWindow(0, 100, 100, 800, 480);//截取部分桌面
mmp.save("./my.jpg");
ui->label->setPixmap(mmp);