文章目录
前言
本文介绍QT常用控件的第二个按钮,Tool Button按钮编程。通过这个例子,初步了解QToolBar容器控件,项目演示了如何将Tool Button按钮放置到QToolBar容器控件中。此外通过这个项目能够进一步熟悉QT的信号与槽机制,特别是连接函数connect()函数在Qt4和Qt5中的使用。
我们的调试环境仍然是双架构Kits
,编译调试在当前的ubuntu(qt5)中进行,重新编译后下载到目标arm设备(qt4)中运行。
我们的编程环境为:Ubuntu64位系统(22.04),目标架构:(1)qt5 x86_64
架构,(2)qt4 32位arm
架构。
环境配置请参见《Qt常用的按钮控件编程(一)》第1节。
4、Tool Button
按钮编程
Tool Button 是 Qt 框架中常用的一个按钮控件,可以显示图标和文本标签。
ToolButton通常是作为动作控件使用的,可以与其他容器控件配合使用,例如QToolBar或QWidget等,以完成应用程序的布局和UI设计。ToolButton可以提供快捷方式和操作接口,可以方便用户快速访问和使用程序的功能,提高用户体验和操作的便捷性。
QToolBar是一个预定义的容器控件,常用来放置常用的或特定功能的ToolButton按钮。它通常位于主窗口MainWindow的顶部或底部,与主窗口相互协调,可以提供用户更好的操作体验。
4.1 程序完成后的执行结果
- 最终程序实现的效果如下。将自定义的设置工具按钮嵌入工具栏中。
- 按下按钮,跳出警告消息框:
4.2 生成项目
- 打开 Qt Creator 并创建一个新的 应用程序项目_qtoolbutton:
- 默认继承QMainWindow 类,(在上个项目_qpushbutton中,选择了Widget基类),不要勾选“Generate form”:
- 将两个配置好的Kits同时选上(后期我们会通过条件编译进行选择):
- 其他界面使用默认设置,项目生成的最初代码:
4.3 完成代码编辑
4.3.1 修改项目文件 _qpushbutton.pro
1 QT += core gui
2
3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
4
5 CONFIG += c++11
6
7 # You can make your code fail to compile if it uses deprecated APIs.
8 # In order to do so, uncomment the following line.
9 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
10
11 SOURCES += \
12 main.cpp \
13 mainwindow.cpp
14
15 HEADERS += \
16 mainwindow.h
17
18 # Default rules for deployment.
19 qnx: target.path = /tmp/$${TARGET}/bin
20 else: unix:!android: target.path = /opt/$${TARGET}/bin
21 !isEmpty(target.path): INSTALLS += target
22
23 # 根据使用的 Qt 版本设置编译条件
24 greaterThan(QT_MAJOR_VERSION, 4) {
25 # 如果使用的是 Qt 5 或者更新版本
26 message("使用的是 Qt 5版本")
27
28 } else {
29 # 如果使用的是 Qt 4 或者更早的版本
30 message("使用的是 Qt 4版本")
31 DEFINES += QT_ARM_PLATFORM
32 QMAKE_CXXFLAGS += -std=c++11
33 QMAKE_CXXFLAGS += -Wno-psabi -Wno-deprecated-declarations
34
35 LIBS += -lts
36
37 }
我们在系统生成的项目文件中使用条件编译增加目标为qt4-arm时的代码:
- 第32行:定义预处理器宏 QT_ARM_PLATFORM,这个宏将被传递给编译器和链接器,用来在程序中做条件编译,判定当前编译的代码是否运行在arm。
- 第32行:由于最新版本的 Qt Creator 默认使用了 C++11 标准。所以在自动生成的代码中会使用 C++11 新增的关键字 nullptr,但是我们的编译器并不认识它,会导致编译失败。增加
QMAKE_CXXFLAGS += -std=c++11
就能修正这一错误。
第33行:
QMAKE_CXXFLAGS += -Wno-psabi -Wno-deprecated-declarations
可以帮助我们忽略掉我们不关心的警告。
第34行:LIBS += -lts 指令用于链接触摸屏 tslib的库文件。
4.3.2 修改 main.cpp
1 #include "mainwindow.h"
2
3 #include <QApplication>
4 //引入 QPushButton
5 #ifdef QT_ARM_PLATFORM
6 #include <QTextCodec>
7 #endif
8 int main(int argc, char *argv[])
9 {
10 QApplication a(argc, argv);
11
12 #ifdef QT_ARM_PLATFORM
13 //解决中文乱码
14 QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
15 QTextCodec::setCodecForTr(QTextCodec::codecForName("system")); //若英文系统,则用GBK
16 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
17 QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
18 #endif
19
20 MainWindow w;
21 w.show();
22 return a.exec();
23 }
为了解决当程序运行在arm架构系统时,中文显示文乱码问题,根据从.pro获得的宏QT_ARM_PLATFORM作为编译条件,判断如果系统运行在arm架构,则程序包含文本字符串转换。
4.3.3 修改 mainwindow.h
1 #ifndef MAINWINDOW_H
2 #define MAINWINDOW_H
3
4 #include <QMainWindow>
5 /* 引入 QToolButton 类 */
6 #include <QToolButton>
7 /* 引入 QToolBar 类 */
8 #include <QToolBar>
9 class MainWindow : public QMainWindow
10 {
11 Q_OBJECT
12
13 public:
14 MainWindow(QWidget *parent = nullptr);
15 ~MainWindow();
16
17 private:
18 /* 声明一个 QToolButton 对象 */
19 QToolButton *toolButton;
20 /* 声明一个 QToolBar 对象 */
21 QToolBar *toolBar;
22
23 private slots:
24 /* 声明对象 toolBar 的槽函数 */
25 void onToolButtonClicked();
26
27 };
28 #endif // MAINWINDOW_H
第 19 和 21 行,声明 QToolButton 对象和 QtoolBar 对象。
第 25行,声明一个 QToolButton 对象的槽函数,用来响应对toolButton按钮的点击。
4.3.4 修改 mainwindow.cpp
1 #include "mainwindow.h"
2 #include <QApplication>
3 #include <QStyle>
4 #include <QMessageBox>
5 #include <QTextCodec>
6
7 MainWindow::MainWindow(QWidget *parent)
8 : QMainWindow(parent)
9 {
10 /* 设置主窗体的位置和大小 */
11 this->setGeometry(0, 0, 800, 480);
12 /* 实例化 QToolBar 对象 */
13 toolBar = new QToolBar(this);
14 /* 设置 toolBar 的位置和大小 */
15 toolBar->setGeometry(0, 0, 800, 80);
16 /* 实例化 QStyle 类对象,用于设置风格,调用系统类自带的图标 */
17 QStyle *style = QApplication::style();
18 /* 使用 Qt 自带的标准图标,可以在帮助文档里搜索 QStyle::StandardPixmap */
19 //QIcon icon = style->standardIcon(QStyle::SP_TitleBarContextHelpButton);
20 QIcon icon = style->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton);
21 /* 实例化 QToolButton 对象 */
22 toolButton = new QToolButton();
23 /* 设置图标 */
24 toolButton->setIcon(icon);
25 /* 设置要显示的文本 */
26 toolButton->setText("设置");
27 /* 调用 setToolButtonStyle()方法,设置 toolButoon 的样式,设置为文本置于图标下方 */
28 toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
29 //连接槽函数
30
31 #ifdef QT_ARM_PLATFORM
32 // 在 Qt 4 中,我们使用 QObject::connect() 函数来连接信号和槽:
33 connect(toolButton, SIGNAL(clicked()), this, SLOT(onToolButtonClicked()));
34 #else
35 // 在 Qt 5 中,由于新的信号和槽语法已被引入,可以使用关键字 connect的函数指针参数语法来连接信号和槽:
36 connect(toolButton, &QToolButton::clicked, this, &MainWindow::onToolButtonClicked);
37 #endif
38
39 /* 最后将 toolButton 添加到 ToolBar 里 */
40 toolBar->addWidget(toolButton);
41 }
42
43 MainWindow::~MainWindow()
44 {
45 }
46
47 /* 槽函数的实现 */
48 void MainWindow::onToolButtonClicked()
49 {
50 //弹出警告框
51 QMessageBox::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("设置成功"), QMessageBox::Ok);
52
53 }
这段代码实现了一个工具栏 toolbar 和一个工具按钮 toolButton,工具按钮上面有一个 Qt 自带的图标并有一个设置文本,点击该按钮会弹出一个警告框显示 “设置成功” 的文字。
- 第11行:首先设置主窗体的位置和大小为 (0,0) 和 (800,480);
- 第13行和第15行:实例化一个 QToolBar 工具栏对象,设置位置为主窗口顶部,并占据整个界面的一行,高度为80;
- 第17行:使用 QApplication 的 style() 函数获取当前应用程序的样式;
- 第20行:使用 QStyle::standardIcon() 函数来获取一个标准图标,这里获取的是一个水平扩展的工具栏图标;
- 第22行:实例化一个 QToolButton 对象;
- 第24行:设置上面的工具按钮的图标为上一步获取的图标;
- 第26行:设置工具提示文本为 “设置”;
- 第28行:设置工具按钮的样式,设置为文本置于图标下方;
- 第33行:如果编译是在 Qt 4 中进行,则使用旧的 QObject::connect() 函数来将工具按钮的 clicked(点击) 信号连接到主窗口类的 onToolButtonClicked 槽函数;
- 第36行:如果编译是在 Qt5 中进行,使用新的 connect 函数指针参数语法来将工具按钮的 clicked (点击) 信号连接到主窗口类的 onToolButtonClicked 槽函数;
- 第40行 使用 QToolBar 的 addWidget() 函数将工具按钮添加到工具栏中。
4.4 切换Kit,获得运行在不同系统中的运行的执行文件
点击窗口左边的Debug,可以选择编译运行在不同平台上的可执行文件,arm-v7为arm架构的设备,使用Qt4库,而桌面则是当前ubuntu系统,使用Qt5。
Qt5编译完成的可执行程序_qtoolbutton
,存放在项目目录的build-_qtoolbutton-unknown-Debug/
文件夹下,Qt4编译完成的可执行程序_qtoolbutton
,存放在项目目录的build-_qtoolbutton-arm_v7-Debug/
文件夹下。
4.5 程序中的qt机制
4.5.1 信号与槽的解耦功能介绍、connect()
在Qt4和Qt5中使用分析
在程序中,不同对象之间的耦合度越低,就越容易维护和扩展。例如,当一个类的内部发生变化时,只会影响到该类的实现和使用,而不会对其他类造成太大的影响。这种低耦合度的设计可以使程序更加灵活和易于修改,从而更好地适应需求变化。
解耦(Decoupling)是指在软件设计中,降低不同模块、组件或对象之间的依赖关系,从而提高软件的可维护性和可扩展性。
信号与槽机制就是一种解耦方式,通过信号与槽之间的连接,解除了不同对象之间的直接依赖关系。当某个对象发送了信号时,其他对象只需要在槽函数中捕获该信号,而不需要直接调用该对象的方法。这样,不同对象之间的耦合度就降低了,从而更容易维护和扩展程序。信号与槽就是用connect()
函数连接起来的。connect函数的参数包括四个:
- 发射信号的对象指针
- 发射信号的信号函数
- 接收信号的对象指针
- 接收信号的槽函数
在我们上面的_qpushbutton项目中,将toolButton按钮的 clicked 信号连接到主窗口定义的槽函数onToolButtonClicked()上:
- Qt4:
connect(toolButton, SIGNAL(clicked()), this, SLOT(onToolButtonClicked()));
- Qt5:
connect(toolButton, &QToolButton::clicked, this, &MainWindow::onToolButtonClicked);
第一句是旧版方式,在Qt4中使用,信号与槽之间使用的是字符串,即 SIGNAL 和 SLOT 宏,例如 SINGAL(clicked) 和 SLOT(onToolButtonClicked())。
第二句是 Qt5 中新引入的方式。在这种方式中,信号和槽的连接使用了一个新的语法,即直接使用信号和槽的函数指针。例如 &QToolButton::clicked 表示 QToolButton 类的 clicked() 信号,&MainWindow::onToolButtonClicked 表示 MainWindow 类的 onToolButtonClicked() 槽函数。Qt5 中引入这种新的连接方式,可以带来以下一些好处:
- 编译时检查:由于信号和槽的连接使用的是函数指针,因此编译器可以在编译时就检查连接的有效性,避免了在运行时才能发现的错误。
- 更安全:使用函数指针的方式,可以避免一些潜在的问题,例如字符串的拼写错误、槽函数不存在等。
- 更加简洁:相较于字符串,函数指针的语法更加简洁和易于理解。
需要注意的是,Qt5 中的新连接语法不完全兼容 Qt4 的旧语法。因此,在将 Qt4 程序迁移到 Qt5 时,也需要将相应的信号和槽的连接方式进行更新。
4.5.2 QToolBar
QToolBar 是一个容器控件。它提供了一种在主窗口中快速创建工具栏的方式,可以方便地创建、添加和管理工具栏以及工具按钮等控件。QToolBar 默认是可以拖拽的,也就是说,用户可以将工具栏拖动到窗口的任意位置。QToolBar 可以被添加到 QMainWindow 或其他以QWidget为基类的容器窗口中。
在我们上面的_qtoolbutton项目中,简单介绍了QToolBar和Tool Button 的使用,我们创建了一个 QToolBar 对象,并将其添加到了主窗口中。接着,我们创建了一个 Tool Button 按钮,并设置对应的文本和工具提示,然后通过 addWidget 方法将其添加到了 QToolBar 中。
在实际应用中,QMenu 和 QToolBar 经常一起使用,可以在菜单栏中创建菜单,用于对应用程序进行一些基本的操作,例如打开或保存文件,或进行一些设置选项。同时,可以在 QToolBar 中添加相同的操作按钮或其他工具按钮(例如下拉框、复选框等),以便用户可以更快速、方便地访问这些操作命令。这种方式不仅更方便用户操作,还能够使应用程序的用户界面看起来更加整洁和专业。
当 QMenu 和 QToolBar 一起使用时,通常需要添加 QAction 才能将菜单项和工具栏按钮关联起来,从而使得这些控件的行为一致。这是因为,QAction 不仅可以添加到 QMenuBar 和 QToolBar 中,还可以添加到 QMenu、QSystemTrayIcon 等其他控件中,因此可以实现控件之间的交互。