Detailed explanation of Qt interface layout management

This article uses a slightly complicated example to explain the common functions of GUI design, including layout management during interface design, and how to access interface components in the program.

Example program function

Create a Widget Application project samp2_2, select the base class QDialog when creating a form, name the generated class QWDialog, and choose to generate a form.

The newly created project samp2_2 has an interface file qwdialog.ui, a header file qwdialog.h and source program file qwdialog.cpp. In addition, there is the project file samp2_2.pro and the main program file main.cpp.

The design interface of qwdialog.ui interface file is shown in Figure 1. The main function of the program is to set the text font style and color of the text box in the middle.

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, C++ design pattern, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project actual combat, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓

 

Figure 1 Design-time interface of sample program samp2_2

When designing the interface, modify the objectName of the components that need to be accessed, such as each button, the edit box that needs to read the input, the label that needs to display the result, etc., so that they can be distinguished in the program. For components that do not require program access, there is no need to modify their objectName, such as GroupBox, Frame, layout, etc. for grouping components on the interface, and let the UI designer automatically name them.

Table 2 Related settings of each component in qwdialog.ui
object name class name property setting Remark
txtEdit  QPlainTextEdit Text="Hello, World
It is my demo. "
Font.PointSize=20
Used to display text content, editable
chkBoxUnder  QCheckBox  Text="Underline" set font to underline
chkBoxItalic  QCheckBox  Text="Italic" set font to italic
chkBoxBold  QCheckBox  Text="Bold" set font to bold
rBtnBlack  QRadioButton  Text="Black" font color is black
rBtnRed  QRadioButton  Text="Red" font color is red
rBtnBlue  QRadioButton  Text="Blue" font color is blue
btnOK  QPushButton  Text="OK" Return OK and close the window
btnCancel  QPushButton  Text="Cancel"  return to cancel, and close the window
btnClose  QPushButton  Text="Exit" exit the program
QWDialog  QWDialog  windowTitle="Dialog by Designer" The class name of the interface window is QWDialog, objectName should not be modified


For the property setting of interface components, you need to pay attention to the following points.

  1. objectName is the instance name of the component created on the form. Each component on the interface needs to have a unique objectName. When accessing the interface component in the program, it is accessed through its objectName, and the automatically generated slot function name also has objectName. Therefore, the objectName of the component needs to be set before designing the program, and generally do not need to be changed after setting. If the objectName is changed after the program is designed, the code involved needs to be changed accordingly.
  2. The objectName of the form is the class name of the form. Do not modify the objectName of the form in the UI designer. The instance name of the form needs to be defined in the code that uses the form.

Interface component layout

Qt's interface design uses the Layout function. The so-called layout refers to the arrangement of components on the interface. The layout can make the components regularly distributed, and automatically adjust the size and relative position as the size of the form changes. Layout management is an essential skill in GUI design. The following will explain step by step how to realize the interface design shown in Figure 1.

Hierarchical Relationship of Interface Components

In order to design the distribution of various components on the interface more beautifully, some container classes are often used, such as QgoupBox, QtabWidget, QFrame, etc.

For example, place 3 CheckBox components in a GroupBox component, and the GroupBox component is the container of these 3 CheckBoxes, and moving this GroupBox will move 3 CheckBoxes at the same time.

 

Figure 3 Placement and hierarchical relationship of interface components

Figure 3 shows the early stages of designing the interface in Figure 1. 2 GroupBox components are placed on the form, 3 CheckBox components are placed in groupBox1, and 3 RadioButton components are placed in groupBox2. The Object Inspector on the right side of Figure 3 shows the hierarchical relationship between the components on the interface.

layout management

Qt provides rich layout management functions for interface design. In the UI designer, there are two component panels, Layouts and Spacers, in the component panel, and there are buttons for layout management in the toolbar above the form (as shown in Figure 4) .

 

Figure 4 Component Palette and Toolbar for Layout Visual Design

The functions of the layout components in the Layouts and Spacers component panels are shown in Table 5:

Table 5 Components used for layout on the component panel
layout component Function
Vertical Layout Vertical layout, components are automatically distributed in the vertical direction
Horizontal Layout Horizontal layout, components are automatically distributed in the horizontal direction
Grid Layout Grid layout, when the size of the grid layout changes, the size of each grid changes
Form Layout Form layout, similar to grid layout, but only the rightmost column of the grid will change size
Horizontal Spacer a space for horizontal separation
Vertical Spacer a space for vertical separation

When using the layout component in the component panel to design the layout, first drag and drop a layout component onto the form, for example, when designing the layout of the three buttons in Figure 4, first place a Horizontal Layout on the form, and the layout component will be displayed in red The frame is displayed. Then drag and drop 3 Push Buttons and 2 Horizontal Spacers into the layout component to get the horizontal layout effect of the 3 buttons in Figure 1.

There is a toolbar on the top of the design form, which is used to adjust the designer to enter different states, and to carry out layout design. The functions of the buttons on the toolbar are shown in Table 6.

Table 6 The functions of each button in the UI designer toolbar
Buttons and Shortcuts Function
Edit Widget (F3) The interface design enters the editing state, which is the normal design state
Edit Signals/Slots(F4)  Enter the visual design state of signals and slots
Edit Buddies Enter the partnership editing state, you can set a Label and a component to become a partnership
Edit Tab Order Enter the tab order editing state, the tab order is the order in which the input focus jumps between the components of the interface when the Tab key is pressed on the keyboard
Lay Out Horizontally (Ctrl+H) Lay out the selected components on the form horizontally
Lay Out Vertically (Ctrl+L)  Lay out the selected components on the form vertically
Lay Out Horizontally in Splitter Horizontally split the layout of the selected components on the form with a split bar
Lay Out Vertically in Splitter Use a split bar to vertically split the layout of the selected components on the form
Lay Out in a Form Layout Layout the selected components on the form according to the form
Lay Out in a Grid Grid layout the selected components on the form
Break Layout Release the layout of the selected components on the form, that is, break up the existing layout
Adjust Size(Ctrl+J) Automatically resize selected components

使用工具栏上的布局控制按钮时,只需在窗体上选中需要设计布局的组件,然后点击某个布局按钮即可。在窗体上选择组件时同时按住 Ctrl 键,可以实现组件多选,选择某个容器类组件,相当于选择了其内部的所有组件。

例如,在图 3 的界面中,选中 groupBox1,然后单击“Lay Out Horizontally”工具栏按钮,就可以对 groupBox1 内的 3 个 CheckBox 水平布局。

在图 4 的界面上,使 groupBox1 里的 3 个 CheckBox 水平布局,groupBox2 里的 3 个 RadioButton 水平布局,下方 3个按钮水平布局。在窗体上又放置了一个 PlainTextEdit 组件。现在,改变 groupBox1、groupBox2 或按钮的水平布局的大小,其内部组件都会自动改变大小。但是当改变窗体大小时,界面上的各组件却并不会自动改变大小。

随后还需为窗体指定一个总的布局。选中窗体(即不要选择任何组件),单击工具栏上的“Lay Out Vertically”按钮,使 4 个组件垂直分布。这样布局后,当窗体大小改变时,各个组件都会自动改变大小。

在 UI 设计器里可视化设计布局时,要善于利用水平和垂直空格组件,善于设置组件的最大、最小宽度和高度来实现某些需要的布局效果。

伙伴关系与 Tab 顺序

在 UI 设计工具栏上单击“Edit Buddies”按钮可以进入伙伴关系编辑状态,如设计一个窗体时,进入伙伴编辑状态之后的界面如图 7 所示。

 

图 7 编辑伙伴关系


伙伴关系(Buddy)是指界面上一个 Label 和一个组件相关联,如图 7 中的伙伴关系编辑状态,单击一个 Label,按住鼠标左键,然后拖向一个组件,就建立了 Label 和组件之间的伙伴关系。

伙伴关系是为了在程序运行时,在窗体上用快捷键快速将输入焦点切换到某个组件上。例如,在图 7 的界面上,设定“姓名”标签的 Text 属性为“姓名(&N)”,其中符号“&”用来指定快捷字符,界面上并不显示“&”,这里指定快捷字母为 N。那么程序运行时,用户按下Alt+N,输入焦点就会快速切换到“姓名”关联的输入框内。

 

图 8 Tab 顺序编辑状态


在 UI 设计器工具栏上单击“Edit Tab Order”按钮进入Tab 顺序编辑状态(如图 8 所示)。Tab 顺序是指在程序运行时,按下键盘上的 Tab 键时输入焦点的移动顺序。一个好的用户界面,在按 Tab 键时,焦点应该以合理的顺序在界面上移动,而不是随意地移动。

进入 Tab 顺序编辑状态后,在界面上会显示具有 Tab 顺序组件的编号,依次按希望的顺序单击组件,就可以重排 Tab 顺序了。没有输入焦点的组件是没有 Tab 顺序的,如 Label 组件。

项目功能实现

下面开始设计程序功能。对于该程序,希望它的功能如下:

  1. 单击 UnderLine、Italic、Bold 3 个 CheckBox 时,根据其状态,设置 PlainTextEdit 里的文字的字体样式;
  2. Black、Red、Blue 3 个 RadioButton 是互斥选择的,单击某个 RadioButton 时,设置文字的颜色;
  3. 单击“确定”“取消”或“退出”按钮时,关闭窗口,退出程序。

字体样式设置

窗体在设计模式下,选中 chkBoxUnder 组件,单击右键调出其快捷菜单。在快捷菜单中单击菜单项“Go to slot…”(中文状态为“转到槽”),出现如图 9 所示的对话框。

 图 9 QcheckBox的Go to slot对话框


该对话框列出了 QCheckBox 类的所有信号,第一个是 clicked(),第二个是带一个布尔类型参数的 clicked(bool)。

信号 clicked(bool) 会将 CheckBox 组件当前的选择状态作为一个参数传递,在响应代码里可以直接利用这个传递的参数。而如果用信号 clicked(),则需要在代码里读取 CheckBox 组件的选中状态。为了简化代码,选择 clicked(bool) 信号。

选择 clicked(bool),然后单击“OK”按钮,在 QWDialog 的类定义中,会在 private slots 部分自动增加一个槽函数声明,函数名是根据发射对象及其信号名称自动命名的。

void on_chkBoxUnder_clicked(bool checked);

同时,在 qwdialog.cpp 文件中自动添加了函数 on_chkBoxUnder_clicked(bool) 的框架,在此函数中添加如下的代码,实现文本框字体下划线的控制。

void QWDialog::on_chkBoxUnder_clicked(bool checked)
{
    QFont font=ui->txtEdit->font();
    font.setUnderline(checked);
    ui->txtEdit->setFont(font);
}

以同样的方法为 Italic 和 Bold 两个 CheckBox设计槽函数,编译后运行,发现已经实现了修改字体的下划线、斜体、粗体属性的功能,说明信号与槽函数已经关联了。

但是,查看 QWDialog 的构造函数,构造函数只有简单的一条语句。

QWDialog::QWDialog(QWidget *parent) : QDialog(parent), ui(new Ui::QWDialog)
{
    ui->setupUi(this);
}

这里没有发现用 connect() 函数进行几个 CheckBox 的信号与槽函数关联的操作。这些功能是如何实现的呢?

查看编译生成的 ui_qwdialog.h 文件。构造函数里调用的 setupUi() 是在 ui_qwdialog.h 文件里实现的。查看 setupUi() 函数的内容,也没有发现用 connect() 函数进行几个 CheckBox 的信号与槽关联的操作,只是在 setupUI()里发现了如下的一条语句:

QMetaObject::connectSlotsByName(QWDialog);

秘密就在于这条语句。connectSlotsByName(QWDialog) 函数将搜索 QWDialog 界面上的所有组件,将信号与槽函数匹配的信号和槽关联起来,它假设槽函数的名称是:

void on_<object name>_<signal name>(<signal parameters>);

例如,通过 UI 设计器的操作,为 chkBoxUnder 自动生成的槽函数是:

void on_chkBoxUnder_clicked(bool checked);

它就正好是 chkBoxUnder 的信号 clicked(bool) 的槽函数。那么,connectSlotsByName() 就会将此信号和槽函数关联起来,如同执行了下面的这样一条语句:

connect(chkBoxUnder, SIGNAL(clicked (bool)),
this, SLOT (on_chkBoxUnder_clicked (bool));

这就是用 UI 设计器可视化设计某个组件的信号响应槽函数,而不用手工去将其关联起来的原因,都是在界面类的构造函数里调用 setupUi() 自动完成了关联。

字体颜色设置

设置字体的 3 个 RadioButton 是互斥性选择的,即一次只有一个 RadioButton 被选中,虽然也可以采用可视化设计的方式设计其 clicked() 信号的槽函数,但是这样就需要生成 3 个槽函数。这里可以简化设计,即设计一个槽函数,将 3 个 RadioButton 的 clicked() 信号关联到这一个槽函数。

为此,在 QWDialog 类的 private slots 部分增加一个槽函数定义如下:

void setTextFontColor();

提示 将鼠标光标移动到这个函数的函数名上面,单击右键,在弹出的快捷菜单中选择“Refactor”→“Add Definition in qwdialog.cpp”,就可以在 qwdialog.cpp 文件中自动为函数 setTextFontColor() 生成一个函数框架。

在 qwdialog.cpp 文件中,为 setTextFontColor() 编写实现代码如下:

void QWDialog::setTextFontColor()
{
    QPalette plet=ui->txtEdit->palette();
    if (ui->rBtnBlue->isChecked())
        plet.setColor(QPalette::Text,Qt::blue);
    else if (ui->rBtnRed->isChecked())
       plet.setColor(QPalette::Text,Qt::red);
    else if (ui->rBtnBlack->isChecked())
        plet.setColor(QPalette::Text,Qt::black);
    else
       plet.setColor(QPalette::Text,Qt::black);
    ui->txtEdit->setPalette(plet);
}

由于这个槽函数是自定义的,所以不会自动与 RadioButton 的 clicked() 事件关联,此时编译后运行程序不会实现改变字体颜色的功能。需要在 QWDialog 的构造函数中手工进行关联,代码如下:

QWDialog::QWDialog(QWidget *parent) : QDialog(parent), ui(new Ui::QWDialog)
{
    ui->setupUi(this);
    connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
    connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
    connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
}

在构造函数中将 3 个 RadioButton 的 clicked() 信号与同一个槽函数 setTextFontColor() 相关联。再编译后运行,就可以更改文字的颜色了。

三个按钮的功能设计

界面上还有“确定”“取消”“退出”3 个按钮,这是在对话框中常见的按钮。“确定”表示确认选择并关闭对话框,“取消”表示取消选择并关闭对话框,“退出”则直接关闭对话框。

QWDialog 是从 QDialog 继承而来的,QDialog 提供了 accept()、reject()、close() 等槽函数来表示这三种状态,只需将按钮的 clicked() 信号与相应槽函数关联即可。

下面采用可视化的方式,将按钮的 clicked() 信号与这些槽函数关联起来。在 UI 设计器里,单击上方工具栏里的“Edit Signals/Slots”按钮,窗体进入信号与槽函数编辑状态,如图 10 所示。

 

图 10 窗体进入Signals/Slot编辑状态


将鼠标移动到“确定”按钮上方,再按下鼠标左键,移动到窗体的空白区域释放左键,这时出现如图 11 所示的关联设置对话框。

 

图 11 信号与槽关联编辑对话框


在图 11 中,左侧的列表框里显示了 btnOK 的信号,选择 clicked(),右边的列表框里显示了 QWDialog 的槽函数,选择 accept(),单击“OK”按钮。

同样的方法可以将 btnCancel 的 clicked() 信号与 QWDialog 的 reject() 槽函数关联,将 btnClose 的 clicked() 信号与 QWDialog 的 close() 槽函数关联。

注意,在图 11 的右侧列表框中没有 close() 槽函数,需要勾选下方的“Show signals and slots inherited from QWidget”才会出现 close() 函数。

设置完 3 个按钮的信号与槽关联之后,在窗体下方的 Signals 和 Slots 编辑器里也显示了这 3 个关联。实际上,可以直接在 Signals 和 Slots 编辑器进行关联设置。现在编译并运行程序,单击这 3 个按钮都会关闭程序。

那么,这 3 个按钮的信号与槽函数的关联是在哪里实现的呢?答案在 setupUi() 函数里,在 setupUi() 函数里自动增加了以下 3 行代码:

Object::connect(btnOK, SIGNAL(clicked()), QWDialog, SLOT(accept()));
QObject::connect(btnCancel, SIGNAL(clicked()), QWDialog, SLOT(reject()));
QObject::connect(btnClose, SIGNAL(clicked()), QWDialog, SLOT(close()));

这个实例程序的功能全部完成了。采用 UI 设计器设计了窗体界面,采用可视化和程序化的方式设计槽函数,设计信号与槽函数之间的关联。

从以上的设计过程可以看到,Qt Creator 和 UI 设计器为设计应用程序提供了强大的可视化设计功能。

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

Guess you like

Origin blog.csdn.net/m0_73443478/article/details/131404541