Qt程序框架的运行机制
Qt程序框架
程序入口
当我们新建一个Qt Widget工程的时候,会自动生成四个文件:
- main.cpp
- widget.h
- widget.cpp
- widget.ui
其中main.cpp是整个程序的入口,文件中只有一个简单的main()
函数。
#include "widget.h" #include <QApplication> #include <QLocale> #include <QTranslator> int main(int argc, char *argv[]) { QApplication a(argc, argv); QTranslator translator; const QStringList uiLanguages = QLocale::system().uiLanguages(); for (const QString &locale : uiLanguages) { const QString baseName = "samp_2_2_" + QLocale(locale).name(); if (translator.load(":/i18n/" + baseName)) { a.installTranslator(&translator); break; } } Widget w; w.show(); return a.exec(); }
main()
中定义了一个QApplication
的对象a
和一个Widget
的对象w
。其中的Widget
类就是我们的Qt工程中主要需要设计的类,包含所有窗口中可视的组件,同时提供信号和槽机制,用于实现不同组件之间复杂的交互功能。QApplication
类的主要作用是处理各种事件。
主程序中的代码非常简单,只有两行。
w.show(); a.exec();
exec()
函数的主要功能是循环检查事件队列中是否有待处理的事件,并依次进行处理。信号与槽机制、事件处理机制,这两大机制构成了Qt编程框架的核心内容。
#include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::Widget *ui; };
Widget
类中默认的内容如上所示,这是一个QWidget
的派生类。并且还在Ui
这个命名空间中定义了一个和Widget
同名的类。Q_OBJECT
是一个声明,本质上是一个定义好的宏。只有声明了Q_OBJECT
的类才能使用Qt的信号与槽机制。
信号与槽机制
信号与槽机制是一个点到点的消息处理机制。在一个复杂的窗口程序中,用户的一个输入或者产生的一个事件可能会引起多个组件的动作。此时就可以使用信号与槽机制。用户的输入或者某一个事件会被作为一个信号发射,与此信号关联的槽函数则会相应地被执行。信号和槽函数之间的关联性需要在MainWindow
的构造函数中显式地指定。同时,所有的信号和槽函数都必须在类的定义中被声明。这里的类可以是MainWindow
,也可以是用户定义的其他类。将信号与槽连接起来的方式是
... MainWindow::MainWindow { ... connect(sender, signal(), receiver, slot_function()); ... }
其中信号和槽都是可以带有参数的。
信号的发射有两种
- 一种是Qt界面组件内部已经定义好的行为。比如GUI窗口中的一个按钮被点击,或者输入框中输入了一些字符等等。Qt定义了非常丰富的信号发射行为,允许用户进行各种自定义的功能实现(比如鼠标悬停在某一个文字组件上等等)。
- 另一种是用户代码中主动调用
emit signal()
,其中的signal()
必须在某一个类中被声明过。
事件处理机制
Qt中的事件可以分为三类,分别是
- 自生事件:由窗口系统产生的事件。
- 发布事件:Qt或者应用程序产生的事件。
- 发送事件:Qt或应用程序定向发送给某个对象的事件。
定时器
Qt中定义了一个QTimer
类,可以方便地实现定时器。所谓的定时器,指的是每隔一定的时间间隔即产生一次触发。可以将这个触发信号作为Qt中的信号,为其设置一个槽函数,从而实现每隔一定的时间间隔调用一次槽函数,实现一些特定的功能。
#include <QTimer> #include <QTime> ... class MainWindow : public QWidget { public: MainWindow(); ~MainWindows(); private: QTimer ftimer; QTime ftime_counter; void on_timer_timeout(); // 定时器的槽函数,可以定时器的中断服务程序 };
在MainWindow
类的构造函数中,需要显式地将定时器的槽函数和定时器关联。
按键事件处理
如果需要窗口程序对用户的按键输入进行响应和处理(在游戏类的应用中比较常见),可以使用Qt框架下的按键事件处理。
#include <QKeyEvent>
在MainWindow
类中需要对虚函数void keyPressEvent(QKeyEvent *ev)
重载。在窗口程序运行的过程中,只要运行一次this->grabKeyboard()
语句,所有的按键事件都会被Qt捕获,并且每按一次按键,都会调用一次我们重载过的keyPressEvent()
函数。直至运行一次this->releaseKeyboard()
。
需要注意的是,只要窗口程序还在运行,所有的按键都会被窗口程序捕获。因此,如果用户在没有关闭窗口程序的情况下,切换到了计算机中正在运行的其他程序上,会发现键盘不能用了(因为实际的按键事件都被Qt窗口程序捕获了)。所以应当合理设置grabKeyboard()
和releaseKeyboard()
。尽可能减少占用键盘输入的时间。
tips
QWidget
类型的对象,在通过setGeometry()
指定其位置和形状的时候,必须同时对所有的分量进行设置。否则可能会遇到形状发生变化的问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下