Qt:Qt Widgets 入门编程
基于记事本应用程序的Qt小部件教程。
在本主题中,我们通过使用C ++和Qt Widgets模块实现一个简单的记事本应用程序来教授基本的Qt知识。该应用程序是一个小型文本编辑器,可让您创建,保存,打印或重新打开并再次对其进行编辑的文本文件。您还可以设置要使用的字体。
您可以在tutorials / notepad目录的qtdoc存储库中找到最终的Notepad源文件。您可以从Qt Project获取Qt 5源,也可以将它们作为Qt 5的一部分进行安装。该应用程序也位于Qt Creator的Welcome模式的示例列表中。
创建记事本项目
在向导的帮助下,可以在Qt Creator中设置新项目,该向导将指导您逐步完成项目创建过程。向导会提示您输入该特定类型的项目所需的设置,并为您创建项目。
要创建记事本项目,请选择“文件” >“新建文件”或“项目” >Qt Widgets Application > 项目名称为Notepad > qmake > 选择QMainWindow作为基类, 类名为Notepad
创建出的项目目录如下:
- notepad.pro-项目文件。
- main.cpp-应用程序的主要源文件。
- notepad.cpp-记事本小部件的记事本类的源文件。
- notepad.h-记事本小部件的记事本类的头文件。
- notepad.ui-记事本小部件的UI窗体。
.cpp,.h和.ui文件随附了必要的样板代码,以便您能够构建和运行项目。.pro文件已完成。我们将在以下各节中仔细研究文件内容。
主要源文件
该向导在main.cpp文件中生成以下代码:
#include "notepad.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication EditorApp(argc, argv);
Notepad Editor;
Editor.show();
return EditorApp.exec();
}
我们将逐行浏览代码。以下几行包括Notepad小部件和QApplication的头文件。所有Qt类都有一个以它们命名的头文件。
#include "notepad.h"
#include <QApplication>
下面的行定义了主要功能,它是所有基于C和C ++的应用程序的入口点:
int main(int argc, char *argv[])
下一行创建一个QApplication对象。该对象管理应用程序范围的资源,对于运行任何使用Qt小部件的Qt程序是必须的。这个对象管理应用程序范围内的资源,并且是运行任何使用Qt小部件的Qt程序所必需的。它使用在argv中运行的argc命令行参数构造一个应用程序对象。(对于不使用Qt小部件的GUI应用程序,可以改用QGuiApplication。)
QApplication EditorApp(argc, argv);
下一行创建记事本对象。这是向导为其创建类和UI文件的对象。用户界面包含widgets
在Qt中调用的可视元素。小部件的示例包括文本编辑,滚动条,标签和单选按钮。小部件也可以是其他小部件的容器。例如对话框或主应用程序窗口。
Notepad Editor;
下面一行在屏幕上自己的窗口中显示Notepad小部件。小部件还可以充当容器。这方面的一个例子是QMainWindow,它通常包含几种类型的小部件。默认情况下,小部件是不可见的;函数show()使小部件可见。
Editor.show();
下一行使QApplication进入其事件循环。当Qt应用程序运行时,会生成事件(比如鼠标按下和键击)并发送到应用程序的小部件。
设计UI
向导生成XML格式的用户界面定义notepad.ui。当您在Qt Creator中打开notepad.ui文件时,它会在集成的Qt Designer中自动打开。
生成应用程序时,Qt Creator将启动Qt用户界面编译器(uic),该程序读取.ui文件并创建相应的C ++头文件ui_notepad.h。
使用Qt Designer
该向导将创建一个使用QMainWindow的应用程序。它有自己的布局,您可以添加菜单栏、停靠小部件、工具栏和状态栏。中心区域可以被任何类型的小部件占用。向导将Notepad小部件放在那里。
要在Qt Designer中添加小部件,请执行以下操作:
- 在Qt Creator编辑器模式下,双击“项目”视图中的notepad.ui文件,以在集成的Qt Designer中启动该文件。
- 将窗口小部件Text Edit(QTextEdit)拖放到窗体。
- 按Ctrl + A(或Cmd + A)选择小部件,然后单击“垂直放置”(或按Ctrl + L)以应用垂直布局(QVBoxLayout)。
- 按Ctrl + S(或Cmd + S)保存更改。
用户界面现在在Qt 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
定义记事本小部件的元素:
<ui version="4.0">
UI文件与Notepad类的头文件和源文件一起使用。我们将在后面的部分中查看UI文件的其余部分。
记事本头文件
该向导为Notepad类生成了一个头文件,该头文件具有必要的#include,构造函数,析构函数和Ui对象。该文件如下所示:
#include <QMainWindow>
namespace Ui {
class Notepad;
}
class Notepad : public QMainWindow
{
Q_OBJECT
public:
explicit Notepad(QWidget *parent = nullptr);
~Notepad();
private slots:
void newDocument();
void open();
void save();
void saveAs();
void print();
void exit();
void copy();
void cut();
void paste();
void undo();
void redo();
void selectFont();
void setFontBold(bool bold);
void setFontUnderline(bool underline);
void setFontItalic(bool italic);
void about();
private:
Ui::Notepad *ui;
QString currentFile;
};
以下行包括QMainWindow,它提供了一个主应用程序窗口:
#include <QMainWindow>
以下各行在ui命名空间中声明Notepad类,该命名空间是该uic工具从生成的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();
以下各行声明一个成员变量,该成员变量是指向记事本UI类的指针。成员变量与特定的类相关联,并且可用于其所有方法。
private:
Ui::Notepad *ui;
QString currentFile;
记事本源文件
向导为Notepad类生成的源文件如下所示:
#include "notepad.h"
#include "ui_notepad.h"
Notepad::Notepad(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Notepad)
{
ui->setupUi(this);
this->setCentralWidget(ui->textEdit);
connect(ui->actionNew, &QAction::triggered, this, &Notepad::newDocument);
connect(ui->actionOpen, &QAction::triggered, this, &Notepad::open);
connect(ui->actionSave, &QAction::triggered, this, &Notepad::save);
connect(ui->actionSave_as, &QAction::triggered, this, &Notepad::saveAs);
connect(ui->actionPrint, &QAction::triggered, this, &Notepad::print);
connect(ui->actionExit, &QAction::triggered, this, &Notepad::exit);
connect(ui->actionCopy, &QAction::triggered, this, &Notepad::copy);
connect(ui->actionCut, &QAction::triggered, this, &Notepad::cut);
connect(ui->actionPaste, &QAction::triggered, this, &Notepad::paste);
connect(ui->actionUndo, &QAction::triggered, this, &Notepad::undo);
connect(ui->actionRedo, &QAction::triggered, this, &Notepad::redo);
connect(ui->actionFont, &QAction::triggered, this, &Notepad::selectFont);
connect(ui->actionBold, &QAction::triggered, this, &Notepad::setFontBold);
connect(ui->actionUnderline, &QAction::triggered, this, &Notepad::setFontUnderline);
connect(ui->actionItalic, &QAction::triggered, this, &Notepad::setFontItalic);
connect(ui->actionAbout, &QAction::triggered, this, &Notepad::about);
// Disable menu actions for unavailable features
#if !defined(QT_PRINTSUPPORT_LIB) || !QT_CONFIG(printer)
ui->actionPrint->setEnabled(false);
#endif
#if !QT_CONFIG(clipboard)
ui->actionCut->setEnabled(false);
ui->actionCopy->setEnabled(false);
ui->actionPaste->setEnabled(false);
#endif
}
Notepad::~Notepad()
{
delete ui;
}
void Notepad::newDocument()
{
currentFile.clear();
ui->textEdit->setText(QString());
}
void Notepad::open()
{
QString fileName = QFileDialog::getOpenFileName(this, "Open the file");
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();
}
void Notepad::save()
{
QString fileName;
// If we don't have a filename from before, get one.
if (currentFile.isEmpty()) {
fileName = QFileDialog::getSaveFileName(this, "Save");
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();
}
void Notepad::saveAs()
{
QString fileName = QFileDialog::getSaveFileName(this, "Save as");
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();
}
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)
}
void Notepad::exit()
{
QCoreApplication::quit();
}
void Notepad::copy()
{
#if QT_CONFIG(clipboard)
ui->textEdit->copy();
#endif
}
void Notepad::cut()
{
#if QT_CONFIG(clipboard)
ui->textEdit->cut();
#endif
}
void Notepad::paste()
{
#if QT_CONFIG(clipboard)
ui->textEdit->paste();
#endif
}
void Notepad::undo()
{
ui->textEdit->undo();
}
void Notepad::redo()
{
ui->textEdit->redo();
}
void Notepad::selectFont()
{
bool fontSelected;
QFont font = QFontDialog::getFont(&fontSelected, this);
if (fontSelected)
ui->textEdit->setFont(font);
}
以下各行包括由向导生成的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:
ui->setupUi(this);
在析构函数中,我们删除ui
:
Notepad::~Notepad()
{
delete ui;
}
为了使文本编辑字段占据整个屏幕,我们将其添加setCentralWidget
到主窗口中。
Notepad::Notepad(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Notepad)
{
ui->setupUi(this);
this->setCentralWidget(ui->textEdit);
connect(ui->actionNew, &QAction::triggered, this, &Notepad::newDocument);
connect(ui->actionOpen, &QAction::triggered, this, &Notepad::open);
connect(ui->actionSave, &QAction::triggered, this, &Notepad::save);
connect(ui->actionSave_as, &QAction::triggered, this, &Notepad::saveAs);
connect(ui->actionPrint, &QAction::triggered, this, &Notepad::print);
connect(ui->actionExit, &QAction::triggered, this, &Notepad::exit);
connect(ui->actionCopy, &QAction::triggered, this, &Notepad::copy);
connect(ui->actionCut, &QAction::triggered, this, &Notepad::cut);
connect(ui->actionPaste, &QAction::triggered, this, &Notepad::paste);
connect(ui->actionUndo, &QAction::triggered, this, &Notepad::undo);
connect(ui->actionRedo, &QAction::triggered, this, &Notepad::redo);
connect(ui->actionFont, &QAction::triggered, this, &Notepad::selectFont);
connect(ui->actionBold, &QAction::triggered, this, &Notepad::setFontBold);
connect(ui->actionUnderline, &QAction::triggered, this, &Notepad::setFontUnderline);
connect(ui->actionItalic, &QAction::triggered, this, &Notepad::setFontItalic);
connect(ui->actionAbout, &QAction::triggered, this, &Notepad::about);
// Disable menu actions for unavailable features
#if !defined(QT_PRINTSUPPORT_LIB) || !QT_CONFIG(printer)
ui->actionPrint->setEnabled(false);
#endif
#if !QT_CONFIG(clipboard)
ui->actionCut->setEnabled(false);
ui->actionCopy->setEnabled(false);
ui->actionPaste->setEnabled(false);
#endif
}
工程文件
向导notepad.pro
将为我们生成以下项目文件:
TEMPLATE = app
TARGET = notepad
QT += widgets
qtHaveModule(printsupport): QT += printsupport
requires(qtConfig(fontdialog))
SOURCES += \
main.cpp\
notepad.cpp
HEADERS += notepad.h
FORMS += notepad.ui
RESOURCES += \
notepad.qrc
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/notepad
INSTALLS += target
项目文件指定应用程序名称和qmake
用于生成项目的模板,以及项目中包含的源文件,头文件和UI文件。
您也可以使用qmake
的-project
选项来生成.pro文件。尽管在这种情况下,您必须记住将行添加QT += widgets
到生成的文件中才能链接到Qt Widgets模块。
添加用户互动
为了向编辑器添加功能,我们首先在工具栏上添加菜单项和按钮。
单击“在这里输入”,然后添加选项“新建”,“打开”,“保存”,“另存为”,“打印”和“退出”。
这将在下面的”操作编辑器“中创建5行代码。要将操作连接到插槽,请右键单击一个操作,并选择Go To slot > triggered(),并完成给定插槽的代码。
如果我们还想向工具栏添加操作,我们可以为每个 QAction分配一个图标,然后将QAction拖到工具栏上。通过在相关操作的图标属性中输入图标名称来分配图标。当QAction被拖到工具栏上时,单击图标将启动相关的插槽。
完成方法
newDocument()
:
void Notepad::newDocument()
{
currentFile.clear();
ui->textEdit->setText(QString());
}
current_file
是包含当前正在编辑的文件的全局变量。它在notepad.h的私有部分中定义:
private:
Ui::Notepad *ui;
QString currentFile;
clear()
清除文本缓冲区。
打开文件
在notepad.ui中,右键单击actionOpen
并选择Go to slot
void Notepad::open()
{
QString fileName = QFileDialog::getOpenFileName(this, "Open the file");
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对象具有选定
file_name
的参数。我们还将所选文件名存储到全局变量current_file
中,以备后用 file.open
以只读文本文件的形式打开文件。如果无法打开,则会发出警告,然后程序停止。file
作为 QTextStream 的参数,文件的内容被复制到QString文本中,用填充我们编辑器的缓冲区 ui->textEdit->setText(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");
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。
另存为
void Notepad::saveAs()
{
QString fileName = QFileDialog::getSaveFileName(this, "Save as");
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
到项目文件中:
QT += printsupport
我们声明一个名为printer的QPrinter对象。我们启动一个打印机对话框,并将选中的打印机存储在object printer中。如果单击Cancel并且没有选择打印机,则该方法将返回。实际的打印机命令是通过ui->textEdit->print和我们的QPrinter对象作为参数给出的。
Copy, Cut, Paste, Undo, and Redo
如果您选择了一些文本,并希望将其复制到剪贴板,您可以调用ui->textEdit的适当方法。剪切、粘贴、撤消和重做的计数相同。
该表显示了要使用的方法名。
任务 | 方法调用 |
---|---|
复制 | ui-> textEdit-> copy() |
剪切 | ui-> textEdit-> cut() |
粘贴 | ui-> textEdit-> paste() |
撤消 | ui-> textEdit-> undo() |
重做 | ui-> textEdit-> redo() |
构建和运行记事本
现在您有了所有必需的文件,选择Build > Build Project Notepad来构建和运行应用程序。Qt Creator使用qmake和make在项目的构建设置中指定的目录中创建可执行文件并运行它。
从命令行构建和运行
要从命令行构建应用程序,请切换到包含应用程序的.cpp文件的目录,并添加前面描述的项目文件(后缀为.pro)。然后使用以下shell命令构建应用程序:
qmake
make (or nmake on Windows)
这些命令在项目目录中创建一个可执行文件。qmake工具读取项目文件并生成一个Makefile,其中包含如何构建应用程序的说明。然后,make工具(或nmake工具)读取Makefile并生成可执行二进制文件。
Example project @ code.qt.io
扩展
关于 | 这里 |
---|---|
使用Qt Creator | Qt创作者 |
使用Qt Creator创建其他类型的应用程序 | Qt Creator教程 |
关于 | 这里 |
---|---|
小部件和窗口几何 | 窗口和对话框小部件 |
事件和事件处理 | 事件系统 |
关于 | 这里 |
---|---|
使用Qt Designer | Qt Designer手册 |
版面 | 布局管理,小部件和布局,布局示例 |
Qt附带的小部件 | Qt小工具库 |
主窗口和主窗口类 | 应用程序主窗口,主窗口示例 |
QObjects和Qt对象模型(这对于理解Qt是必不可少的) | 对象模型 |
qmake和Qt构建系统 | qmake手册 |
关于 | 这里 |
---|---|
MDI应用 | QMdiArea,MDI示例 |
文件和I / O设备 | QFile时,QIODevice中 |
tr()与国际化 | Qt语言手册,编写源代码翻译,国际化使用Qt |
还没有评论,来说两句吧...