开始第一个Qt Widgets

以下通过编写一个简单的记事本程序,来学习如何使用Qt Widgets。
最终效果


最终效果

创建项目

在菜单栏中选择 文件 > 新建文件或项目,打开引导窗口 New File or Project

创建项目

New File or Project 窗口中选择 Application > Qt Widgets Application 后,点击 Choose... 按钮进入下一步,填写项目名称和项目路径

项目名称和路径

点击 下一步 后,选择构建工具,此处我们选择 qmake

构建工具

点击 下一步 后,生成项目时的类文件信息,此处我们将 Class name 修改为 Notepad,Base class 这一项选择继承哪一个基类,可选择 QMainWindowQWidgetQDialog

  • QMainWindow - 提供一个有菜单条、锚接窗口(例如工具条)和一个状态条的主应用程序窗口,是最常见的窗口形式,可以作为GUI程序的主窗口。
  • QWidget - 是所有用户界面对象的基类。所有窗口或者控件都直接或间接继承自QWidget类。
  • QDialog - 是对话框窗口的基类。主要用于短期任务以及和用户进行简要通讯的顶级窗口。


    类信息

点击 下一步 后,选择构建套件,在这里我已提前安装了Qt 5.13.1,选中即可

kits

最后 下一步 > 完成,项目便创建完成。

项目结构

Qt Widgets Application 向导会为我们创建好初始的项目文件:

  • notepad.pro - 工程文件,用来告诉qmake如何创建Makefile
  • main.cpp - 应用程序主源文件,main函数便写在该文件中
  • notepad.h - Notepad类的头文件
  • notepad.cpp - Notepad类的源文件
  • notepad.ui - UI窗体描述文件,该文件是一个xml文件

点击运行按钮,启动一下


第一次运行

设计界面

创建完项目后,Qt Creator 为我们生成了一个notepad.ui文件,该文件为UI窗体描述文件。
构建应用时,Qt Creator会启动uic读取ui文件并创建出一个对应的头文件,本项目中的头文件是ui_notepad.h

在开始设计界面前,先准备好图片资源。

首先,我们需要添加图片资源,在当前项目目录/data/study/notepad下创建目录images并将需要用到的图片放置在其中。然后切换至编辑模式,在项目名上点击右键选择 Add New...

新建资源文件

在新建文件对话框中选择 Qt > Qt Resource File 点击 Choose...,进入新建资源文件向导

资源文件位置

填写资源文件的名称res,并指定路径为当前项目路径/data/study/notepad后,点击下一步 > 完成
完成资源文件的创建后,在左侧项目浏览器中能看到一个名为res.qrc的文件,现在我们打开该文件,将图片添加进去

图片资源

下面,双击 notepad.ui 进入设计模式。

设计模式界面

先添加一个文本框,在左侧选择 Input Widgets > Text Edit 后拖拽至主窗体中

添加文本框

选中主窗体,点击工具栏中的 垂直布局 或使用快捷键 Ctrl + L

工具栏

文本框垂直布局

双击 在这里输入 ,分别输入 &File&Edit,创建两个菜单 File 和 Edit。& 符号紧跟着的字母为快捷键,故此处 File 菜单快捷是 F,Edit 菜单快捷键是 E。

菜单

为菜单 File 添加子菜单 New、Open、Save、SaveAs、Exit。
为菜单 Edit 添加子菜单 Undo、Redo、Font、Copy、Cut、Paste。

观察设计器底部 Action Editor,这些是菜单的动作

Action Editor

双击每个动作,为它们添加图标,由于我们已经将图片资源加载进来了,现在可以在图标一项中使用 选择资源...

编辑动作

选择资源

接下来,我们要为记事本添加工具栏。
在菜单与文本框之间的空白处右键,并选择 添加工具栏,下图中红色区域便是添加的工具栏

添加工具栏

Action Editor 中的动作拖拽至工具栏中。

工具栏展示

自此,设计部分结束,下面该进行编码。

编写代码

首先,打开 notepad.h 定义记事本的操作

#ifndef NOTEPAD_H
#define NOTEPAD_H

#include 

QT_BEGIN_NAMESPACE
namespace Ui { class Notepad; }
QT_END_NAMESPACE

class Notepad : public QMainWindow
{
    Q_OBJECT    // (1)

public:
    Notepad(QWidget *parent = nullptr);
    ~Notepad();

private slots:    // (2)
    void newFile();

    void open();

    void save();

    void saveAs();

    void exit();

    void copy();

    void cut();

    void paste();

    void undo();

    void redo();

    void selectFont();

private:
    Ui::Notepad *ui;
    QString currentFile;
};
#endif // NOTEPAD_H

(1) Q_OBJECT 是Qt中定义的宏,只有直接或间接继承 QObject 类才可以使用,只有使用了该宏才具有信号槽机制。当前类 Notepad 继承自 QMainWindow,而 QMainWindow 继承自 QWidget 即间接继承了 QObject,所有我们才能定义槽函数
(2) 以下从 void newFile()void selectFont() 均为槽函数

打开 notepad.cpp 实现操作代码

#include "notepad.h"
#include "ui_notepad.h"

#include 
#include 
#include 
#include 

Notepad::Notepad(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::Notepad)
{
    ui->setupUi(this);
    this->setCentralWidget(ui->textEdit);

    connect(ui->actionNew, &QAction::triggered, this, &Notepad::newFile);    // (1)
    connect(ui->actionOpen, &QAction::triggered, this, &Notepad::open);
    connect(ui->actionSave, &QAction::triggered, this, &Notepad::save);
    connect(ui->actionSaveAs, &QAction::triggered, this, &Notepad::saveAs);
    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);
}

Notepad::~Notepad()
{
    delete ui;
}

void Notepad::newFile()
{
    currentFile.clear();
    ui->textEdit->setText(QString());
}

void Notepad::open()
{
    QString fileName = QFileDialog::getOpenFileName(this, "打开文件");
    if (fileName.isEmpty()) {
        return;
    }
    QFile file(fileName);
    currentFile = fileName;
    if (!file.open(QIODevice::ReadOnly | QFile::Text)) {
        QMessageBox::warning(this, "警告", "不能打开: " + file.errorString());
        return;
    }
    setWindowTitle(fileName);
    QTextStream in(&file);
    QString text = in.readAll();
    ui->textEdit->setText(text);
    file.close();
}

void Notepad::save()
{
    QString fileName;
    if (currentFile.isEmpty()) {
        fileName = QFileDialog::getSaveFileName(this, "保存");
        currentFile = fileName;
    } else {
        fileName = currentFile;
    }
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QFile::Text)) {
        QMessageBox::warning(this, "警告", "不能保存: " + 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, "另存为...");
    QFile file(fileName);

    if (!file.open(QFile::WriteOnly | QFile::Text)) {
        QMessageBox::warning(this, "警告", "不能保存: " + file.errorString());
        return;
    }
    currentFile = fileName;
    setWindowTitle(fileName);
    QTextStream out(&file);
    QString text = ui->textEdit->toPlainText();
    out << text;
    file.close();
}

void Notepad::exit()
{
    QCoreApplication::quit();
}

void Notepad::copy()
{
    ui->textEdit->copy();
}

void Notepad::cut()
{
    ui->textEdit->cut();
}

void Notepad::paste()
{
    ui->textEdit->paste();
}

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);
}

(1) 此处是绑定信号,将 New 菜单的 triggered 信号绑定至当前类中的 newFile 槽函数,当点击了 New 菜单后,newFile 函数便会执行。

之后,就可以运行了,当然,代码并不健壮,有兴趣的可以自己完善一下。

代码已上传至 https://github.com/abeir/qt-study

你可能感兴趣的:(开始第一个Qt Widgets)