Qt Event

事件循环

事件循环(Event Loop)是 Qt 框架的核心机制,主要负责管理应用程序的事件分发、信号槽调用、定时器、网络通信等异步操作。

事件循环是一个无限循环,不断检查是否有新的事件(如鼠标点击、键盘输入、网络数据到达)需要处理,并分发给对应的对象,主要组成部分:

  • 事件队列(Event Queue):存储所有待处理的事件,按照先进先出的原则处理
  • 事件分发器:(Event Dispatcher):负责从队列中取出事件,将事件发送到目标对象
  • 事件处理器:(Event Handler):对象中处理特定事件的方法(如 mousePressEvent())

在 Qt 应用程序中,Qt 的主事件循环由 QCoreApplication::exec() 或 QApplication::exec() 启动,一般位于 main() 函数的末尾。

c++ 复制代码
int main(int argc, char *argv[]) 
{
    QApplication app(argc, argv);

    MainWindow window;
    window.show();

    return app.exec(); // 进入主事件循环
}

如果没有 app.exec(),程序会立即退出,UI 无法显示,信号槽也无法正常工作。

对于非 GUI 程序(如后台服务),使用 QCoreApplication::exec()。

事件循环的应用场景

保持 UI 响应

事件循环允许 GUI 程序在等待用户输入时不会卡死(例如一个窗口调用show方法以模态框的方式显示后不会阻塞(这一点跟winform、c++builder的form不太一样));如果没有事件循环,UI 会冻结,无法响应用户操作。

异步网络通信

QTcpSocket、QUdpSocket 依赖事件循环来接收数据。

c++ 复制代码
QTcpSocket socket;
socket.connectToHost("127.0.0.1", 1800);
QObject::connect(&socket, &QTcpSocket::readyRead, [&]() {
	qDebug() << "Data received:" << socket.readAll();
});

readyRead 信号只能在事件循环运行时触发。

定时器

QTimer 依赖事件循环

c++ 复制代码
QTimer timer;
timer.setInterval(1000); // 1秒触发一次
QObject::connect(&timer, &QTimer::timeout, []() {
	qDebug() << "timer triggered!";
});
timer.start(); // 需要事件循环才能运行

跨线程通信

如果对象在不同线程,信号槽调用会通过目标线程的事件循环进行调度

c++ 复制代码
Worker worker;
worker.moveToThread(&workerThread); // 将 worker 移到子线程
QObject::connect(this, &MainWindow::startWork, &worker, &Worker::doWork);
workerThread.start();

当 emit startWork() 时,doWork() 会在 workerThread 的事件循环中被调用。

手动控制事件循环

局部事件循环

有时需要临时进入事件循环(如等待用户输入)

c++ 复制代码
QEventLoop loop;
QTimer::singleShot(3000, &loop, &QEventLoop::quit); // 3秒后退出
loop.exec(); // 阻塞,直到 quit() 被调用

多线程与事件循环

每个线程可以有独立的事件循环

c++ 复制代码
class WorkerThread : public QThread {
protected:
    void run() override 
    {
        QTimer timer;
    	connect(&timer, &QTimer::timeout, []() { qDebug() << "Thread tick"; });
        timer.start(1000);
        exec(); // 启动子线程的事件循环
    }
};

主线程的事件循环由 QApplication::exec() 启动。

子线程的事件循环由 QThread::exec() 启动。

跨线程信号槽依赖目标线程的事件循环。

扩展:关于qt线程的一些总结

  • QThread 的run函数相当于程序main函数,只有在run函数中调用的函数才算是在子线程中执行;
  • 建议使用moveToThread,这样简单且安全,不推荐继承QThread

事件

Qt 的事件系统是一个事件驱动架构 ,它让程序能够响应用户操作(鼠标、键盘等)、系统消息(窗口调整、定时器)、以及自定义事件。所有事件都被封装为 QEvent 对象,通过事件循环分发给对应的 QObject(尤其是 QWidget)处理。

Qt 的事件驱动实际上是面向对象的事件传递系统(继承 + 虚函数),与.net框架的事件驱动有很大区别(.net的事件驱动类似与Qt的信号、槽机制,属于发布/订阅模式)。

QEvent

  • 所有事件的基类。
  • 定义了 Type 枚举,表示事件类型,比如鼠标事件、键盘事件、定时器事件、绘图事件等。
  • 支持事件"接受/忽略"机制,控制事件是否继续传递。
c++ 复制代码
void QEvent::accept();   // 设置事件已处理
void QEvent::ignore();   // 设置事件未处理
bool QEvent::isAccepted() const;

QObject::event(QEvent *event)

  • 事件处理的统一入口。
  • 默认实现根据事件类型调用对应的虚函数,如 mousePressEvent(), keyPressEvent()
  • 可重写此函数实现自定义事件处理逻辑。
c++ 复制代码
bool MyWidget::event(QEvent *event) override {
    if (event->type() == QEvent::KeyPress) {
        // 自定义键盘事件处理
        return true;
    }
    return QWidget::event(event);  // 调用父类默认处理
}

事件过滤器(Event Filter)

  • 允许一个对象监听和拦截另一个对象的事件。
  • 通过 installEventFilter() 安装。
  • 通过重写 eventFilter() 实现事件拦截与处理。
c++ 复制代码
class MainWindow : public QMainWindow {
public:
    MainWindow();
protected:
    bool eventFilter(QObject *obj, QEvent *event);
private:
    QTextEdit *textEdit;
};
 
MainWindow::MainWindow() {
    textEdit = new QTextEdit;
    setCentralWidget(textEdit);
    
    textEdit->installEventFilter(this);//MainWindow中有一个QTextEdit控件,拦截它的键盘按下的事件。
}
 
bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
    if (obj == textEdit)  {
        if (event->type() == QEvent::KeyPress) {
            QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
            qDebug() << "you press" << keyEvent->key();
            //事件不再进行传播,拦截
            return true;
        }  else {
            return false;//继续传播
        }
    } 
    else  {
        //当不确定是否继续传播时,按照父类的方法来处理
        //即调用父类的evenFilter函数
        return QMainWindow::eventFilter(obj, event);
    }
}
相关推荐
Magic--2 小时前
Qt 桌面计算器项目
开发语言·qt
李昊哲小课2 小时前
Python办公自动化教程 - 第2章 单元格样式魔法 - 让表格变得美观专业
开发语言·python·excel·openpyxl
特立独行的猫a2 小时前
HarmonyOS鸿蒙PC的QT应用开发:QT项目运行原理与 EmbeddedUIExtensionAbility介绍
qt·华为·harmonyos·openharmony·鸿蒙pc
张健11564096482 小时前
QT创建线程
开发语言·qt
鲸渔2 小时前
【C++ 输入输出】cin、cout、cerr 与格式化输出
开发语言·c++·算法
3GPP仿真实验室2 小时前
【MATLAB源码】水声:时变信道估计仿真平台
开发语言·matlab
froginwe112 小时前
Eclipse 关闭项目详解
开发语言
wjs20242 小时前
《jQuery Validate》深度解析与应用指南
开发语言
森G2 小时前
51、Move方式创建线程---------多线程
c++·qt