Qt 编程入门Qt Widgets
在本主题中,我们将通过使用 C++ 和 Qt Widgets 模块,传授Qt的基础知识。该应用程序是一个小型文本编辑器,允许您创建文本文件、保存、打印,或重新打开并再次编辑。您还可以设置要使用的字体。

运行示例
您可以通过以下方式运行示例:
- Qt Creator
打开Welcome 模式,并从Examples 中选择该示例。如需更多信息,请参阅Qt Creator :教程:构建与运行。
- Qt Extension for Visual Studio Code
在Command Palette 中运行Qt: Open Qt examples 命令,并从列表中选择该示例。有关更多信息,请参阅Qt Extension for Visual Studio Code :教程:构建和运行。
创建 Notepad 项目
在Qt Creator 中创建新项目时,向导会逐步引导您完成项目创建过程。该向导会提示您输入特定项目类型所需的设置,并为您创建项目。
注意: Qt Creator 中的用户界面文本以及生成的文件内容取决于您使用的Qt Creator 版本。

要创建“记事本”项目,请选择“File ” > “New Project ” > “Application (Qt) ” > Qt Widgets Application >Choose ,并按照向导的提示操作。在“Class Information ”对话框中,将类名输入为Notepad,并选择QMainWindow 作为基类。

该 Qt Widgets Application 向导将创建一个项目,其中包含一个主源文件以及一组用于定义用户界面(Notepad 控件)的文件:
- CMakeLists.txt——项目文件。
- main.cpp —— 应用程序的主源文件。
- notepad.cpp ——“记事本”控件中 notepad 类的源文件。
- notepad.h——Notepad 控件中 notepad 类的头文件。
- notepad.ui - Notepad 控件的用户界面表单。
这些文件已包含必要的模板代码,以便您能够编译并运行该项目。我们将在后续章节中详细探讨这些文件的内容。
了解更多
| 关于 | 此处 |
|---|---|
| 使用Qt Creator | Qt Creator |
| 使用Qt Creator | Qt Creator 教程 |
主源文件
向导会在 main.cpp 文件中生成以下代码:
#include "notepad.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Notepad w;
w.show();
return a.exec();
}我们将逐行分析这段代码。以下几行包含了“记事本”控件和QApplication 的头文件。所有 Qt 类都有一个以该类命名的头文件。
#include "notepad.h"
#include <QApplication>以下代码行定义了 main 函数,它是所有基于 C 和 C++ 的应用程序的入口点:
int main(int argc, char *argv[])下一行创建了一个QApplication 对象。该对象负责管理全局资源,对于运行任何使用Qt Widgets 的Qt程序而言都是必不可少的。它通过argc 命令行参数在argv 中构建应用程序对象。(对于不使用Qt Widgets 的GUI应用程序,可以使用QGuiApplication 代替。)
QApplication a(argc, argv);以下代码行创建了 Notepad 对象。这是向导为其创建类和 UI 文件的对象。用户界面包含视觉元素,在 Qt 中称为widgets 。小部件的示例包括文本输入框、滚动条、标签和单选按钮。 小部件也可以作为其他小部件的容器;例如,对话框或主应用程序窗口。
Notepad w;以下代码行将 Notepad 小部件以独立窗口的形式显示在屏幕上。小部件还可以充当容器,例如QMainWindow 通常就包含多种类型的小部件。默认情况下,小部件是不可见的;函数show() 可使小部件可见。
w.show();以下代码行使QApplication 进入其事件循环。当Qt应用程序运行时,会生成事件并将其发送给应用程序中的控件。事件的示例包括鼠标点击和按键操作。
return a.exec();了解更多
设计用户界面
向导会生成一个 XML 格式的用户界面定义文件:notepad.ui。当您在Qt Creator 中打开 notepad.ui 文件时,它会自动在集成的Qt Widgets Designer 中打开。
当您构建应用程序时,Qt Creator 会启动 QtUser Interface Compiler (uic),该工具会读取 .ui 文件并创建相应的 C++ 头文件 ui_notepad.h。
使用Qt Widgets Designer
向导会创建一个使用QMainWindow 的应用程序。它拥有自己的布局,您可以在其中添加菜单栏、停靠控件、工具栏和状态栏。中心区域可放置任何类型的控件。向导会将“记事本”控件放置在此处。
要在Qt Widgets Designer 中添加控件:
- 在Qt Creator 的Edit 模式下,双击“Projects ”视图中的notepad.ui文件,即可在集成的Qt Widgets Designer 中打开该文件。
- 将“文本编辑”(QTextEdit )控件拖放至表单中。
- 按Ctrl+A(或Cmd+A)选中控件,然后单击“Lay out Vertically ”(或按Ctrl+L)应用垂直布局(QVBoxLayout )。
- 按Ctrl+S(或Cmd+S)保存更改。
现在,在Qt Widgets Designer 中,用户界面如下所示:

您可以在代码编辑器中查看生成的 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 version="1.0" encoding="UTF-8"?>文件的其余部分定义了一个ui 元素,该元素定义了一个 Notepad 控件:
<ui version="4.0">该 UI 文件需与 Notepad 类的头文件和源文件配合使用。我们将在后续章节中详细探讨该 UI 文件的其余部分。
记事本头文件
向导为 Notepad 类生成了一个头文件,其中包含必要的 #include 语句、构造函数、析构函数以及 Ui 对象。该文件内容如下:
#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 ,该文件提供了一个主应用程序窗口:
#include <QMainWindow>以下几行在 Ui 命名空间中声明了 Notepad 类,该命名空间是uic 工具根据 .ui 文件生成的 UI 类的标准命名空间:
namespace Ui {
class Notepad;
}类声明中包含Q_OBJECT 宏。该宏必须位于类定义的开头,并将我们的类声明为QObject 。当然,它还必须继承自QObject 。QObject 为普通的C++类增添了若干功能。 值得注意的是,类名和插槽名可以在运行时进行查询。此外,还可以查询插槽的参数类型并调用该插槽。
class Notepad : public QMainWindow
{
Q_OBJECT以下几行声明了一个带有名为parent 的默认参数的构造函数。值 0 表示该控件没有父控件(它是顶级控件)。
public:
explicit Notepad(QWidget *parent = nullptr);以下代码行声明了一个虚拟析构函数,用于释放对象在其生命周期内获取的资源。 根据 C++ 命名约定,析构函数的名称与所属类相同,并在名前加一个波浪号 (~)。在QObject 中,析构函数被声明为虚拟的,以确保当通过基类指针删除对象时,派生类的析构函数能被正确调用。
~Notepad();以下几行声明了一个成员变量,该变量是 Notepad UI 类的指针。成员变量与特定类相关联,且该类的所有方法均可访问该变量。
private:
Ui::Notepad *ui;
QString currentFile;
};Notepad 源文件
向导为 Notepad 类生成的源文件如下所示:
#include "notepad.h"
#include "ui_notepad.h"
Notepad::Notepad(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Notepad)
{
ui->setupUi(this);
}以下几行代码导入了由向导生成的 Notepad 类头文件以及由uic 工具生成的 UI 头文件:
#include "notepad.h"
#include "ui_notepad.h"以下代码行定义了Notepad 的构造函数:
Notepad::Notepad(QWidget *parent) :以下代码行调用了QMainWindow 的构造函数,该类是Notepad类的基类:
QMainWindow(parent),以下代码行创建了 UI 类的实例,并将其赋值给ui 成员:
ui(new Ui::Notepad)以下代码行用于设置用户界面:
{
ui->setupUi(this);在析构函数中,我们销毁了ui :
Notepad::~Notepad()
{
delete ui;
}项目文件
向导为我们生成了以下项目文件:CMakeLists.txt :
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(notepad LANGUAGES CXX)
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
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
qt_generate_deploy_app_script(
TARGET notepad
OUTPUT_SCRIPT deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${deploy_script})该项目文件指定了项目中包含的源文件、头文件和 UI 文件。
了解更多
| 关于 | 此处 |
|---|---|
| 使用Qt Widgets Designer | Qt Widgets Designer 手册 |
| 布局 | 布局管理、控件与布局、布局示例 |
| Qt Widgets自带的小部件 | Qt Widgets 图库 |
| 主窗口和主窗口类 | 应用程序主窗口、主窗口示例 |
| QObject 与 Qt 对象模型(这是理解 Qt 的关键) | 对象模型 |
| qmake 与 Qt 构建系统 | qmake 手册 |
添加用户交互
要为编辑器添加功能,我们首先在工具栏上添加菜单项和按钮。
点击“在此处输入”,并添加“新建”、“打开”、“保存”、“另存为”、“打印”和“退出”选项。这将在下方的“操作编辑器”中生成 5 行内容。要将操作与槽连接起来,请右键单击一个操作,选择“Go to slot ” > “triggered() ”,并为该槽补全代码。
如果还想将这些动作添加到工具栏中,可以为每个QAction 分配一个图标,然后将QAction 拖动到工具栏上。分配图标的方法是在相关动作的Icon属性中输入图标名称。将QAction 拖动到工具栏后,点击该图标将调用关联的slot。
完成方法newDocument() :
void Notepad::newDocument()
{
currentFile.clear();
ui->textEdit->setText(QString());
}变量currentFile 是一个全局变量,用于存储当前正在编辑的文件,而clear() 用于清空文本缓冲区。变量currentFile 在 notepad.h 的私有部分中定义:
private:
Ui::Notepad *ui;
QString currentFile;打开文件
在 `notepad.ui` 中,右键单击 `actionOpen `,然后选择 `Go to Slot`。
完成方法open() 。
void Notepad::open()
{
QString fileName = QFileDialog::getOpenFileName(this, "Open the file");
if (fileName.isEmpty())
return;
QFile file(fileName);
currentFile = fileName;
if (!file.open(QIODevice::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, "Warning", "Cannot open file: " + file.errorString());
return;
}
setWindowTitle(fileName);
QTextStream in(&file);
QString text = in.readAll();
ui->textEdit->setText(text);
file.close();
}QFileDialog::getOpenFileName 将打开一个对话框,供您选择文件。QFile 对象myfile 将所选的file_name 作为参数传入。我们将所选文件也存储到全局变量currentFile 中,以备后用。我们使用file.open 将该文件作为只读文本文件打开。如果无法打开,则发出警告,程序终止。
我们为参数 `myfile` 定义了一个QTextStream `instream 。文件 `myfile ` 的内容被复制到 `QString `text 中。`setText(text) ` 将 `text` 填入编辑器的缓冲区中。
保存文件
我们以与“打开文件”相同的方式创建保存文件的方法:右键单击actionSave ,然后选择Go to Slot 。
void Notepad::save()
{
QString fileName;
// If we don't have a filename from before, get one.
if (currentFile.isEmpty()) {
fileName = QFileDialog::getSaveFileName(this, "Save");
if (fileName.isEmpty())
return;
currentFile = fileName;
} else {
fileName = currentFile;
}
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString());
return;
}
setWindowTitle(fileName);
QTextStream out(&file);
QString text = ui->textEdit->toPlainText();
out << text;
file.close();
}QFile 对象myfile 与全局变量current_file 相关联,该变量存储了我们正在编辑的文件。如果无法打开myfile ,则会显示错误信息并终止该方法。我们创建一个QTextStream outstream 。编辑器缓冲区的内容将转换为纯文本,然后写入outstream 。
以其他名称保存文件
void Notepad::saveAs()
{
QString fileName = QFileDialog::getSaveFileName(this, "Save as");
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString());
return;
}
currentFile = fileName;
setWindowTitle(fileName);
QTextStream out(&file);
QString text = ui->textEdit->toPlainText();
out << text;
file.close();
}此操作与“保存文件”的步骤相同,唯一的区别在于这里需要为要创建的文件输入一个新文件名。
打印文件
若要使用打印功能,需在项目文件中添加PrintSupport :
find_package(Qt6
REQUIRED COMPONENTS Core Gui Widgets
OPTIONAL_COMPONENTS PrintSupport
)在notepad.cpp 中,我们声明了一个名为printDev 的QPrinter对象:
void Notepad::print()
{
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
QPrinter printDev;
#if QT_CONFIG(printdialog)
QPrintDialog dialog(&printDev, this);
if (dialog.exec() == QDialog::Rejected)
return;
#endif // QT_CONFIG(printdialog)
ui->textEdit->print(&printDev);
#endif // QT_CONFIG(printer)
}我们弹出打印机对话框,并将选定的打印机存储在对象printDev 中。如果点击了Cancel 却未选择打印机,该方法将直接返回。实际的打印命令通过ui->textEdit->print 发出,并将我们的 QPrinter 对象作为参数传入。
选择字体
void Notepad::selectFont()
{
bool fontSelected;
QFont font = QFontDialog::getFont(&fontSelected, this);
if (fontSelected)
ui->textEdit->setFont(font);
}我们通过QFontDialog 声明一个布尔变量,用于指示是否已选择字体。如果已选择,则通过ui->textEdit->setFont(myfont) 设置字体。
复制、剪切、粘贴、撤销和重做
若选中部分文本并希望将其复制到剪贴板,请调用ui->textEdit 的相应方法。剪切、粘贴、撤销和重做操作亦同。
下表列出了应使用的方法名称。
| 任务 | 调用的方法 |
|---|---|
| 复制 | ui->textEdit->copy() |
| 剪切 | ui->textEdit->cut() |
| 粘贴 | ui->textEdit->paste() |
| 撤销 | ui->textEdit->undo() |
| 重做 | ui->textEdit->redo() |
了解更多
| 关于 | 此处 |
|---|---|
| 文件和 I/O 设备 | QFile、QIODevice |
| tr() 与国际化 | Qt Linguist 手册、编写可供翻译的源代码、使用 Qt 实现国际化 |
从命令行构建和运行
若要从命令行构建示例应用程序,请为其创建一个构建目录。切换到该构建目录,并运行 `qt-cmake ` 以配置项目以便构建。如果项目配置成功,生成的文件将使您能够构建该项目。
md <build_directory>
cd <build_directory>
<qt_installation_directory>\bin\qt-cmake -GNinja <source_directory>
<generator>这些命令会在构建目录中生成一个可执行文件。CMake 工具会读取项目文件,并生成有关如何构建应用程序的指令。随后,生成器会根据这些指令生成可执行二进制文件。
例如,要在 Windows 上构建“记事本”示例,且使用 Ninja 作为生成器时,请输入以下命令:
md notepad-build
cd notepad-build
C:\Qt\6.12.0\msvc2022_64\bin\qt-cmake -GNinja C:\Examples\notepad
ninja如果您不使用 Ninja 作为生成器,请使用与生成器无关的 CMake 命令来构建应用程序,而不是使用ninja :
cmake --build© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.