虽然Qt是跨平台的C++开发框架,Qt的很多能力其实是操作系统提供的,只不过Qt封装了系统的API。程序试是运行在操作系统上的,需要操作系统给我们通过支撑。

一、事件

1、事件的概念

用户进行各种操作的时候。就可能会产生出信号,可以给某个信号指定槽函数,当信号触发时,就能够自动地执行对应的槽函数。

事件也非常相似,用户进行的各种操作,也会产生事件,程序员同样可以给事件关联处理函数,当事件触发的时候,就能够执行对应的处理函数。

事件本身是操作系统提供的机制,Qt也同样把操作系统事件机制进行了封装,拿到Qt中。但是由于事件对应的代码编写起来很不方便,Qt就对事件机制又进一步进行了封装,就得到了信号槽机制。所以,信号槽就是对事件的进一步封装,事件就是信号槽的底层机制。

实际Qt开发程序过程中,绝大部分和用户之间进行的交互都是通过信号槽来完成的。但是有些特殊情况下,信号槽不一定能搞定,Qt没有提供对应的信号。此时就需要通过重写事件处理函数的形式,来手动处理事件的响应逻辑。

Qt系统_Qt

2、事件的处理

事件的处理方法一般是让当前的类,重写某个事件处理函数。使用了多态机制,创建子类继承Qt已有的类,在子类中重写父类的事件处理函数。后序事件触发过程中,就会通过多态的机制,执行自定义子类重写的函数。

举个例子,处理一下鼠标进入和离开事件:

鼠标进入是enterEvent,鼠标离开是leaveEvent。我们要创建一个QLabel的子类,然后重写enterEvent和leaveEvent。

//自定义的Label
//label.cpp
#include "label.h"

Label::Label(QWidget* parent)
    :QLabel(parent)
{
          

}
//重新事件处理函数
void Label::enterEvent(QEvent *event)
{
          
    qDebug()<<"鼠标进入";
}

void Label::leaveEvent(QEvent *event)
{
          
    qDebug()<<"鼠标离开";
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

在Qt Designer中创建QLabel,然后通过点击“提升为”将其变为我们自定义的Label。

Qt系统_Qt_02

Qt系统_事件_03

2.1、鼠标事件

处理鼠标按下事件:

mousePressEvent方法是在鼠标按下时触发的事件处理函数。这个函数在按下鼠标左键、右键、滚轮都能触发,有的鼠标还有前进后退侧键,也可以触发。但又还有的鼠标,有更多的按键,就不一定能触发了。

#include "label.h"

Label::Label(QWidget *parent)
    :QLabel(parent)
{
          }

void Label::mousePressEvent(QMouseEvent *event)
{
          
    //显示按下的键
    if(event->button()==Qt::LeftButton)
    {
          
        qDebug()<<"按下左键";
    }
    else if(event->button()==Qt::RightButton)
    {
          
        qDebug()<<"按下右键";
    }
    else if(event->button()==Qt::MiddleButton)
    {
          
        qDebug()<<"按下中键";
    }
    //显示鼠标坐标
        //以Label左上角为原点的坐标
    qDebug()<<"相对坐标:"<<event->x()<<","<<event->y();
        //以窗口左上角为原点的坐标
    qDebug()<<"全局坐标:"<<event->globalX()<<","<<event->globalX();
}
  • 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.

Qt系统_Qt_04

处理鼠标释放事件与双击事件:

clicked信号就相当于一次按下事件+一次释放事件。

#include "label.h"

Label::Label(QWidget *parent)
    :QLabel(parent)
{
          }

void Label::mousePressEvent(QMouseEvent *event)
{
          
    //显示按下的键
    if(event->button()==Qt::LeftButton)
    {
          
        qDebug()<<"按下左键";
    }
    else if(event->button()==Qt::RightButton)
    {
          
        qDebug()<<"按下右键";
    }
    else if(event->button()==Qt::MiddleButton)
    {
          
        qDebug()<<"按下中键";
    }
}

void Label::mouseReleaseEvent(QMouseEvent *event)
{
          
    //显示按下的键
    if(event->button()==Qt::LeftButton)
    {
          
        qDebug()<<"释放左键";
    }
    else if(event->button()==Qt::RightButton)
    {
          
        qDebug()<<"释放右键";
    }
    else if(event->button()==Qt::MiddleButton)
    {
          
        qDebug()<<"释放中键";
    }
}

void Label::mouseDoubleClickEvent(QMouseEvent *event)
{
          
    //显示按下的键
    if(event->button()==Qt::LeftButton)
    {
          
        qDebug()<<"双击左键";
    }
    else if(event->button()==Qt::RightButton)
    {
          
        qDebug()<<"双击右键";
    }
    else if(event->button()==Qt::MiddleButton)
    {
          
        qDebug()<<"双击中键";
    }
}
  • 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.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.

Qt系统_网络_05

处理鼠标移动事件:

在上面的例子中,重写鼠标事件都是在自定义Label中完成的,此时鼠标只有在Label范围内活动,才能捕捉到。其实也可以直接把这些操作放到Widget(QWidget子类)中完成,这样的话,鼠标在整个窗口中进行的各种动作都能捕获了。

鼠标移动不同于鼠标按下,随便移动一下鼠标,就会产生大量的鼠标移动事件,当我们进行捕获时间的时候,尤其是在进行一些复杂逻辑时,程序负担就会很重,很容易产生卡顿之类的情况。Qt为了保证程序的流畅性,默认情况下不会对鼠标移动进行追踪,鼠标移动的时候不会调用mouseMoveEvent,除非显式地告诉Qt就是要追踪鼠标位置。如何告诉Qt呢?通过setMouseTracking方法把Widget的属性设置为true才能追踪鼠标的移动位置。

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QMouseEvent>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
          
    ui->setupUi(this);
    //告诉Qt要追踪鼠标位置
    this->setMouseTracking(true);
}

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

void Widget::mouseMoveEvent(QMouseEvent *event)
{
          
    qDebug()<<event->x()<<","<<event->y();
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

Qt系统_网络_06

2.2、鼠标滚轮事件
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QWheelEvent>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
          
    ui->setupUi(this);
    total=0;
}

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

void Widget::wheelEvent(QWheelEvent *event)
{
          
    total+=event->delta();
    //通过delta获取滚轮滚动的距离,正负号代表滚轮滚动的方向
    qDebug()<<total;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.

Qt系统_事件_07

2.3、键盘事件

Qt把一些用来搭配组合键的功能键单独拎出来了,使用modifiers方法。

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QKeyEvent>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    ,