Qt:Qt Widgets 入门编程

本教程介绍如何使用C++和QtWidgets模块创建一个简单的记事本应用程序,涵盖文本编辑、文件管理和用户界面设计等方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于记事本应用程序的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中添加小部件,请执行以下操作:

  1. 在Qt Creator编辑器模式下,双击“项目”视图中的notepad.ui文件,以在集成的Qt Designer中启动该文件。
  2. 将窗口小部件Text Edit(QTextEdit)拖放到窗体。
  3. Ctrl + A(或Cmd + A)选择小部件,然后单击“垂直放置”(或按Ctrl + L)以应用垂直布局(QVBoxLayout)。
  4. 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 CreatorQt创作者
使用Qt Creator创建其他类型的应用程序Qt Creator教程
关于这里
小部件和窗口几何窗口和对话框小部件
事件和事件处理事件系统
关于这里
使用Qt DesignerQt Designer手册
版面布局管理小部件和布局布局示例
Qt附带的小部件Qt小工具库
主窗口和主窗口类应用程序主窗口主窗口示例
QObjects和Qt对象模型(这对于理解Qt是必不可少的)对象模型
qmake和Qt构建系统qmake手册
关于这里
MDI应用QMdiAreaMDI示例
文件和I / O设备QFile时QIODevice中
tr()与国际化Qt语言手册编写源代码翻译国际化使用Qt
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值