C++ Qt5.9学习笔记-事件1.5W字总结

news2025/1/18 9:57:17

⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨‍🎓。
如果觉得本文能帮到您,麻烦点个赞👍呗!

近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支持一下呗。👍⭐️❤️
Qt5.9专栏定期更新Qt的一些项目Demo
项目与比赛专栏定期更新比赛的一些心得面试项目常被问到的知识点。

QT5.9专栏会定期更新有趣的Qt知识

以工程为导向进行Qt5.9的学习,打捞基础。专栏中有Qt5.9学习笔记-仿Everything的的文件搜索的GUI工具,以及相关的基础知识。
在这里插入图片描述

最近在重新梳理一下Qt事件的基础知识,发现了一些有趣的知识点和开发的坑点,做一些笔记。

当涉及到Qt5.9事件时,事件系统是非常重要的一个主题。Qt5.9事件系统是一个强大的工具,它允许开发人员在Qt应用程序中响应和处理各种类型的事件。在本文中,我们将讨论Qt5.9事件系统的基础知识以及如何在应用程序中使用它来处理事件。

目录

  • 大纲
    • 1. 事件系统基础介绍
      • 1.1 事件和事件处理的定义
      • 1.2 事件的种类和分类
      • 1.3 事件循环
    • 2. Qt5.9中的事件处理
      • 2.1 事件过滤器
      • 2.2 事件处理函数
      • 2.3 事件分发和派发
    • 3 自定义事件
      • 3.1 创建自定义事件
      • 3.2 发送和处理自定义事件
      • 3.3 使用自定义事件来扩展Qt应用程序
      • :fire:3.4 坑点的地方要注意一下:
    • 4. 多线程和事件处理
      • 4.1 理解多线程和事件处理
      • 4.2 跨线程事件的发送和处理
    • 5 Qt5.9中的常见事件
      • 5.1 定时器事件
      • 5.2 鼠标事件
      • 5.3 键盘事件
    • 6. 事件调试和排查
      • 使用断点调试
      • 打印调试信息
      • 事件调试

大纲

  1. 事件系统基础介绍
  • 事件和事件处理的定义
  • 事件的种类和分类
  • 事件循环
  1. Qt5.9中的事件处理
  • 事件过滤器
  • 事件处理函数
  • 事件分发和派发
  1. 自定义事件
  • 创建自定义事件
  • 发送和处理自定义事件
  • 使用自定义事件来扩展Qt应用程序
  1. 多线程和事件
  • 理解多线程和事件处理
  • 跨线程事件的发送和处理
  1. Qt5.9中的常见事件
  • 定时器事件
  • 鼠标事件
  • 键盘事件
  • 窗口事件
  1. 事件调试和排查
  • 调试事件处理
  • 查找事件相关问题的技巧

1. 事件系统基础介绍

1.1 事件和事件处理的定义

在Qt5.9中,事件是指在应用程序中发生的事情。这些事件可以来自操作系统或其他应用程序组件,如鼠标或键盘输入、定时器事件等。事件处理是指在Qt5.9应用程序中对这些事件进行响应和处理的机制。

1.2 事件的种类和分类

在Qt5.9中,事件可以分为以下几类:

  • QEvent: 基本事件类,所有其他事件类都派生自QEvent。
  • QInputEvent: 鼠标、键盘等输入事件类。
  • QWheelEvent: 鼠标滚轮事件类。
  • QFocusEvent: 焦点事件类。
  • QTimerEvent: 定时器事件类。
  • QResizeEvent: 窗口大小调整事件类。
  • QCloseEvent: 关闭事件类。
  • QPaintEvent: 绘制事件类。

1.3 事件循环

事件循环是Qt5.9中的核心机制之一,用于处理事件并响应应用程序的输入。在Qt5.9中,事件循环会不断地从系统事件队列中获取事件并将其派发到应用程序中的事件接收者(即QObject派生类对象)中。

Qt的事件循环是一个核心机制,用于在应用程序中处理各种类型的事件。事件循环不断地从系统事件队列中获取事件并将其派发到应用程序中的事件接收者(即QObject派生类对象)中,以便响应应用程序的输入。

事件循环在Qt中非常重要,因为它允许应用程序以一种非阻塞的方式响应用户输入。事件循环的运行方式通常是在应用程序启动时自动启动,并在应用程序关闭时自动停止。

以下是一个简单的例子,演示了如何在Qt中使用事件循环:

cppCopy code#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    QLabel label("Hello, world!");
    label.show();
    
    return app.exec(); // 启动事件循环
}

在这个例子中,我们创建了一个应用程序并在应用程序中创建了一个QLabel对象。我们将该对象显示在屏幕上,然后通过调用QApplication::exec()函数来启动事件循环。

当应用程序启动时,事件循环将开始运行。在事件循环运行期间,任何用户输入(如鼠标或键盘事件)都会被放入系统事件队列中,然后被事件循环处理。在这个例子中,我们使用了一个非常简单的应用程序,但在更复杂的应用程序中,事件循环通常是应用程序中最重要的部分之一。

需要注意的是,Qt的事件循环通常是由QApplication对象来管理的,因此在使用Qt时,通常需要创建一个QApplication对象并通过它来启动事件循环。

希望这个例子能够帮助你更好地理解Qt的事件循环。

2. Qt5.9中的事件处理

2.1 事件过滤器

事件过滤器是一种机制,它允许在事件到达目标对象之前对其进行拦截和处理。在Qt5.9中,可以通过QObject::installEventFilter()函数来为一个对象安装事件过滤器。事件过滤器需要实现QObject::eventFilter()函数,该函数将在事件到达目标对象之前被调用。

Qt5.9的事件过滤器是一种机制,用于在Qt应用程序中拦截和处理事件。它可以让我们在事件传递到目标对象之前截获事件并执行一些自定义操作,例如修改事件、记录事件、阻止事件等。

事件过滤器可以应用于任何QObject派生类对象,并通过重载QObject::eventFilter()函数来实现自定义的事件处理逻辑。事件过滤器通常被用来增强Qt应用程序的交互性、改善用户体验以及实现一些高级的功能。

以下是一个简单的例子,演示了如何在Qt中使用事件过滤器:

#include <QApplication>
#include <QPushButton>
#include <QLabel>
#include <QEvent>
#include <QDebug>

class MyEventFilter : public QObject
{
public:
    bool eventFilter(QObject* obj, QEvent* event) override
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            qDebug() << "Mouse button pressed!";
            return true; // 拦截事件
        }

        return QObject::eventFilter(obj, event);
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    QPushButton button("Click me");
    MyEventFilter filter;
    
    button.installEventFilter(&filter); // 安装事件过滤器
    
    QLabel label("Hello, world!");
    label.show();
    
    return app.exec();
}

在这个例子中,我们创建了一个QPushButton对象,并为其安装了一个事件过滤器MyEventFilter。在事件过滤器的eventFilter()函数中,我们检查事件的类型是否为QEvent::MouseButtonPress(鼠标按钮按下),如果是,则打印一条消息并返回true,表示拦截了事件。否则,我们调用了父类的eventFilter()函数,继续将事件传递到目标对象中。

通过安装事件过滤器,我们可以拦截和处理按钮的所有事件,包括鼠标事件和键盘事件等。在这个例子中,我们只处理了鼠标按钮按下的事件,并打印了一条消息。如果我们想要拦截并处理其他类型的事件,只需要在eventFilter()函数中进行相应的处理即可。

总的来说,事件过滤器在Qt应用程序中有很多应用场景,例如捕获和处理快捷键、记录用户操作、实现拖放等。它可以让我们更加灵活地控制和定制Qt应用程序的事件处理逻辑。

2.2 事件处理函数

事件处理函数是指为一个对象实现的用于处理特定事件的函数。在Qt5.9中,可以为QObject派生类对象实现特定事件的处理函数,例如:

cppCopy codevoid MyWidget::mousePressEvent(QMouseEvent* event)
{
    // 处理鼠标按下事件
}

2.3 事件分发和派发

简单来说,就是当操作系统接收到事件并将其传递给Qt应用程序时,Qt框架会将该事件封装成QEvent对象,并将其插入到事件队列中。事件分发机制会不断从事件队列中取出事件,并将其分发到正确的QObject派生类对象中进行处理。

#include <QApplication>
#include <QWidget>
#include <QKeyEvent>

class MyWidget : public QWidget
{
public:
    MyWidget(QWidget *parent = nullptr) : QWidget(parent)
    {
        setWindowTitle("My Widget");
        setFixedSize(300, 200);
    }

protected:
    void keyPressEvent(QKeyEvent *event) override
    {
        if (event->key() == Qt::Key_Escape)
            qApp->quit();
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MyWidget w;
    w.show();

    return app.exec();
}

在上面的代码中,我们定义了一个MyWidget类,它继承自QWidget。在MyWidget类中,我们重载了keyPressEvent()函数,该函数用于处理键盘事件。如果用户按下了Esc键,则我们调用qApp->quit()函数来退出应用程序。

在main()函数中,我们创建了一个QApplication对象,并创建了一个MyWidget对象并显示出来。当用户在MyWidget对象中按下键盘时,该事件将被传递给操作系统,并由操作系统将其发送到Qt应用程序的事件队列中。事件分发机制会不断从事件队列中取出事件,并将其分发到正确的QObject派生类对象中进行处理。在本例中,当键盘事件被分发到MyWidget对象时,MyWidget对象的keyPressEvent()函数会被调用,从而完成了事件的处理。

小结:事件分发和派发是指在Qt5.9中将事件发送到目标对象并处理它的过程。事件分发是指事件循环从系统事件队列中获取事件并将其分发到目标对象。事件派发是指目标对象的事件处理函数被调用来处理特定的事件。

3 自定义事件

3.1 创建自定义事件

在Qt5.9中,可以使用QEvent::registerEventType()函数来注册自定义事件类型。注册自定义事件类型时,需要

  • 创建自定义事件

创建自定义事件:
在Qt中,可以通过继承QEvent类来创建自定义事件。我们需要定义一个新的事件类型,并在该事件类型中添加需要的数据。下面是一个简单的例子来说明如何创建自定义事件:

#include <QEvent>

class MyCustomEvent : public QEvent
{
public:
    static constexpr QEvent::Type EventType = static_cast<QEvent::Type>(QEvent::User + 1);

    MyCustomEvent(const QString &data) : QEvent(EventType), m_data(data) {}

    QString data() const { return m_data; }

private:
    QString m_data;
};

在上面的代码中,我们定义了一个名为MyCustomEvent的自定义事件。我们通过继承QEvent类来创建该事件,并在事件类型中添加了一个QString类型的数据。注意,我们需要为该事件定义一个唯一的事件类型。在本例中,我们将事件类型设置为QEvent::User + 1。

3.2 发送和处理自定义事件

我们可以通过QCoreApplication::postEvent()函数来发送自定义事件。该函数会将自定义事件插入到事件队列中,然后返回。当事件队列中有自定义事件时,事件分发机制会将其分发到正确的QObject派生类对象中进行处理。下面是一个简单的例子来说明如何发送和处理自定义事件:

#include <QCoreApplication>
#include <QDebug>

class MyObject : public QObject
{
public:
    MyObject(QObject *parent = nullptr) : QObject(parent) {}

protected:
    bool event(QEvent *event) override
    {
        if (event->type() == MyCustomEvent::EventType) {
            MyCustomEvent *customEvent = static_cast<MyCustomEvent *>(event);
            qDebug() << "Received custom event with data:" << customEvent->data();
            return true;
        }
        return QObject::event(event);
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    MyObject obj;
    obj.setObjectName("myObject");

    QCoreApplication::postEvent(&obj, new MyCustomEvent("Hello, world!"));

    return app.exec();
}

在上面的代码中,我们定义了一个名为MyObject的QObject派生类对象,并在其中重载了event()函数来处理自定义事件。当收到自定义事件时,我们将其转换为MyCustomEvent类型,并打印出事件中存储的数据。在main()函数中,我们创建了一个MyObject对象,并使用QCoreApplication::postEvent()函数来向该对象发送一个自定义事件。

3.3 使用自定义事件来扩展Qt应用程序

自定义事件可以帮助我们扩展Qt应用程序的功能。例如,我们可以定义一个自定义事件来实现异步任务。在任务完成后,我们可以发送自定义事件来通知应用程序更新界面。下面是一个简单的例子来说明如何使用自定义事件来扩展Qt应用程序:

#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>

class MyObject : public QObject
{
public:
    MyObject(QObject *parent = nullptr) : QObject(parent) {}

    void startTask()
    {
        QThread *thread = new QThread(this);
        Worker *worker = new Worker();
        worker->moveToThread(thread);

        connect(thread, &QThread::started, worker, &Worker::doWork);
        connect(worker, &Worker::workFinished, this, &MyObject::onWorkFinished);
        connect(worker, &Worker::finished, thread, &QThread::quit);
        connect(worker, &Worker::finished, worker, &Worker::deleteLater);
        connect(thread, &QThread::finished, thread, &QThread::deleteLater);

        thread->start();
    }

signals:
    void taskFinished(const QString &result);

private slots:
    void onWorkFinished(const QString &result)
    {
        QCoreApplication::postEvent(this, new TaskFinishedEvent(result));
    }
};

class Worker : public QObject
{
public:
    Worker(QObject *parent = nullptr) : QObject(parent) {}

signals:
    void workFinished(const QString &result);
    void finished();

public slots:
    void doWork()
    {
        qDebug() << "Starting task on thread:" << QThread::currentThread();
        QThread::sleep(5);
        emit workFinished("Task finished successfully!");
        emit finished();
    }
};

class TaskFinishedEvent : public QEvent
{
public:
    static constexpr QEvent::Type EventType = static_cast<QEvent::Type>(QEvent::User + 1);

    TaskFinishedEvent(const QString &result) : QEvent(EventType), m_result(result) {}

    QString result() const { return m_result; }

private:
    QString m_result;
};

class MyApplication : public QCoreApplication
{
public:
    MyApplication(int argc, char **argv) : QCoreApplication(argc, argv)
    {
        m_object.setObjectName("myObject");
        m_object.startTask();
    }

protected:
    bool event(QEvent *event) override
    {
        if (event->type() == TaskFinishedEvent::EventType) {
            TaskFinishedEvent *taskFinishedEvent = static_cast<TaskFinishedEvent *>(event);
            qDebug() << "Task finished with result:" << taskFinishedEvent->result();
            quit();
            return true;
        }
        return QCoreApplication::event(event);
    }

private:
    MyObject m_object;
};

int main(int argc, char *argv[])
{
    MyApplication app(argc, argv);
    return app.exec();
}

在上面的代码中,我们定义了一个名为MyObject的QObject派生类对象,并在其中定义了一个名为startTask()的槽函数。该槽函数会创建一个新的QThread对象,并将一个名为Worker的QObject派生类对象移动到该线程中。然后,我们通过信号和槽来连接。

🔥3.4 坑点的地方要注意一下:

自定义按钮事件的时候,进行重写的时候,最好要调用父类的方法进行重写

问题 : 槽函数没有响应?

image-20230425224452667

否则的话,要对一些信号的处理做一些额外工作,否则槽函数可能调用不了

// 以下是一个简单的示例程序,演示了如何解决槽函数没有相应的问题:

#include <QApplication>
#include <QPushButton>

class MyButton : public QPushButton
{
    Q_OBJECT

public:
    MyButton(QWidget *parent = nullptr) : QPushButton(parent) {}

protected:
    void mousePressEvent(QMouseEvent *event) override {
        QPushButton::mousePressEvent(event);
        emit clicked(event->x(), event->y());
    }

signals:
    void clicked(int x, int y);
};

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr) : QWidget(parent) {
        button = new MyButton(this);
        button->setText("Click me");
        button->move(50, 50);

        connect(button, &MyButton::clicked, this, &Widget::onButtonClicked);
    }

private slots:
    void onButtonClicked(int x, int y) {
        qDebug("Button clicked at (%d, %d)", x, y);
    }

private:
    MyButton *button;
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    Widget widget;
    widget.show();

    return app.exec();
}

在上面的示例中,我们自定义了一个 MyButton 类继承自 QPushButton,重载了 mousePressEvent() 函数来处理鼠标点击事件,并通过 emit 语句发送了 clicked 信号,传递了鼠标点击位置的坐标。在 Widget 类中,我们实例化了 MyButton 对象,并将其与 onButtonClicked() 槽函数绑定。当鼠标点击按钮时,槽函数会被调用,并输出鼠标点击位置的坐标。

4. 多线程和事件处理

多线程和事件处理是Qt框架中非常重要的概念,能够帮助我们更好地实现复杂的功能,并提高应用程序的性能。本文将从理解多线程和事件处理、跨线程事件的发送和处理两个方面进行介绍。

4.1 理解多线程和事件处理

多线程和事件处理是两个独立但密切相关的概念。在单线程应用程序中,所有的代码都是顺序执行的,当应用程序接收到事件时,事件处理函数会在主线程中执行。而在多线程应用程序中,每个线程都有自己的执行上下文和事件队列,当应用程序接收到事件时,事件将被分发到相应的线程中进行处理。

在Qt框架中,我们可以使用QThread类来创建新的线程,并使用QObject类的moveToThread()函数来将对象移动到其他线程中。此外,Qt还提供了一套完整的多线程编程模型,包括信号和槽、事件处理、互斥锁等机制,能够帮助我们更好地实现多线程应用程序。

4.2 跨线程事件的发送和处理

在多线程应用程序中,当我们需要在一个线程中执行某个操作,并将操作结果返回给另一个线程时,就需要使用跨线程事件的发送和处理机制。在Qt框架中,我们可以使用QEvent和QCoreApplication类的postEvent()和sendEvent()函数来实现跨线程事件的发送和处理。

下面是一个简单的例子,演示了如何在一个新线程中执行一个任务,并将任务结果返回给主线程。

#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>

class Worker : public QObject {
    Q_OBJECT
public:
    Worker() {}

public slots:
    void doWork() {
        qDebug() << "Worker thread id: " << QThread::currentThreadId();
        QThread::sleep(2);
        qDebug() << "Work done!";
        emit workFinished();
    }

signals:
    void workFinished();
};

class Controller : public QObject {
    Q_OBJECT
public:
    Controller() {
        m_worker = new Worker();
        m_workerThread = new QThread();
        m_worker->moveToThread(m_workerThread);
        connect(m_workerThread, &QThread::started, m_worker, &Worker::doWork);
        connect(m_worker, &Worker::workFinished, this, &Controller::onWorkFinished);
        m_workerThread->start();
    }

    ~Controller() {
        m_workerThread->quit();
        m_workerThread->wait();
        delete m_worker;
        delete m_workerThread;
    }

signals:
    void startWork();

public slots:
    void onWorkFinished() {
        qDebug() << "Work finished!";
        QCoreApplication::quit();
    }

private:
    Worker* m_worker;
    QThread* m_workerThread;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    Controller controller;
    QTimer::singleShot(0, &controller, &Controller::startWork);
    return a.exec();
}

#include "main.moc"

这段代码演示了在Qt中如何使用多线程来执行一个耗时操作(在这个例子中,是等待2秒),并在操作完成后关闭应用程序。

代码中定义了两个类:Worker和Controller,Worker是一个执行耗时操作的工作线程,Controller是应用程序的控制类,负责创建和管理工作线程,并在工作完成后关闭应用程序。

Worker继承自QObject,包含一个doWork()函数,它在工作线程中执行。doWork()函数会在工作线程中输出线程的ID,等待2秒钟,然后输出"Work done!",并发射workFinished()信号表示工作完成。

Controller同样继承自QObject,并包含一个指向Worker对象的指针和一个指向工作线程的指针。在Controller的构造函数中,它创建了一个Worker对象和一个工作线程对象,并将Worker对象移到工作线程中。然后,Controller连接工作线程的started()信号到Worker对象的doWork()槽函数,以便在工作线程启动时执行耗时操作。Controller还连接了Worker对象的workFinished()信号到自己的onWorkFinished()槽函数,在工作完成后关闭应用程序。

在main()函数中,创建了一个QCoreApplication对象和一个Controller对象。然后,使用QTimer::singleShot()函数延迟0毫秒,发出startWork()信号以启动工作线程。最后,调用a.exec()函数进入Qt事件循环,等待应用程序关闭。

总体来说,这段代码演示了如何使用多线程来处理耗时操作,并在工作完成后关闭应用程序。同时,它也演示了如何在不同的线程中发送信号和槽,并在跨线程调用中避免潜在的问题。

image-20230425214551067

5 Qt5.9中的常见事件

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

Qt5.9中的三种常见事件:定时器事件、鼠标事件和键盘事件。

5.1 定时器事件

定时器事件是指在指定的时间间隔内周期性地触发事件。在Qt中,我们可以通过继承QTimer类来创建定时器对象。下面是一个简单的例子:

class MyTimer : public QTimer
{
    Q_OBJECT

public:
    MyTimer(QObject *parent = nullptr) : QTimer(parent)
    {
        connect(this, &QTimer::timeout, this, &MyTimer::onTimeout);
        start(1000);
    }

signals:
    void timerSignal();

private slots:
    void onTimeout()
    {
        emit timerSignal();
    }
};

在上面的代码中,我们创建了一个MyTimer类继承自QTimer类,并重写了QTimer类中的timeout()方法,即定时器事件的处理函数。在MyTimer类的构造函数中,我们通过connect()函数将定时器的timeout信号连接到自定义的槽函数onTimeout(),并将定时器的时间间隔设置为1秒。在onTimeout()槽函数中,我们发射了一个自定义的信号timerSignal(),以便在应用程序的其他地方使用。

5.2 鼠标事件

鼠标事件是指当用户在应用程序的窗口中移动鼠标时,会触发相应的事件。在Qt中,我们可以通过重写QWidget类的鼠标事件处理函数来处理鼠标事件。下面是一个简单的例子:

class MyWidget : public QWidget
{
    Q_OBJECT

public:
    MyWidget(QWidget *parent = nullptr) : QWidget(parent)
    {
        setFixedSize(200, 200);
    }

protected:
    void mousePressEvent(QMouseEvent *event) override
    {
        qDebug() << "Mouse Pressed:" << event->pos();
    }

    void mouseMoveEvent(QMouseEvent *event) override
    {
        qDebug() << "Mouse Moved:" << event->pos();
    }

    void mouseReleaseEvent(QMouseEvent *event) override
    {
        qDebug() << "Mouse Released:" << event->pos();
    }
};

在上面的代码中,我们创建了一个MyWidget类继承自QWidget类,并重写了QWidget类中的三个鼠标事件处理函数:mousePressEvent()mouseMoveEvent()mouseReleaseEvent()。在这三个函数中,我们使用qDebug()函数输出鼠标事件的信息,例如鼠标按下、移动和释放的位置。

5.3 键盘事件

键盘事件是指当用户在应用程序的窗口中按下或释放键盘按键时,会触发相应的事件。在Qt中,我们可以通过重写QWidget类的键盘事件处理函数来处理键盘事件。下面是一个简单的例子:

下面是完整的代码实现:

#include <QApplication>
#include <QWidget>
#include <QTimerEvent>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QLabel>

class MyWidget : public QWidget
{
public:
    MyWidget(QWidget *parent = nullptr);

protected:
    void timerEvent(QTimerEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    void keyPressEvent(QKeyEvent *event) override;

private:
    int m_timerId;
    QLabel *m_label;
};

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent), m_timerId(-1)
{
    m_label = new QLabel(this);
    m_label->setAlignment(Qt::AlignCenter);
    m_label->setText("Press the left mouse button or any key to generate events");
    m_label->setGeometry(10, 10, 280, 80);

    m_timerId = startTimer(1000);
}

void MyWidget::timerEvent(QTimerEvent *event)
{
    if (event->timerId() == m_timerId) {
        m_label->setText(QString("Timer event %1").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
    } else {
        QWidget::timerEvent(event);
    }
}

void MyWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        m_label->setText("Mouse left button pressed");
    } else {
        QWidget::mousePressEvent(event);
    }
}

void MyWidget::keyPressEvent(QKeyEvent *event)
{
    m_label->setText(QString("Key %1 pressed").arg(event->text()));
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MyWidget w;
    w.show();

    return a.exec();
}

这个例子演示了如何在Qt中使用定时器事件、鼠标事件和键盘事件。在窗口中,我们添加了一个QLabel控件来显示事件的信息。当定时器事件发生时,标签的文本将被更新以显示当前时间。当鼠标左键按下时,标签将显示“Mouse left button pressed”。当任何键按下时,标签将显示哪个键被按下。注意,在键盘事件处理函数中,我们使用了QKeyEvent的text()函数来获取按下的键的文本。

6. 事件调试和排查

  • 在Qt中,我们可以使用Qt Creator中的调试器来调试事件处理代码。以下是调试事件处理的一些技巧和建议:

    使用断点调试

    在事件处理代码中设置断点,以检查事件何时被处理以及处理代码是否按照预期执行。使用单步执行来跟踪事件处理流程,以便在需要时进行修改。

    打印调试信息

    使用qDebug()宏打印事件处理代码中的调试信息。这对于跟踪事件流以及确认事件是否正确处理非常有用。例如,可以使用qDebug()在事件处理函数中输出事件的类型和属性。

    事件调试

    如果存在事件过滤器,检查过滤器是否正确设置和工作。通过使用单步执行来跟踪事件流,可以检查事件何时到达过滤器并如何处理它们。

    如果涉及到多线程事件处理,确保事件处理代码是线程安全的。通过使用Qt的信号和槽机制将事件发送到正确的线程,并使用线程安全的方法来访问和更新共享数据。

    以下是一个简单的示例代码,演示了如何使用断点和打印调试信息来调试事件处理程序:

    #include <QApplication>
    #include <QWidget>
    #include <QMouseEvent>
    #include <QDebug>
    
    class MyWidget : public QWidget
    {
    public:
        MyWidget(QWidget *parent = nullptr);
    
    protected:
        void mousePressEvent(QMouseEvent *event) override;
    
    private:
        int m_count;
    };
    
    MyWidget::MyWidget(QWidget *parent)
        : QWidget(parent), m_count(0)
    {
        setFixedSize(300, 200);
    }
    
    void MyWidget::mousePressEvent(QMouseEvent *event)
    {
        qDebug() << "Mouse event occurred";
        m_count++;
        if (m_count == 5) {
            qDebug() << "Reached event count limit, stopping event processing";
            event->accept();
        } else {
            qDebug() << "Event count:" << m_count;
            QWidget::mousePressEvent(event);
        }
    }
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        MyWidget w;
        w.show();
    
        return a.exec();
    }
    
    

    在这个例子中,我们重写了QWidget的mousePressEvent()函数来处理鼠标事件。我们设置了一个断点在mousePressEvent()函数内部,并使用qDebug()宏打印调试信息。当事件发生时,我们可以跟踪代码执行流程并查看事件处理代码的执行情况。在这个例子中,我们检查鼠标事件的数量,如果数量达到5个,我们停止事件处理。

最后,最后
如果觉得有用,麻烦三连👍⭐️❤️支持一下呀,希望这篇文章可以帮到你,你的点赞是我持续更新的动力

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/500873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

物业管理系统【纯控制台】(Java课设)

系统类型 纯控制台类型&#xff08;没有用到数据库&#xff09; 使用范围 适合作为Java课设&#xff01;&#xff01;&#xff01; 部署环境 jdk1.8Idea或eclipse 运行效果 本系统源码地址&#xff1a;https://download.csdn.net/download/qq_50954361/87753361 更多系统…

YOLOv5结合BiFPN:BiFPN网络结构调整,BiFPN训练模型训练技巧

目录 一、BiFPN网络结构调整1、堆叠BiFPN2、调整网络深度3、调整BiFPN的参数 二、训练技巧和注意事项1、数据增强2、学习率调度3、优化器选择4、权重初始化5、模型选择6、Batch size的选择7、模型保存和加载8、注意过拟合和欠拟合问题 三、实验结果和分析1、数据集和评估指标2、…

开发、部署应用程序APP的【12要素原则】你顺便了解一下?

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 开发、部署应用程序APP的【12要素原则】你顺便了解一下&#xff1f; ☘️摘要☘️介绍☘️背景☘️谁应该阅读这份文件?☘️十二要素原则&#x1f33f;I. 代码库 Codebase&#x1f…

2.进程与线程

2.进程与线程 2.1 进程与线程 进程&#xff1a; 程序由指令和数据组成&#xff0c;指令要执行&#xff0c;数据要读写&#xff0c;就需要将指令加载到cpu&#xff0c;数据加载到内存&#xff0c;进程就是用来加载指令、管理IO、管理内存的当一个程序被执行&#xff0c;从磁盘…

大数据环境准备(二) - VMware 虚拟机系统设置

VMware 虚拟机系统设置 1.对三台虚拟机完成主机名、固定IP、SSH免密登录等系统设置 1&#xff09;配置固定IP地址 开启node1,修改主机名为node1 #切换root用户 su - #修改主机名 hostnamectl set-hostname node1关闭node1终端&#xff0c;重新打开&#xff1b; 同理开启nod…

Java页面布局

Java页面常用的布局主要有五种&#xff1a;FlowLayout、BorderLayout、GridLayout、CardLayout和NULL 1、FlowLayout 称为“流布局”&#xff0c;将组件按从左到右顺序、流动的安排到容器中&#xff0c;直到占满上方的空间时、则向下移动一行&#xff0c;Flow Layout是面板的…

13.多线程

1.实现多线程 1.1简单了解多线程【理解】 是指从软件或者硬件上实现多个线程并发执行的技术。 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程&#xff0c;提升性能。 1.2并发和并行【理解】 并行&#xff1a;在同一时刻&#xff0c;有多个指令在多个CPU上…

Packet Tracer - 配置 IPv6 ACL

Packet Tracer - 配置 IPv6 ACL 拓扑图 地址分配表 设备 接口 IPv6 地址/前缀 默认网关 服务器 3 NIC 2001:DB8:1:30::30/64 FE80::30 目标 第 1 部分&#xff1a;配置、应用并验证一个 IPv6 ACL 第 2 部分&#xff1a;配置、应用并验证第二个 IPv6 ACL 第 1 部分…

node.js+vue鲜花销售网站

后台模块设计&#xff1a; ①用户管理功能。管理员在后台首页点击用户管理就会进入用户列表页面&#xff0c;系统会将数据库中的用户信息以列表的形式显示出来&#xff0c;管理员可以在这个页面进行用户的更新和删除操作&#xff0c;系统可以将最新更新的信息重新写入用户表中并…

Chrome浏览器更新字体看不清的最终解决方案

阿酷TONY / 2023-5-6 / 长沙 / 原创 / 实测解决 Chrome更新至版本Chrome 109.0.5414.120 字体看不清 浏览器症状&#xff1a;Chrome更新至版本Chrome 109.0.5414.120 字体看不清&#xff1b;会很细&#xff0c;在设置中选择自定义的字体&#xff0c;仍无法解决&#xff1b;…

当因果推理遇上时间序列,会碰撞出怎样的火花?

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 近年来因果推理和时间序列已经成为了数据科学领域备受瞩目的研究方向。因果推理可以帮助我们识别变量之间的因果关系&#xff0c;时间序列分析则可以便于我们理解变量随时间变化的规律。这两个方向都可以为我们…

javaScript---设计模式-封装与对象

目录 1、封装对象时的设计模式 2、基本结构与应用示例 2.1 工厂模式 2.2 建造者模式 2.3 单例模式 封装的目的&#xff1a;①定义变量不会污染外部&#xff1b;②能作为一个模块调用&#xff1b;③遵循开闭原则。 好的封装&#xff08;不可见、留接口&#xff09;&#xff1a;①…

Cacti 前台命令注入漏洞

文章目录 文档说明漏洞描述影响版本漏洞原理命令执行简单分析客户端ip伪造分析 漏洞复现下载vulhub启动环境配置攻击 复现总结修复方案原创申明 文档说明 本文作者:SwBack 创作时间:2023/4/8 0:12 知乎:https://www.zhihu.com/people/back-88-87 CSDN:https://blog.csdn.net/q…

solidity--语言基础

solidity源文件结构 // SPDX-License-Identifier: MIT pragma solidity ^0.5.2; pragma abicoder v1; import "filename"; 注释 智能合约组成 状态变量 // SPDX-License-Identifier: GPL-3.0 pragma solidity >0.4.0 <0.9.0;contract SimpleStorage {uint stor…

SD卡打不开是怎么回事?SD卡打不开里面数据怎样恢复

SD卡已经成为了移动设备和数码相机中受欢迎的存储选项之一。但是使用过程中难免会遇到一些问题&#xff0c;例如SD卡突然打不开了&#xff0c;并且无法访问其中的数据。这种情况常常让人感到烦恼和无助。但是不要紧张&#xff0c;下面我们将介绍SD卡打不开里面数据怎样恢复的方…

Yuzuki Lizard V851S开发板 –编译 OPENCV 4.5.4

1.主要参考教程地址&#xff0c;实际操作结合多个教程。 https://blog.csdn.net/Flag_ing/article/details/109508374 2.放从OPENCV RELEASE 下载的解压出来的文件&#xff0c;里面还要放对应版本的contribute 解压文件 /root/opencv-4.5.4/root/opencv-4.5.4/build6在这里要…

深入理解Java虚拟机——内存分配与回收策略

1.前言 在读这篇博客之前&#xff0c;你需要了解分代收集理论中&#xff0c;收集器应该将Java堆划分出不同的区域**&#xff0c;**然后将回收对象依据其年龄&#xff08;年龄即对象熬过垃圾收集过程的次数&#xff09;分配到不同的区域之中存储。 例如appel式回收&#xff0c…

SSM整合详细教学(上)

SSM整合详细教学&#xff08;上&#xff09; 一、SSM整合1. SSM整合配置1.1 SSM整合流程1.2 SSM整合配置1.2.1 创建工程&#xff0c;添加依赖和插件1.2.2 Spring整合Mybatis1.2.3 Spring整合SpringMVC 2. 功能模块开发2.1 数据层开发(BookDao)2.2 业务层开发(BookService/BookS…

java注解,一篇文章就够了

开篇一张图 一、定义 注解是一种标记&#xff0c;使类或接口附加额外信息&#xff0c;帮助编译器和 JVM 完成一些特定功能。 Annotation(注解)也被称为元数据(Metadata)是JDK1.5及以后版本引入的&#xff0c;用于修饰包、类、接口、字段、方法参数、局部变量等。 如&#xf…

iOS与Android应用开发的对比:如何选择最佳开发平台?

第一章&#xff1a;引言 在移动应用开发领域&#xff0c;iOS和Android是最为流行的操作系统。选择最佳的开发平台可以使开发人员更有效地开发和发布应用程序。本文将分析iOS和Android应用开发的优缺点&#xff0c;并提供一些有关如何选择最佳开发平台的建议。 第二章&#xf…