Qt 是目前最先进、最完整的跨平台C++开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。
在本文中,我们通过使用C++和Qt Widgets模块实现一个简单的记事本应用程序来学习基本的Qt知识,该应用程序是一个小型的文本编辑器,允许您创建文本文件、保存、打印或重新打开并在此编辑它,还可以设置要使用的字体。
在上文中(点击这里回顾>>),我们为大家介绍了主源文件的生成、如何开始设计用户界面,本文将为大家详细介绍设计用户界面的具体步骤。
点击获取Qt Widget组件下载(Q技术交流:166830288)
设计一个用户界面
使用Qt Designer(设计器)
向导创建一个使用QMainWindow的应用程序,它有自己的布局,您可以在其中添加菜单栏、dock小部件、工具栏和状态栏。中心区域可以被任何类型的小部件占用,向导将Notepad小部件放在那里。
在Qt Designer中添加小部件:
- 在Qt Creator编辑模式下,双击记事本,在集成的Qt设计器中启动该文件。
- 将小部件文本编辑器(QTextEdit)拖放到表单中。
- 按Ctrl+A(或Cmd+A)选择小部件,然后单击Lay out Vertically(或按Ctrl+L)应用垂直布局(QVBoxLayout)。
- 按Ctrl+S(或Cmd+S)保存更改。
UI现在看起来像下面的Qt Designer:
您可以在代码编辑器中查看生成的XML文件:
XML
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Notepad</class>
<widget class="QMainWindow" name="Notepad">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>Notepad</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextEdit" name="textEdit"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
...
下面一行包含XML声明,它指定了文档中使用的XML版本和字符编码:
XML
<?xml version="1.0" encoding="UTF-8"?>
文件的其余部分指定了一个UI元素,该元素定义了一个Notepad小部件:
XML
<ui version="4.0">
UI文件与Notepad类的头文件和源文件一起使用,我们将在后面的小节中查看UI文件的其余部分。
Notepad Header文件
向导为Notepad类生成了一个头文件,其中包含必要的#includes、构造函数、析构函数和UI对象。该文件如下所示:
cpp
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class Notepad;
}
QT_END_NAMESPACE
class Notepad : public QMainWindow
{
Q_OBJECT
public:
explicit Notepad(QWidget *parent = nullptr);
~Notepad();
private:
Ui::Notepad *ui;
QString currentFile;
};
下面这行包括QMainWindow,它提供了一个主应用程序窗口:
下面几行在UI命名空间中声明Notepad类,这是uic工具从.ui文件生成的UI类的标准命名空间:
cpp
namespace Ui {
class Notepad;
}
类声明包含Q_OBJECT宏,它必须首先出现在类定义中,并将类声明为QObject。当然它也必须继承QObject,QObject为一个普通的c++类添加了一些功能。值得注意的是,类名和槽名可以在运行时查询,还可以查询槽的参数类型并调用它。
cpp
class Notepad : public QMainWindow
{
Q_OBJECT
下面几行声明了一个构造函数,它有一个默认实参parent,值0表示该小部件没有父部件(它是顶级小部件)。
cpp
public:
explicit Notepad(QWidget *parent = nullptr);
下面一行声明了一个虚析构函数来释放对象在其生命周期中获得的资源,根据c++的命名约定,析构函数具有与其关联的类相同的名称,并以波浪号(~)作为前缀。在QObject中,析构函数是虚函数,以确保在通过指向基类的指针删除对象时正确调用派生类的析构函数。
cpp
~Notepad();
下面几行声明了一个成员变量,它是指向Notepad UI类的指针。成员变量与特定的类相关联,并且它的所有方法都可以访问。
cpp
private:
Ui::Notepad *ui;
QString currentFile;
};
Notepad源文件
向导为记事本类生成的源文件如下所示:
cpp
#include "notepad.h"
#include "ui_notepad.h"
Notepad::Notepad(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Notepad)
{
ui->setupUi(this);
}
以下几行包括由向导生成的记事本类头文件和由UI工具生成的UI头文件:
cpp
#include "notepad.h"
#include "ui_notepad.h"
下面一行定义了Notepad的构造函数:
cpp
Notepad::Notepad(QWidget *parent) :
下面这行调用QMainWindow构造函数,它是Notepad类的基类:
cpp
QMainWindow(parent),
下面这行代码创建了UI类实例并将其赋值给UI成员:
cpp
ui(new Ui::Notepad)
下面这行设置了UI:
cpp
{
ui->setupUi(this);
在析构函数中,删除UI:
cpp
Notepad::~Notepad()
{
delete ui;
}
项目文件
向导为我们生成以下项目文件CMakeLists.txt:
cpp
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(notepad LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/tutorials/notepad")
find_package(Qt6
REQUIRED COMPONENTS Core Gui Widgets
OPTIONAL_COMPONENTS PrintSupport
)
qt_standard_project_setup()
qt_add_executable(notepad
main.cpp
notepad.cpp notepad.h notepad.ui
)
set_target_properties(notepad PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(notepad PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
if(TARGET Qt6::PrintSupport)
target_link_libraries(notepad PRIVATE Qt6::PrintSupport)
endif()
# Resources:
set(notepad_resource_files
"images/bold.png"
"images/copy.png"
"images/create.png"
"images/cut.png"
"images/edit_redo.png"
"images/edit_undo.png"
"images/exit.png"
"images/font.png"
"images/info.png"
"images/italic.png"
"images/new.png"
"images/open.png"
"images/paste.png"
"images/pencil.png"
"images/print.png"
"images/save.png"
"images/save_as.png"
"images/underline.png"
)
qt_add_resources(notepad "notepad"
PREFIX
"/"
FILES
${notepad_resource_files}
)
install(TARGETS notepad
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)
项目文件指定项目中包含的源文件、头文件和UI文件。