Qt系统相关——事件

文章目录

事件和信号槽的关系

Qt信号槽机制: 用户进行的操作就可能产生信号,可以给某个信号指定槽函数,当信号触发的时候,就能够执行到对应的槽函数。

对于事件,和信号槽类似,用户进行的各种操作,也会产生事件,可以给事件关联处理函数,当事件触发的时候,就能够执行到对应的代码。

事件本身是由操作系统提供的机制,Qt将操作系统事件机制进行封装。

但是事件对应的代码编写起来不方便,Qt对事件机制又继续了进一步封装,就得到了信号槽。

事件是信号槽的底层机制

大部分情况都是采用信号槽,但对于有些行为,Qt没有提供对应的信号,此时就需要重写事件处理函数,来手动处理事件的响应逻辑了。

事件机制,灵活度更高。

常见Qt事件:

常见事件描述:

事件名称 描述
鼠标事件 鼠标左键、鼠标右键、鼠标滚轮、鼠标的移动、鼠标按键的按下和松开
键盘事件 按键类型、按键按下、按键松开
定时器事件 定时时间到达
进入离开事件 鼠标的进入和离开
滚轮事件 鼠标滚轮滚动
绘屏事件 重绘屏幕的某些部分
显示隐藏事件 窗口的显示和隐藏
移动事件 窗口位置的变化
窗口事件 是否为当前窗口
大小改变事件 窗口大小改变
焦点事件 键盘焦点移动
拖拽事件 用鼠标进行拖拽

事件处理

事件处理就是让一段代码和某个事件关联起来,当事件触发的时候,就能指定到这段代码。

之前信号槽是通过connect来完成上述关联的;

对于事件,让当前的类,重写某个事件处理函数。

属于多态机制,创建子类,继承Qt自己的类,然后重新父类的事件处理函数。

鼠标事件

鼠标进入和离开

处理一下鼠标的进入和离开事件

ui界面:

创建QLabel的子类,然后重写enterEventleaveEvent

label.h

cpp 复制代码
#ifndef LABEL_H
#define LABEL_H

#include <QWidget>
#include<QLabel>
class Label : public QLabel
{
    Q_OBJECT
public:
    Label(QWidget* parent);
    
    void enterEvent(QEvent* event);
    void leaveEvent(QEvent* event);
};

#endif // LABEL_H

label.cpp

cpp 复制代码
#include "label.h"
#include<QDebug>
Label::Label(QWidget* parent)
    : QLabel(parent)
{
    
}

void Label::enterEvent(QEvent *event)
{
    (void)event;
    qDebug() << "enterEvent";
}

void Label::leaveEvent(QEvent *event)
{
    (void)event;
    qDebug() << "leaveEvent";    
}

此时重写完毕之后,只是对于Label,而界面是的是QLabel

要确保界面上的label是我们自定义的实例,才会执行到这两个函数。

鼠标点击获取位置

label.cpp

cpp 复制代码
#include "label.h"
#include<QDebug>
#include<QMouseEvent>
Label::Label(QWidget* parent)
    :QLabel(parent)
{}

void Label::mousePressEvent(QMouseEvent *event)
{
    //当前控件左上角为原点
    qDebug() << event->x() << "," << event->y();
    //屏幕左上角为原点
    qDebug() << event->globalX() << "," << event->globalY();
}

这个函数可以触发鼠标的各种按键,例如左键、右键、滚轮等

cpp 复制代码
#include "label.h"
#include<QDebug>
#include<QMouseEvent>
Label::Label(QWidget* parent)
   :QLabel(parent)
{}

void Label::mousePressEvent(QMouseEvent *event)
{
   if(event->button() == Qt::LeftButton)
   {
       qDebug() << "左键触发"; 
   }
   else if(event->button() == Qt::RightButton)
   {
       qDebug() << "右键触发";	
   }
   //当前控件左上角为原点
   qDebug() << event->x() << "," << event->y();
   //屏幕左上角为原点
   qDebug() << event->globalX() << "," << event->globalY();
}

鼠标释放

基于上面的代码,重写鼠标释放函数

cpp 复制代码
void Label::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        qDebug() << "左键释放";
    }
    else if(event->button() == Qt::RightButton)
    {
        qDebug() << "右键释放";
    }
}

一次clicked,相当于鼠标一次按下事件+一次释放事件

鼠标双击

重写双击虚函数

cpp 复制代码
void Label::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        qDebug() << "左键双击";
    }
    else if(event->button() == Qt::RightButton)
    {
        qDebug() << "右键双击";
    }
}

这里双击的时候,也会触发单击的事件,这就又有可能导致意外的情况

鼠标移动

上面都是在Label控件里面进行活动,也可以直接放到Widget里面来完成。

widget.h

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void mouseMoveEvent(QMouseEvent* event);

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QMouseEvent>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    qDebug() << event->x() << event->y();
}

上面的代码,不会直接移动的时候捕获位置,因为鼠标经常移动,稍微移动一下,就会产生大量的鼠标移动事件。

在捕获事件的时候,如果这里逻辑很复杂,就会导致程序特别卡顿。

为了保证程序流畅性,默认不会对鼠标移动进行追踪,鼠标移动的时候,不会调用mouseMoveEvent,除非显式告诉Qt

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setMouseTracking(true);
}

鼠标滚轮

通过wheelEvent

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QMouseEvent>
#include<QWheelEvent>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    total = 0;
}

Widget::~Widget()
{
    delete ui;
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    qDebug() << event->x() << event->y();
}

void Widget::wheelEvent(QWheelEvent *event)
{
    total += event->delta();
    qDebug() << total;
}

键盘事件

QShortCut定义一个快捷键,然后搭配QKeySequence这个类,指定当前按键是什么按键序列。如果按下这个键,就触发actived信号。这是信号槽机制封装过的,获取键盘按键的快捷方式。

也可以通过事件获取到当前用户键盘按下的情况。

重写一个父类函数,keyPressEvent

单个按键:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QKeyEvent>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    qDebug() << event->key();
}

组合按键:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QKeyEvent>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_A && event->modifiers() == Qt::ControlModifier)
    {
        qDebug() << "alt + A";
    }
}

定时器事件

可以使用QTimer这个类来完成定时器这个功能。

QTimer背后是QTimerEvent定时器事件来进行支撑;

QObject提供了timerevent这个函数:

  • startTimer启动定时器
  • killTimer关闭定时器

widget.h

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void timerEvent(QTimerEvent *event);
private:
    Ui::Widget *ui;
    int timerId;
};
#endif // WIDGET_H

widget.cpp

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //开启定时器事件
    //startTimer由QObject提供
    //Widget继承QWidget
    //QWidget继承QObject

    //返回一个整数,定时器身份标识
    timerId = this->startTimer(1000);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::timerEvent(QTimerEvent *event)
{
    //一个程序存在多个定时器, 每个定时器都会触发这个函数
    //需要判断,这次触发是否是想要的定时器触发的
    if(event->timerId() != this->timerId)
    {
        return;
    }
    int value = ui->lcdNumber->intValue();
    if(value <= 0)
    {
        this->killTimer(this->timerId);
        return;
    }
    value -= 1;
    ui->lcdNumber->display(value);
}

窗口移动和窗口改变

  • moveEvent窗口移动时触发的事件
  • resizeEvent窗口大小改变时触发的事件
cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QMoveEvent>
#include<QResizeEvent>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::moveEvent(QMoveEvent *event)
{
    qDebug() << event->pos();
}

void Widget::resizeEvent(QResizeEvent *event)
{
    qDebug() << event->size();
}
相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00616 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术16 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript