Qt学习记录(九)事件

目录

前言:

注意:! 因为第一次写的代码出问题(能力不足)我给全删了,后续重写了一遍,但有个文件的名字和之前的不一样了,MyWdiget和Wdiget是同一个文件,大家复制代码的时候记得留意一下

一,理解

1,文档解释

 2,gpt解释

二,前置

1,新建工程

2,添加标签

3,添加C++类 

 4,更改类名

 5,头文件   #include

三,代码和现象

1,鼠标按下:显示鼠标在事件窗口的(x,y)

2,按下鼠标的左中右,改变事件颜色

3,同理更改,鼠标释放和移动

4,鼠标进入离开事件窗口

​编辑

5,定时器,计时器

6,两个定时器 

四,事件的接受和忽略

1,自定义按钮,,提升到ui

2,按钮被按下,打印

3,重写按钮的鼠标按下事件

4,解释 

5,处理

​编辑五,是否关闭窗口

六,event()

1,QEvent的Public Functions(公有函数)

 (1)QEvent::Type QEvent::type() const

七,事件过滤器

gpt


前言:

亲吻小猫咪

注意:! 因为第一次写的代码出问题(能力不足)我给全删了,后续重写了一遍,但有个文件的名字和之前的不一样了,MyWdiget和Wdiget是同一个文件,大家复制代码的时候记得留意一下


一,理解

1,文档解释

事件(event)是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件在对用户操作做出响应时发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件。

在前面我们也曾经简单提到,Qt 程序需要在main()函数创建一个QApplication对象,然后调用它的exec()函数。这个函数就是开始 Qt 的事件循环。在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件。当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于QEvent。在事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler)

 2,gpt解释

在Qt中,事件(Event)是一种消息机制,用于处理用户输入、系统通知等各种事件。Qt中的事件机制遵循了观察者模式,通过事件的发送者和接收者之间的分离,实现了模块之间的解耦。

Qt中的事件主要包括两类:基本事件(Basic Event)和自定义事件(Custom Event)。基本事件是Qt已经定义好的事件,比如鼠标点击事件、键盘按下事件等;而自定义事件则是用户可以自定义的事件,用于实现特定的功能。

理解Qt事件的关键概念包括:

  1. 事件发送和接收:事件由发送者发送到接收者,接收者通过重写特定的事件处理函数来处理事件。比如,QWidget中的event函数可以处理各种事件,如鼠标事件、键盘事件等。

  2. 事件过滤器:事件过滤器是一种机制,允许在事件到达接收者之前拦截事件并进行处理。通过安装事件过滤器,可以在不修改接收者代码的情况下对事件进行处理。

  3. 事件分发:Qt中的事件分发机制会根据事件的类型和接收者的状态将事件分派到合适的接收者进行处理。事件分发的过程是自动的,开发者通常无需关心具体的分发细节。

  4. 事件循环:Qt应用程序在运行时会进入事件循环,不断地从事件队列中取出事件并将其分发给对应的接收者进行处理。事件循环保证了用户交互和系统通知等事件能够得到及时处理。

总的来说,理解Qt事件就是理解事件的发送和接收机制、事件的处理方式以及事件循环的工作原理。通过深入学习Qt事件机制,可以更好地处理用户输入、实现界面交互以及优化应用程序的性能。

二,前置

1,新建工程

2,添加标签

3,添加C++类 

 4,更改类名

 5,头文件   #include <QMouseEvent>

  1. Qt::MouseButton button() const:返回鼠标事件的按钮。
  2. Qt::MouseButtons buttons() const:返回鼠标事件中所有按下的按钮的组合。
  3. Qt::MouseEventFlags flags() const:返回鼠标事件的标志。
  4. QPoint globalPos() const:返回鼠标事件在屏幕上的全局位置。
  5. int globalX() const:返回鼠标事件在屏幕上的全局X坐标。
  6. int globalY() const:返回鼠标事件在屏幕上的全局Y坐标。
  7. const QPointF &localPos() const:返回鼠标事件在接收事件的窗口内的位置。
  8. QPoint pos() const:返回鼠标事件在接收事件的窗口内的位置。
  9. const QPointF &screenPos() const:返回鼠标事件在屏幕上的位置。
  10. Qt::MouseEventSource source() const:返回鼠标事件的来源。
  11. const QPointF &windowPos() const:返回鼠标事件在接收事件的窗口内的位置。
  12. int x() const:返回鼠标事件在接收事件的窗口内的X坐标。
  13. int y() const:返回鼠标事件在接收事件的窗口内的Y坐标。

三,代码和现象

1,鼠标按下:显示鼠标在事件窗口的(x,y)

//鼠标按下
void MyLabel ::mousePressEvent(QMouseEvent *ev)
{
    int i = ev ->x();
    int j = ev ->y();
    //sprinf
    /*
     *QString str =QString ("abc %1 ^_^ %2").arg(123).arg("milk");
     * str = abc 123 ^_^ milk
     */

    QString text = QString("<center><h1>Mouse Press:(%1,%2)</h1></center>")
                            .arg(i).arg(j);

    this->setText(text);
}

QString text = QString("<center><h1>Mouse Press:(%1,%2)</h1></center>")
.arg(i).arg(j);
  1. QString text:定义了一个QString类型的变量text,用于存储格式化后的字符串。
  2. QString("<center><h1>Mouse Press:(%1,%2)</h1></center>"):创建了一个QString对象,其中包含一个HTML格式的字符串,其中(%1,%2)是占位符,用于稍后用具体的数值替换。
  3. .arg(i).arg(j):使用arg()函数将变量i和j的值分别填充到占位符(%1,%2)中,生成最终的格式化后的字符串。

最终,text会包含形如<center><h1>Mouse Press:(i,j)</h1></center>的格式化字符串,其中i和j分别代表鼠标按下事件发生时的X和Y坐标。您可以将这个字符串用于显示鼠标按下事件的坐标信息。

2,按下鼠标的左中右,改变事件颜色

//鼠标按下
void MyLabel ::mousePressEvent(QMouseEvent *ev)
{
    int i = ev ->x();
    int j = ev ->y();
    //sprinf
    /*
     *QString str =QString ("abc %1 ^_^ %2").arg(123).arg("milk");
     * str = abc 123 ^_^ milk
     */
    QString text = QString("<center><h1>Mouse Press:(%1,%2)</h1></center>")
                            .arg(i).arg(j);
    this->setText(text);

    if(ev->button() == Qt::LeftButton)
        {
        this -> setStyleSheet ("QLabel {"
                                   "background-color:blue;"
                                   "}");
        }
    else if(ev->button()==Qt::RightButton)
        {
        this -> setStyleSheet ("QLabel {"
                                   "background-color:red;"
                                   "}");
        }
    else if (ev->button() == Qt::MidButton)
        {
        this -> setStyleSheet ("QLabel {"
                                   "background-color:green;"
                                   "}");
        }

}

3,同理更改,鼠标释放和移动

#include "mylabel.h"
#include <QMouseEvent>
#include <QDebug>

MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{
    //设定默认追踪鼠标
    this ->setMouseTracking(true);
}

//鼠标按下,显示Mouse Press:(x,y)
void MyLabel ::mousePressEvent(QMouseEvent *ev)
{
    int i = ev ->x();
    int j = ev ->y();
    //sprinf
    /*
     *QString str =QString ("abc %1 ^_^ %2").arg(123).arg("milk");
     * str = abc 123 ^_^ milk
     */
    QString text = QString("<center><h1>Mouse Press:(%1,%2)</h1></center>")
                            .arg(i).arg(j);
    this->setText(text);
//按下鼠标左键背景变成蓝色,中键背景变成红色,左键背景变成绿色
    if(ev->button() == Qt::LeftButton)
        {
        this -> setStyleSheet ("QLabel {"
                                   "background-color:blue;"
                                   "}");
        }
    else if(ev->button()==Qt::RightButton)
        {
        this -> setStyleSheet ("QLabel {"
                                   "background-color:red;"
                                   "}");
        }
    else if (ev->button() == Qt::MidButton)
        {
        this -> setStyleSheet ("QLabel {"
                                   "background-color:green;"
                                   "}");
        }

}

//鼠标释放,显示Mouse Release:(x,y)
void MyLabel::mouseReleaseEvent(QMouseEvent *ev)
{
    QString text = QString("<center><h1>Mouse Release:(%1,%2)</h1></center>")
                            .arg( ev->x()).arg(ev->y());
    //边框:5像素,黑色
    this->setStyleSheet ("QLabel {"
                         "border: 5px solid black;"
                         "}");

    this->setText(text);
}

//鼠标移动,显示Mouse Move:(x,y),
void MyLabel::mouseMoveEvent(QMouseEvent *ev)
{
    QString text = QString("<center><h1>Mouse Move:(%1,%2)</h1></center>")
                            .arg( ev->x()).arg(ev->y());
    //边框:5像素,红色
    this->setStyleSheet ("QLabel {"
                         "border: 5px solid red;"
                         "}");

    this->setText(text);

}

4,鼠标进入离开事件窗口

void MyLabel::enterEvent(QEvent *e)
{
    QString text = QString("<center><h1>Mouse enter</h1></center>");
    this->setText(text);

}

void MyLabel::leaveEvent(QEvent *e)
{
    QString text = QString("<center><h1>Mouse leave</h1></center>");
    this->setText(text);


}

5,键盘按下,打印字母

.h文件声明

#include <QKeyEvent>
protected:
    void keyPressEvent(QKeyEvent *ev) ;

 代码

#include<QDebug>
void MyWidget::keyPressEvent(QKeyEvent *e)
{
    qDebug() <<(char) e ->key();

}

现象

5,定时器,计时器

定时器

.h
protected:
void timerEvent (QTimerEvent *e);

private:
int timerId;



.cpp
MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    ui->label-> setStyleSheet ("QLabel {"
                               "border: 2px solid black;"
                               "}");
    timerId = this-> startTimer (1000);//毫秒为单位 每隔一秒触发一次定时器
}
void MyWidget::timerEvent(QTimerEvent *e)
{
    static int sec =0;
    sec++;
    ui-> label->setText(
                QString("<center><h1>time out:(%1)</h1></center>")
                        .arg(sec)
                );
    if(5 == sec)//5秒后停止
    {
        //停止定时器
        this ->killTimer(this->timerId);
    }
}

现象

6,两个定时器 

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->label-> setStyleSheet ("QLabel {"
                               "border: 2px solid black;"
                               "}");
    timerId = this-> startTimer (1000);//毫秒为单位 每隔一秒触发一次定时器
    this->timerId2 = this->startTimer(500);
}

void Widget::timerEvent(QTimerEvent *e)
{
    static int sec =0;
    sec++;

    if(e->timerId()==this->timerId)
    {
        ui-> label->setText(
                    QString("<center><h1>time out:(%1)</h1></center>")
                            .arg(sec)
                    );
        if(5 == sec)
        {
            //停止定时器
            this ->killTimer(this->timerId);
        }
    }
    else if(e->timerId()==this->timerId2)
    {
        ui-> label_2 ->setText(
                    QString("<center><h1>time out:(%1)</h1></center>")
                            .arg(sec)
                    );
    }

}

四,事件的接受和忽略

1,自定义按钮,,提升到ui

更改类名等,,

#ifndef MYBUTTON_H
#define MYBUTTON_H

#include <QPushButton>

class MyButton : public QPushButton
{
    Q_OBJECT
public:
    explicit MyButton(QWidget *parent = nullptr);

signals:

};

#endif // MYBUTTON_H
.pro文件
CONFIG += c++11

2,按钮被按下,打印

.cpp

#include<QPushButton>
#include<QDebug>

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MyWidget)
{
    connect(ui -> pushButton  , &MyButton::clicked,
            [=]()
            {
                qDebug()<<("按钮被按下");

            });
}

3,重写按钮的鼠标按下事件

mybutton.h

#include <QPushButton>

protected:
 void mousePressEvent (QMouseEvent *e) ;
///
.cpp

void MyButton::mousePressEvent (QMouseEvent *e)
{
    if(e->button()==Qt::LeftButton)
    {
        //如果左键被按下
        qDebug()<<"按下的是左键";
    }
    else
    {
        //不作处理
        QPushButton::mousePressEvent(e);
    }
}

现象

"按下的是左键"   覆盖了  "按钮被按下"

自定义按钮被打印了,但是clicked没有

4,解释 

在图形用户界面应用程序中,事件的传递和忽略是一个重要的概念。在Qt中,事件传递是基于事件处理器的机制,每个QObject都可以处理事件。事件传递的基本原则是:事件从父对象传递到子对象,直到有对象处理该事件为止。如果某个对象处理了事件,则该事件不会传递给其他对象。

下面是一些关于事件传递和忽略的常见情况和方法:

  1. 事件的传递:当一个事件发生时,它首先被发送给应用程序的事件循环,然后传递给适当的对象进行处理。事件的传递路径是从父对象到子对象的层次结构中进行传递的。如果某个对象处理了事件,该事件就会被停止传递。

  2. 事件的忽略:如果一个对象不想处理某个特定事件,可以调用ignore()方法来通知Qt框架忽略该事件。这样,事件将继续传递给对象的父对象或其他对象进行处理。

  3. 重写事件处理器:可以通过重写特定的事件处理器函数来处理或忽略特定类型的事件。例如,对于鼠标事件,可以重写mousePressEvent()mouseReleaseEvent()等函数来处理鼠标点击事件。

  4. 过滤器:可以为对象安装事件过滤器,通过重写eventFilter()函数来拦截并处理特定类型的事件。在eventFilter()函数中,可以决定是否忽略该事件或者继续传递给对象的默认事件处理器。

5,处理

void MyButton::mousePressEvent (QMouseEvent *e)
{
    if(e->button()==Qt::LeftButton)
    {
        //如果左键被按下
        qDebug()<<"按下的是左键";
    }
    else
    {
        //不作处理
        //QPushButton::mousePressEvent(e);
    }
    QPushButton::mousePressEvent(e);
}

五,是否关闭窗口

.h
protected:
void closeEvent(QCloseEvent *e);
///
.cpp
void MyWidget::closeEvent(QCloseEvent *e)
{
    int ret =QMessageBox::question(this,"question","是否需要关闭窗口");
    if(ret == QMessageBox::Yes)
        {
         //关闭窗口
         //处理关闭窗口事件,接收事件,事件就不会再往下传递
         e->accept();
        }
     else
        {
        //不关闭窗口
        //忽略事件,事件继续传递给父组件传递
        e ->ignore();
        }
}

六,event()

1,QEvent的Public Functions(公有函数)

  • QEvent(QEvent::Type type):

    • 构造函数。构造指定 type 类型的事件对象。type 参数是 QEvent::Type 枚举中的一个值,用于定义事件的类型。
  • virtual ~QEvent():

    • 析构函数。析构函数是虚拟的,允许对派生类进行适当的清理。
  • void accept():

    • 设置事件对象的接受标志。这表示事件接收者已处理该事件,并且不应进一步处理该事件。
  • void ignore():

    • 清除事件对象的接受标志。这表示事件尚未被处理,如果需要的话,应继续处理。
  • bool isAccepted() const:

    • 如果事件被接受,则返回 true;否则返回 false。这指示事件接收者是否已接受事件。
  • void setAccepted(bool accepted):

    • 将事件对象的接受标志设置为 accepted。如果 accepted 为 true,则表示事件已被处理;如果为 false,则表示事件尚未被处理。
  • bool spontaneous() const:

    • 如果事件是自发事件,则返回 true;否则返回 false。自发事件由系统生成(例如鼠标或键盘事件),而不是应用程序明确发布的事件。
  • QEvent::Type type() const:

    • 返回事件的类型。这是 QEvent::Type 枚举中的一个值,表示事件的种类(例如 QEvent::MouseButtonPressQEvent::KeyPress 等)。
  • 这些函数允许您管理事件的生命周期,确定其类型,并控制是否应让应用程序中的其他事件处理程序进一步处理该事件。

 (1)QEvent::Type QEvent::type() const

widget.h
    protected:
        //重写event事件
        bool event(QEvent,*);

widget.cpp
    #include<QEvent>
    bool Widget::event(QEvent *e)
     {
         //事件分发
         if(e->type() == QEvent::Timer)
         {
             //干掉计时器
             //如果返回true,事件停止传播
             //QTimerEvent *e
         
             QTimerEvent *env = static_cast<QTimerEvent *>(e);
             timerEvent(env);
             return true;
         }
         else if(e->type() == QEvent :: KeyPress)
         {
             QKeyEvent *env = static_cast<QKeyEvent *>(e);
             if(env->key() == Qt::Key_B)
             {
                 return QWidget::event(e);
             }
             return  true;
         }
         else
         {
            return QWidget::event(e);
           // return false;
            /*event()容易导致事件无效*/
         }
     }
    

七,事件过滤器

event()比较麻烦

gpt

事件过滤器(Event Filter)在Qt框架中是一个非常有用的机制,它允许开发者拦截并处理在对象之间传播的事件。以下是事件过滤器的主要用途:

  1. 拦截事件:事件过滤器可以拦截发送给特定对象(被监视对象)的事件,这样在事件到达该对象之前,过滤器可以先对事件进行处理。

  2. 全局事件处理:通过安装事件过滤器,可以在整个应用程序范围内对特定类型的事件进行监控和处理,而不必在每个可能接收事件的类中重写event()函数。

  3. 解耦代码:事件过滤器提供了一种将事件处理逻辑从UI逻辑中分离的方法,有助于保持代码的模块化和可维护性。

  4. 动态事件处理:事件过滤器可以在运行时动态地添加或移除,这意味着可以动态地改变事件处理行为,而无需修改对象的代码。

  5. 精确的事件控制:事件过滤器可以精确控制哪些事件应该被处理,哪些应该被忽略或传递给其他对象。

  6. 调试和监控:事件过滤器可以用于监控事件流,这在调试应用程序时非常有用。

事件过滤器的核心是QObject::eventFilter()函数,其原型如下:

bool QObject::eventFilter(QObject *watched, QEvent *event);
Copy

当一个事件被发送给watched对象时,eventFilter()会被调用。如果eventFilter()返回true,则事件将被视为已处理,不会传递给watched对象。如果返回false,事件将继续传递给watched对象。

widget.h

protected:
    //事件过滤器
    bool eventFilter(QObject *,QEvent *);

widget.cpp

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
  /**************这里有一堆代码(忽略)*****************/    
    //安装过滤器
    ui->label_2->installEventFilter(this);
}

//事件过滤器
 bool Widget::eventFilter(QObject *obj,QEvent *e)
 {
     if(obj == ui->label_2)
     {
         QMouseEvent *env = static_cast<QMouseEvent *>(e);
         //判断事件
         if(e->type() == QEvent::MouseMove)
         {
             ui->label_2->setText(QString("Mouse move:(%1,%2)").arg(env->x()));
             return true;
         }
         if(e->type() == QEvent::MouseButtonPress)
         {
             ui->label_2->setText(QString("Mouse press:(%1,%2)").arg(env->x()));
             return true;
         }
         if(e->type() == QEvent::MouseButtonRelease)
         {
             ui->label_2->setText(QString("Mouse Release:(%1,%2)").arg(env->x()));
             return true;
         }
         else
         {
             return QWidget::eventFilter(obj,e);
         }

     }
     else
     {
         return QWidget::eventFilter(obj,e);
     }
     
 }

  • 22
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值