11. Qt 常用指针类
-
QPointer
- QPointer 是 Qt 中的智能指针,它可以自动管理指针的生命周期,并且可以检测被管理的对象是否已经被销毁,如果被管理的对象已经被销毁,QPointer 会自动将指针置为 nullptr
- QPointer 通常用于管理 QWidget 对象等需要在程序运行期间动态创建和销毁的对象
- QPointer 只能用于指向 QObject 及派生类的对象
- QPointer 对象超出作用域时,并不会删除它指向的内存对象
-
QScopedPointer
- QScopedPointer 是 Qt 中的局部智能指针,它可以自动管理指针的生命周期,并且可以在指针超出作用域时自动释放指针指向的内存
- QScopedPointer 通常用于管理局部变量和堆内存对象等需要在作用域结束时自动释放的对象
-
QSharedPointer
- QSharedPointer 是 Qt 中的共享智能指针,它可以在多个指针之间共享同一个对象,并且可以自动管理指针的生命周期
- 当最后一个指向对象的 QSharedPointer 被销毁时,QSharedPointer 会自动释放对象的内存
- QSharedPointer 通常用于管理需要在多个地方使用同一个对象的情况
QSharedPointer 和 std::shared_ptr 区别
- 1、QSharedPointer 是 Qt 框架提供的智能指针,而 std::shared_ptr 是 C++11 标准库提供的智能指针
- 2、QSharedPointer 可以与 QObject 一起使用,可以自动处理 QObject 的引用计数,当 QObject 被删除时,QSharedPointer 会自动释放对它的引用。而 std::shared_ptr 无法处理 QObject 的引用计数,需要手动管理
- 3、QSharedPointer 可以使用 qSharedPointerCast 进行类型转换,可以方便地将一个 QSharedPointer 转换为另一个 QSharedPointer。而 std::shared_ptr 只能使用 std::dynamic_pointer_cast 进行类型转换
- 4、QSharedPointer 的默认删除器是 delete,而 std::shared_ptr 的默认删除器是 std::default_delete
-
QWeakPointer
- QWeakPointer 是 Qt 中的弱智能指针,它类似于 QSharedPointer,但是不会增加对象的引用计数
- QWeakPointer 通常用于在多个指针之间共享同一个对象时,避免产生循环引用问题
-
QSharedDataPointer
- QSharedDataPointer 是 Qt 中的共享数据指针,它可以在多个对象之间共享同一个数据,而不需要共享整个对象
- QSharedDataPointer 通常用于实现 copy-on-write(COW)技术,避免不必要的复制操作
-
std::weak_ptr
- std::weak_ptr 是 C++11 标准库中的弱智能指针,它类似于 QWeakPointer,但是不是 Qt 所提供的
- std::weak_ptr 可以用于在多个指针之间共享同一个对象时,避免产生循环引用问题
12. Qt 设计界面的方式
- 1. 手工编写创建界面的代码
- 此方法比较复杂,不够直观,需要从 Qt 已有的 GUI 类库中选择一个类作为基类继承,并添加必要的其它成员
- 首先,会从 QDialog、QWidget、QMainWindow 等类中选择一个作为主窗体
- 然后,创建其它的控件,并使用布局管理器布局这些控件
- 最后,将该布局设置为主窗体的布局
- 2. 使用 Qt Designer 界面编辑器设计
- 所有的操作都采用可视化的操作,可直接拖放控件、设置控件的属性,简单、直观、易于操作
- 3. 动态加载 UI 文件并生成界面
- 此方法很灵活,当需要更改界面时只需更改 .UI 文件即可,无需重新编译程序
- 创建一个 mainwindow.ui 的 UI 文件,之后就可以采用 QUILoader 类动态加载该文件,并生成该窗体
13. Qt 常用的类控件
- QLabel(标签控件):用于显示文本或图像
- QPushButton(按钮控件):用于接收用户的点击事件
- QLineEdit(单行编辑框控件):用于接收用户输入的单行文本
- QTextEdit(多行编辑框控件):用于接收用户输入的多行文本
- QComboBox(下拉框控件):用于在预定义的选项中进行选择
- QCheckBox(复选框控件):用于允许用户选择一个或多个选项
- QRadioButton(单选按钮控件):用于允许用户从多个选项中选择一个
- QSpinBox/QDoubleSpinBox(数值输入框控件):用于接收用户输入的数值
14. 自定义控件
- 定义
- Qt 本身的控件不能满足需求,将原控件功能提升达到要求的控件称为自定义控件
- 自定义控件的方法
- 从外观设计上: QSS、继承绘制函数重绘、继承 QStyle 相关类重绘 、组合拼装等
- 从功能行为上:重写事件函数、添加或修改信号和槽等
自定义控件可以通过写代码的方式实现,也可通过 Qt Designer 的插件机制来实现
- 自定义控件的流程
- 1. 创建子类:基于 Qt 框架提供的现有控件类(如 QWidget、QLabel 等),创建自定义控件的子类,通过继承现有控件类,可以重用现有控件的功能,同时实现特定定制
- 2. 重载方法:根据需求,在自定义控件的子类中重载相关方法,实现自定义控件的特定行为
- 3. 设计界面:使用 Qt Designer 等界面设计工具,设计自定义控件的外观和布局
- 4. 资源管理:如果自定义控件需要使用资源文件(如图像、样式表等),需要将这些资源文件添加到项目中,并在控件中引用这些资源
- 自定义控件示例:在光标进入、按下、离开三种状态下显示不同的图片
- 1、定义一个新的类,继承自 QPushButton
- 2、在类的构造函数中设置按钮的三种状态下的图片
- 3、重载鼠标进入事件 (QEvent::Enter)、鼠标按下事件 (QEvent::MouseButtonPress) 和鼠标离开事件 (QEvent::Leave) 函数,分别在这三个事件中设置按钮的状态图片
class MyButton : public QPushButton { public: MyButton(QWidget *parent = nullptr) : QPushButton(parent) { // 设置按钮的三种状态图片 setStyleSheet("QPushButton {border-image: url(normal.png);}" "QPushButton:hover {border-image: url(hover.png);}" "QPushButton:pressed {border-image: url(pressed.png);}"); } protected: void enterEvent(QEvent *event) override { // 鼠标进入事件,设置按钮状态为 hover QPushButton::enterEvent(event); setStyleSheet("QPushButton {border-image: url(normal.png);}" "QPushButton:hover {border-image: url(hover.png);}" "QPushButton:pressed {border-image: url(pressed.png);}"); } void mousePressEvent(QMouseEvent *event) override { // 鼠标按下事件,设置按钮状态为 pressed QPushButton::mousePressEvent(event); setStyleSheet("QPushButton {border-image: url(normal.png);}" "QPushButton:hover {border-image: url(hover.png);}" "QPushButton:pressed {border-image: url(pressed.png);}"); } void leaveEvent(QEvent *event) override { // 鼠标离开事件,设置按钮状态为 normal QPushButton::leaveEvent(event); setStyleSheet("QPushButton {border-image: url(normal.png);}" "QPushButton:hover {border-image: url(hover.png);}" "QPushButton:pressed {border-image: url(pressed.png);}"); } };
15. QApplication 的作用
- QApplication 是 Qt 框架中的一个类,用于管理应用程序的主事件循环以及全局设置,它是一个用于创建 Qt 应用程序的核心类,通常在 Qt 程序的 main() 函数中作为应用程序的入口点
- 管理事件循环:QApplication 提供了事件处理和事件分发的机制,负责接收和分发事件给适当的组件处理,确保用户交互和程序逻辑正常工作
- 全局设置:QApplication 允许设置应用程序的全局属性,如应用程序名称、图标、风格、翻译文件等,以及一些全局的行为设置,例如鼠标追踪、应用程序版本等
- 资源管理:QApplication 负责管理应用程序的资源,如图形资源、字体资源、翻译资源等,方便应用程序统一调度和管理
- 应用程序控制:QApplication 提供了一些控制应用程序行为的方法,如退出应用程序、激活窗口、设置主窗口等
- 跨平台:QApplication 可以实现跨平台的能力,可在多个操作系统上运行,保证了 Qt 应用程序的可移植性
16. Qt 创建对象的方式
- 1、使用 Qt 自带的构造函数,如 QWidget,QPushButton,QDialog 等
- 可以直接创建Qt对象,但是不能实现动态创建,也不能调用它们的函数或者访问它们的成员变量
- 2、使用 Qt 的 meta-object 系统,如 QMetaObject::newInstance,QMetaObject::invokeMethod 等
- 可实现动态创建 Qt 对象,可调用它们的函数或者访问它们的成员变量
17. Qt 中常用的布局方式
- 常用布局方式
- 水平布局(QHBoxLayout):将控件水平地排列在一行中
- 垂直布局(QVBoxLayout):将控件垂直地排列在一列中
- 网格布局(QGridLayout):将控件按照行和列的网格布局方式排列
- 栅格布局(QFormLayout):用于表单的布局,通常用于标签和输入框的布局
- 堆叠布局(QStackedLayout):用于在同一区域内堆叠显示多个控件,每次只显示一个控件
- 实现窗口自适应缩放的方法
- 使用布局管理器:在设计界面时,使用布局管理器来管理控件的布局,这样当窗口大小改变时,布局管理器会自动调整控件的位置和大小
- 设置控件的大小策略:对于可伸缩的控件,可以设置其在水平和垂直方向上的大小策略,如 QSizePolicy::Expanding 表示控件会随着窗口的改变而扩展
- 重写 resizeEvent 方法:在窗口类中重写 resizeEvent 方法,监听窗口大小改变的事件,在该方法中手动调整控件的位置和大小
18. Qt 中的容器类
- QList:动态数组,支持随机访问和快速插入、删除操作
- QList 类是一种动态数组容器,它可以存储任意类型的数据,并且支持动态增加和删除操作
- QList 类的内部实现是一个可变大小的数组,可以动态调整数组的大小以适应数据的存储需求
- QList 类通常用于存储一组数据,并且需要对数据进行动态操作,如排序、查找等
QList<int> list; list.append(1); list.append(2); list.append(3); int num = list.at(1); // 获取第 2 个元素 list.removeLast(); // 删除最后一个元素
- QLinkedList
- QLinkedList 类是一种双向链表容器,它可以存储任意类型的数据,并且支持动态增加和删除操作
- QLinkedList 类的内部实现是一个双向链表,可以动态调整链表的大小以适应数据的存储需求
- QLinkedList 类通常用于存储一组数据,并且需要对数据进行动态操作,如排序、查找等
QLinkedList<int> list; list.append(1); list.append(2); list.append(3); int num = list.at(1); // 获取第 2 个元素 list.removeLast(); // 删除最后一个元素
- QVector
- QVector 类是一种动态数组容器,它可以存储任意类型的数据,并且支持动态增加和删除操作,类似 QList,但具有更好的性能
- QVector 类通常用于存储一组数据,并且需要对数据进行动态操作,如排序、查找等,
QVector<int> vec; vec.append(1); vec.append(2); vec.append(3); int num = vec.at(1); // 获取第 2 个元素 vec.removeLast(); // 删除最后一个元素
- QHash
- QHash 类是一种无序的哈希容器,它可以将一个键值对映射到另一个键值对,且键值对是按照哈希值进行存储的
- QHash 类通常用于对一组数据进行哈希操作,常见的操作包括查找、插入、删除等
QHash<QString,int> hash; hash.insert("Tom",18); hash.insert("Jack",20); hash.insert("Lucy",17); int age = hash.value("Tom"); // 获取键为 "Tom" 的值 hash.remove("Lucy"); // 删除键为 "Lucy" 的键值对
- QMap
- QMap 类(基于红黑树的映射表)是一种有序的映射容器,它可以将一个键值对映射到另一个键值对,且键值对是按照键的顺序进行排序的
- QMap 类通常用于对一组数据进行映射操作,常见的操作包括查找、插入、删除等
QMap<QString,int> map; map.insert("Tom",18); map.insert("Jack",20); map.insert("Lucy",17); int age = map.value("Tom"); // 获取键为 "Tom" 的值 map.remove("Lucy"); // 删除键为 "Lucy" 的键值对
如果需要对数据进行频繁的插入和删除操作,建议使用 QLinkedList 类;如果需要对数据进行频繁的访问和遍历操作,建议使用 QList 类;如果需要对数据进行排序和查找操作,建议使用 QMap 类;如果需要对数据进行哈希操作,建议使用 QHash 类;如果需要对数据进行动态操作,建议使用 QVector 类
19. QString 与基本数据类型转换
- 1、将 QString 转换为基本数据类型
QString str = "123"; int num = str.toInt(); // 将 QString 转换为 int 类型 float f = str.toFloat(); // 将 QString 转换为 float 类型 double d = str.toDouble(); // 将 QString 转换为 double 类型
- 2、将基本数据类型转换为 QString
// 通过QString的静态函数,可以将int、float、double等基本数据类型转换为QString int num = 123; QString str = QString::number(num); // 将 int 类型转换为 QString float f = 3.14; QString str2 = QString::number(f); // 将 float 类型转换为 QString
20. Qt 中的用户界面类
-
QLayout
- QLayout 类是 Qt 中用于管理控件布局的类,它可以将控件按照一定的布局方式进行排列,如水平布局、垂直布局、网格布局等
- QLayout 类通常用于创建复杂的用户界面,可以有效地管理控件的位置和大小
QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(button1); layout->addWidget(button2); layout->addWidget(button3); setLayout(layout);
-
QStackedWidget
- QStackedWidget 类是一种堆栈容器控件,它可以将多个子控件按照堆栈的方式进行管理,只显示当前的子控件,其它子控件被隐藏
- QStackedWidget 类通常用于创建多页应用程序,例如多个窗口之间的切换
QStackedWidget *stack = new QStackedWidget; stack->addWidget(page1); stack->addWidget(page2); stack->addWidget(page3); stack->setCurrentIndex(0);
-
QSplitter
- QSplitter 类是一种分割窗口控件,它可以将窗口分割成多个部分,每个部分可以包含一个或多个子控件
- QSplitter 类通常用于创建可调整大小的用户界面,可以让用户自由调整窗口的大小和位置
QSplitter *splitter = new QSplitter(Qt::Horizontal); splitter->addWidget(widget1); splitter->addWidget(widget2); splitter->addWidget(widget3);
-
QDockWidget
- QDockWidget 类是一种停靠窗口控件,它可以将窗口停靠在主窗口的边缘或浮动在主窗口上方
- QDockWidget 类通常用于创建多文档界面(MDI)应用程序,可以让用户自由调整窗口的停靠位置和大小
QDockWidget *dock = new QDockWidget; dock->setWidget(widget); dock->setWindowTitle("Dock Window"); addDockWidget(Qt::LeftDockWidgetArea,dock);