Qt事件及其处理


事件是应用程序内部或者外部产生的事情或者动作的统称

img

例如:

  • 鼠标事件
  • 键盘事件
  • 定时器事件

就好比是信号那样子

事件处理

事件处理⼀般常用的方法为:重写相关的 Event 函数

在qt中几乎所有的 Event 函数都是虚函数,所以可以重新实现业务处理。

鼠标事件

进入离开事件

img

img

实现一个鼠标进入到 label 控件和离开 label 控件时分别修改 label 的文本

img

首先需要新建一个 QLabel 的子类并重写这两个事件

img

注意,在进行下面的操作前,需要先把控件给提升为自己新建的类,否则操作自己新建的类是不会对控件产生效果的。因为没有提升之前的空间是属于 QWidget的

接着在 mylabel.cpp 中重写这两个事件虚函数

void MyLabel::enterEvent(QEvent *event)
{
    (void)event;
    this->setText("鼠标进来了");
}

void MyLabel::leaveEvent(QEvent *event)
{
    (void)event;
    this->setText("鼠标离开了");
}

img

单击事件

img

这个点击事件包含了鼠标上的 左键、右键、滚轮以及侧键这些标准按键的点击事件。

注意这个 mousePressEvent 函数的参数,这个参数里包含了鼠标点击的坐标,其中坐标又可以分为两种

  1. 直接调用 x y:这是相对于点击的控件的坐标
  2. 调用 globalx globaly:这是相当于屏幕的坐标

因此基于以上性质,实现一个鼠标左键点击则打印相对控件坐标,鼠标右键点击则打印相对屏幕坐标,滚轮则打印 滚轮 两个字

void MyLabel::mousePressEvent(QMouseEvent *event)
{
    // 鼠标左键
    if(event->button() == Qt::LeftButton)
    {
        this->setText("左键:" +
                      QString::number(event->x()) +
                      ", " +
                      QString::number(event->y()));
    }

    // 鼠标右键
    if(event->button() == Qt::RightButton)
    {
        this->setText("右键:" +
                      QString::number(event->globalX()) +
                      ", " +
                      QString::number(event->globalY()));
    }

    // 鼠标滚轮
    if(event->button() == Qt::MidButton){
        this->setText("滚轮");
    }
}

img

释放事件

不同于单击事件,这个需要点了之后必须释放才会触发,而单击事件只要点了不释放也会释放。

img

void MyLabel::mouseReleaseEvent(QMouseEvent *event)
{
    // 鼠标左键
    if(event->button() == Qt::LeftButton)
    {
        this->setText("左键释放");
    }

    // 鼠标右键
    if(event->button() == Qt::RightButton)
    {
        this->setText("右键释放");
    }

    // 鼠标滚轮
    if(event->button() == Qt::MidButton){
        this->setText("滚轮释放");
    }
}

img

双击事件

需要鼠标双击才可以触发

img

void MyLabel::mouseDoubleClickEvent(QMouseEvent *event)
{
    // 鼠标左键
    if(event->button() == Qt::LeftButton)
    {
        this->setText("左键双击");
    }

    // 鼠标右键
    if(event->button() == Qt::RightButton)
    {
        this->setText("右键双击");
    }

    // 鼠标滚轮
    if(event->button() == Qt::MidButton){
        this->setText("滚轮双击");
    }
}

img

移动事件

鼠标移动时触发

img

这个需要搭配 setMouseTracking 函数使用,由于鼠标的追踪状态默认是关闭的,所以需要 setMouseTracking 设为true,否则鼠标只有在点击的时候才会触发。

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

    // 设置鼠标追踪状态
    setMouseTracking(true);
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    ui->label->setText("鼠标位置:" +
                       QString::number(event->x()) +
                       ";" +
                       QString::number(event->y()));
}

img

滚轮事件

img

img

滚轮事件的参数为 QWheelEvent 类型,这个类里面有一个函数 delta 用来获取滚轮滑动的距离。

void Widget::wheelEvent(QWheelEvent *event)
{
    static int x = 0;
    x += event->delta();
    ui->label->setText("滚轮滑动距离:" +
                       QString::number(x));
}

img

按键事件

按键事件是通过 QKeyEvent 类来实现的

单个按键按下

img

void Widget::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_A)
        ui->label->setText("A按键被按下");
    if(event->key() == Qt::Key_B)
        ui->label->setText("B按键被按下");
}

img

组合按键

代码说明
Qt::NoModifier无修改
Qt::ShiftModifierShift
Qt::ControlModifierCtrl
Qt::AltModifierAlt
Qt::MetaModifierMeta(Win/Command)
Qt::KeypadModifier数字键盘
Qt::GroupSwitchModifier输入法之间切换

这些都是定义了在处理键盘事件时对应的修改键,这些修改键可以和键盘事件组合使用。

void Widget::keyPressEvent(QKeyEvent *event)
{
    if(event->modifiers() == Qt::ControlModifier)
    {
        if(event->key() == Qt::Key_A)
            ui->label->setText("Ctrl + A按键被按下");
        if(event->key() == Qt::Key_B)
            ui->label->setText("Ctrl + B按键被按下");
    }
}

img

定时器事件

Qt中的定时器分为 QTimerEvent 和 QTimer

  • QTimerEvent 用来描述一个定时器事件。需要通过 startTimer 函数开启一个定时器,以毫秒为单位,返回值代表这个定时器。当事件到了就可以在 timerEvent 函数中获取该定时器的编号来进行业务处理
  • QTimer 用来实现一个定时器,相比前者有更高层次的接口,可以使用信号和槽,也可以设置只运行一次

QTimerEvent

首先添加定时器和需要显示的变量为类的私有成员变量,重写时才可以调用得到

img

重写事件

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

    // 启动定时器
    timer1 = startTimer(1000);
    timer2 = startTimer(2000);
}

void Widget::timerEvent(QTimerEvent *e)
{
    // timer1定时器管理label_1
    if(e->timerId() == timer1)
        ui->label->setText(QString::number(num1++));

    // timer2定时器管理label_2
    if(e->timerId() == timer2)
        ui->label_2->setText(QString::number(num2++));
}

img

QTimer

设计一个倒计时器,使用 QLCDNumber 控件来显示

QLCDNumber *num = new QLCDNumber(this);
num->display(5); num->setGeometry(100, 100, 100, 100);
num->setSegmentStyle(QLCDNumber::Flat);

// 创建QTimer定时器成员
QTimer *time = new QTimer(this);
// 每个一秒显示器的数字减1,数字为0时关闭定时器
connect(time, &QTimer::timeout, this, [=](){
    int n = num->intValue();
    if(n <= 0)
    {
        time->stop();
        Widget::close(); // 关闭窗口
    }
    num->display(n - 1);
});
// 设置定时器每隔一秒触发一次
time->start(1000);

img

获取系统日期及时间

获取系统的日期及实时时间可以通过 QTimer 类 和 QDateTime类

QDateTime 类提供了字符串格式的时间。字符串形式的时间输出格式由 toString() 方法中的 format 参数列表决定。

实现显示实时时间

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

    QTimer *timer = new QTimer(this);

    // 每隔一秒更新一次实时时间
    connect(timer, &QTimer::timeout, this, [=](){
        // 获取实时时间并格式化
        QString s = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
        // 显示到 label
        ui->label->setText(s);
    });

    // 启动定时器
    timer->start(1000);
}

img

事件分发器

事件分发器负责将事件从⼀个对象传递到另⼀个对象,直到事件被处理或被取消。

每个继承自 QObject 类或 QObject 类本⾝都可以在本类中重写 bool event(QEvent *e) 函数,来实现相关事件的捕获和拦截。

img

event 函数如果返回 true 就不会再向下分发了。

// 事件分发器处理
bool Widget::event(QEvent *event)
{
    if(event->type() == QEvent::MouseButtonPress)
    {
        ui->label->setText("事件分发器");
        return true; // 返回 true 就不会再将事件分给其他的event函数了
    }

    // 其他事件交给父类处理
    return QWidget::event(event);
}

// 鼠标释放事件处理
void Widget::mousePressEvent(QMouseEvent *event)
{
    (void)event;
    ui->label->setText("mouseReleaseEvent");
}

img

可以看到这样子鼠标单击事件就被事件分发器处理了,轮不到 mousePressEvent 去处理了。

事件过滤器

⼀个对象可能经常要查看或拦截另外⼀个对象的事件,如对话框想要拦截按键事件,不让别的组件接收到或者修改按键的默认值等。

事件过滤器是在应用程序分发到 event事件分发器之前,再做一次更高级的拦截

img

使用步骤:

  1. 安装事件过滤器
  2. 重写事件过滤器函数:eventfilter
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 给控件安装一个过滤器
    ui->label->installEventFilter(this);
}

// 事件过滤器处理
bool Widget::eventFilter(QObject *obj, QEvent *event)
{
    if(obj == ui->label)
    {
        if(event->type() == QEvent::MouseButtonPress)
        {
            ui->label->setText("事件过滤器");
            return true; // 返回 true 就不会再将事件分给其他的event函数了
        }

    }
    // 其他事件交给父类处理
    return QWidget::eventFilter(obj, event);
}

// 事件分发器处理
bool Widget::event(QEvent *event)
{
    if(event->type() == QEvent::MouseButtonPress)
    {
        ui->label->setText("事件分发器");
        return true; // 返回 true 就不会再将事件分给其他的event函数了
    }

    // 其他事件交给父类处理
    return QWidget::event(event);
}

// 鼠标释放事件处理
void Widget::mousePressEvent(QMouseEvent *event)
{
    (void)event;
    ui->label->setText("mouseReleaseEvent");
}

img

可以看到当点击安装了过滤器的控件时就不会执行到事件分发器了

  • 30
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CHJBL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值