Qt5编写一个记事本(多文档编辑器)

目录

一、准备工作

1.1创建工程

1.2创建资源文件(myimages.qrc)

1.3创建界面文件(mainwindow.ui)

二、实现功能

1.1新建c++class类

1.2 MainWindow类代码如下

1.3主函数

三、程序发布

          总结


使用qt5编写一个具有多文档编辑器功能(可以编写多个文档,有保存,打开,编辑,撤销,剪切,复制,粘贴等功能)的项目。

ps:本项目运用Qt5.6和基于《Qt及Qt Quick开发实战精解》第一章开发。(原书是运用Qt4.7和Qt Creator 2.1.0开发)。

下面是程序运行效果:

附上程序和源码地址:

链接:https://pan.baidu.com/s/1sNCOUqrQnX0Com6zxZhfKA 
提取码:idug

一、准备工作

准备需要的图标文件(最好是图标具有实际意义),保存为Qt资源文件,后面好调用,使用ui设计出窗口界面。

   1.1创建工程

        打开Qt Creator,创建新项目,新建Application ->Qt Widgets Applictation 项目名字改为myMid

设置基类为QMainWindow。创建成功如下:

1.2创建资源文件(myimages.qrc)

      鼠标右击工程名称,添加新文件,选择Qt Resource File,文件名改为myimages.qrc,点开myimages.qrc,在下方添加菜单栏中添加一个前缀名/images。然后在工程目录新建一个文件夹命名为images,在里面放入图标文件(可以是任何格式如.**ico **.png **.jpg,但文件大小不易过大)。在回到myimages.qrc,通过添加菜单中的添加文件,将刚刚的图标文件添加进images。添加好后如下图

1.3创建界面文件(mainwindow.ui)

 通过这些操作UI界面就设计好了。将四个运行菜单项名字改为menuF,menuE,menuW,menuH。

可以运行看看效果;

二、实现功能

让每个模块实现自己的功能,如打开文件,复制粘贴,撤销撤回等功能。

1.1新建c++class类

在在项目中右键选择新建c++class类基类选择QDialog类名为MdiChild。

MdiChild.h:

#ifndef MDICHILD_H
#define MDICHILD_H

#include <QTextEdit>

class MdiChild : public QTextEdit
{
    Q_OBJECT
public:
    explicit MdiChild(QWidget *parent = 0);
    void newFile(); // 新建操作
    bool loadFile(const QString &fileName); // 加载文件
    bool save();  // 保存操作
    bool saveAs();  // 另存为操作
    bool saveFile(const QString &fileName); // 保存文件
    QString userFriendlyCurrentFile(); // 提取文件名
    QString currentFile(){return curFile;} // 返回当前文件路径
protected:
    void closeEvent(QCloseEvent *event); // 关闭事件
    void contextMenuEvent(QContextMenuEvent *e); // 右键菜单事件
private slots:
    void documentWasModified();  // 文档被更改时,显示更改状态标志
private:
    bool maybeSave();  // 是否需要保存
    void setCurrentFile(const QString &fileName); // 设置当前文件
    QString curFile;  // 保存当前文件路径
    bool isUntitled;  // 作为当前文件是否被保存到硬盘上的标志
};

#endif // MDICHILD_H

MdiChild.cpp

#include "mdichild.h"
#include <QFile>
#include <QTextStream>
#include <QMessageBox>
#include <QFileInfo>
#include <QApplication>
#include <QFileDialog>
#include <QCloseEvent>
#include <QPushButton>
#include <QMenu>
#include <qtextcodec.h>
MdiChild::MdiChild(QWidget *parent) :
    QTextEdit(parent)
{
    setAttribute(Qt::WA_DeleteOnClose); // 这样可以在子窗口关闭时销毁这个类的对象
    isUntitled = true;  // 初始isUntitled为true
}

QTextCodec *codec1 = QTextCodec::codecForName("GB2312");//显示为中文字符

void MdiChild::newFile() // 新建文件操作
{
    static int sequenceNumber = 1;
    // 设置窗口编号,因为编号一直被保存,所以需要使用静态变量

    isUntitled = true; // 新建的文档没有被保存过

    // 将当前文件命名为未命名文档加编号,编号先使用再加1
    curFile = codec1->toUnicode("未命名文档%1.txt").arg(sequenceNumber++);


    // 设置窗口标题,使用[*]可以在文档被更改后在文件名称后显示”*“号
    setWindowTitle(curFile + "[*]" + codec1->toUnicode(" - 筱忆多文档编辑器"));

    // 当文档被更改时发射contentsChanged()信号,
    // 执行我们的documentWasModified()槽函数
    connect(document(), SIGNAL(contentsChanged()),
            this, SLOT(documentWasModified()));

}

void MdiChild::documentWasModified() //文档被更改时,窗口显示更改状态标志
{
    // 根据文档的isModified()函数的返回值,判断我们编辑器内容是否被更改了
    // 如果被更改了,就要在设置了[*]号的地方显示“*”号,这里我们会在窗口标题中显示
    setWindowModified(document()->isModified());
}

bool MdiChild::loadFile(const QString &fileName) // 加载文件
{
    QFile file(fileName); // 新建QFile对象
    if (!file.open(QFile::ReadOnly | QFile::Text)) {
        QMessageBox::warning(this, codec1->toUnicode("筱忆多文档编辑器"),
                             codec1->toUnicode("无法读取文件 %1:\n%2.")
                             .arg(fileName).arg(file.errorString()));
        return false; // 只读方式打开文件,出错则提示,并返回false
    }

    QTextStream in(&file); // 新建文本流对象
    QApplication::setOverrideCursor(Qt::WaitCursor); // 设置鼠标状态为等待状态
    setPlainText(in.readAll());  // 读取文件的全部文本内容,并添加到编辑器中
    QApplication::restoreOverrideCursor(); // 恢复鼠标状态

    setCurrentFile(fileName); // 设置当前文件

    connect(document(), SIGNAL(contentsChanged()),
            this, SLOT(documentWasModified()));

    return true;
}

void MdiChild::setCurrentFile(const QString &fileName) // 设置当前文件
{
    // canonicalFilePath()可以除去路径中的符号链接,“.”和“..”等符号
    curFile = QFileInfo(fileName).canonicalFilePath();

    isUntitled = false; // 文件已经被保存过了
    document()->setModified(false); // 文档没有被更改过
    setWindowModified(false); // 窗口不显示被更改标志

    // 设置窗口标题,userFriendlyCurrentFile()返回文件名
    setWindowTitle(userFriendlyCurrentFile() + "[*]");

}

QString MdiChild::userFriendlyCurrentFile() // 提取文件名
{
    return QFileInfo(curFile).fileName(); // 从文件路径中提取文件名
}

bool MdiChild::save() // 保存操作
{
    if (isUntitled) { // 如果文件未被保存过,则执行另存为操作
        return saveAs();
    } else {
        return saveFile(curFile); // 否则直接保存文件
    }
}

bool MdiChild::saveAs() // 另存为操作
{
    // 获取文件路径,如果为空,则返回false
    QString fileName = QFileDialog::getSaveFileName(this, codec1->toUnicode("另存为"),curFile);
    if (fileName.isEmpty())
        return false;

    return saveFile(fileName); // 否则保存文件
}

bool MdiChild::saveFile(const QString &fileName) // 保存文件
{
    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text)) {
        QMessageBox::warning(this, codec1->toUnicode("筱忆多文档编辑器"),
                             codec1->toUnicode("无法写入文件 %1:\n%2.")
                             .arg(fileName).arg(file.errorString()));
        return false;
    }

    QTextStream out(&file);
    QApplication::setOverrideCursor(Qt::WaitCursor);
    out << toPlainText(); // 以纯文本文件写入
    QApplication::restoreOverrideCursor();

    setCurrentFile(fileName);
    return true;
}


void MdiChild::closeEvent(QCloseEvent *event)
{
    if (maybeSave()) { // 如果maybeSave()函数返回true,则关闭窗口
        event->accept();
    } else {   // 否则忽略该事件
        event->ignore();
    }
}


bool MdiChild::maybeSave()  // 是否需要保存
{
    if (document()->isModified()) { // 如果文档被更改过
        QMessageBox box;
        box.setWindowTitle(codec1->toUnicode("筱忆多文档编辑器"));
        box.setText(codec1->toUnicode("是否保存对“%1”的更改?")
                    .arg(userFriendlyCurrentFile()));
        box.setIcon(QMessageBox::Warning);

        // 添加按钮,QMessageBox::YesRole可以表明这个按钮的行为
        QPushButton *yesBtn = box.addButton(codec1->toUnicode("是(&Y)"),QMessageBox::YesRole);

        box.addButton(codec1->toUnicode("否(&N)"),QMessageBox::NoRole);
        QPushButton *cancelBtn = box.addButton(codec1->toUnicode("取消"),
                                               QMessageBox::RejectRole);
        box.exec(); // 弹出对话框,让用户选择是否保存修改,或者取消关闭操作
        if (box.clickedButton() == yesBtn)// 如果用户选择是,则返回保存操作的结果
            return save();
        else if (box.clickedButton() == cancelBtn) // 如果选择取消,则返回false
            return false;
    }
    return true; // 如果文档没有更改过,则直接返回true
}

void MdiChild::contextMenuEvent(QContextMenuEvent *e) // 右键菜单事件
{
    QMenu *menu = new QMenu; // 创建菜单,并向其中添加动作
    QAction *undo = menu->addAction(codec1->toUnicode("撤销(&U)"),this,
                                    SLOT(undo()),QKeySequence::Undo);
    undo->setEnabled(document()->isUndoAvailable());
    QAction *redo = menu->addAction(codec1->toUnicode("恢复(&R)"),this,
                                    SLOT(redo()),QKeySequence::Redo);
    redo->setEnabled(document()->isRedoAvailable());
    menu->addSeparator();
    QAction *cut = menu->addAction(codec1->toUnicode("剪切(&T)"),this,
                                   SLOT(cut()),QKeySequence::Cut);
    cut->setEnabled(textCursor().hasSelection());
    QAction *copy = menu->addAction(codec1->toUnicode("复制(&C)"),this,
                                    SLOT(copy()),QKeySequence::Copy);
    copy->setEnabled(textCursor().hasSelection());
    menu->addAction(codec1->toUnicode("粘贴(&P)"),this,SLOT(paste()),QKeySequence::Paste);
    QAction *clear = menu->addAction(codec1->toUnicode("清空"),this,SLOT(clear()));
    clear->setEnabled(!document()->isEmpty());
    menu->addSeparator();
    QAction *select = menu->addAction(codec1->toUnicode("全选"),this,
                                SLOT(selectAll()),QKeySequence::SelectAll);
    select->setEnabled(!document()->isEmpty());
    menu->exec(e->globalPos()); // 获取鼠标的位置,然后在这个位置显示菜单
    delete menu; // 最后销毁这个菜单
}



1.2 MainWindow类代码如下

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
class MdiChild;
class QMdiSubWindow;
class QSignalMapper;
namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_actionNew_triggered(); // 新建文件菜单
    void updateMenus(); // 更新菜单
    MdiChild *createMdiChild(); // 创建子窗口
    void setActiveSubWindow(QWidget *window); // 设置活动子窗口

    void on_actionOpen_triggered(); // 打开文件菜单

    void updateWindowMenu(); // 更新窗口菜单

    void on_actionSave_triggered();

    void on_actionSaveAs_triggered();

    void on_actionUndo_triggered();

    void on_actionRedo_triggered();

    void on_actionCut_triggered();

    void on_actionCopy_triggered();

    void on_actionPaste_triggered();

    void on_actionClose_triggered();

    void on_actionCloseAll_triggered();

    void on_actionTile_triggered();

    void on_actionCascade_triggered();

    void on_actionNext_triggered();

    void on_actionPrevious_triggered();

    void on_actionAbout_triggered();

    void on_actionAboutQt_triggered();

    void on_actionExit_triggered();

    void showTextRowAndCol(); // 显示文本的行号和列号

private:
    Ui::MainWindow *ui;
    QAction *actionSeparator; // 分隔符
    MdiChild *activeMdiChild(); // 活动窗口
    QMdiSubWindow *findMdiChild(const QString &fileName);// 查找子窗口

    QSignalMapper *windowMapper; // 信号映射器

    void readSettings();  // 读取窗口设置
    void writeSettings(); // 写入窗口设置


    void initWindow(); // 初始化窗口

protected:
    void closeEvent(QCloseEvent *event);  // 关闭事件
};

#endif // MAINWINDOW_H

MainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mdichild.h"
#include <QMdiSubWindow>
#include <QFileDialog>
#include <QSignalMapper>
#include <QMessageBox>
#include <QSettings>
#include <QCloseEvent>
#include <QLabel>
#include <qtextcodec.h>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    actionSeparator = new QAction(this); // 创建间隔器动作
    actionSeparator->setSeparator(true); // 在其中设置间隔器
    updateMenus();   // 更新菜单
    connect(ui->mdiArea,SIGNAL(subWindowActivated(QMdiSubWindow*)),this,
            SLOT(updateMenus()));  // 当有活动窗口时更新菜单

    windowMapper = new QSignalMapper(this); // 创建信号映射器
    connect(windowMapper, SIGNAL(mapped(QWidget*)), // 映射器重新发射信号
            this, SLOT(setActiveSubWindow(QWidget*))); // 设置活动窗口

    // 更新窗口菜单,并且设置当窗口菜单将要显示的时候更新窗口菜单
    updateWindowMenu();
    connect(ui->menuW,SIGNAL(aboutToShow()),this,SLOT(updateWindowMenu()));


    readSettings(); // 初始窗口时读取窗口设置信息
    initWindow(); // 初始化窗口
}



QTextCodec *codec = QTextCodec::codecForName("GB2312");
MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actionNew_triggered()  // 新建文件菜单
{
    MdiChild *child = createMdiChild(); // 创建MdiChild
    child->newFile(); // 新建文件
    child->show(); // 显示子窗口
}

MdiChild * MainWindow::createMdiChild() // 创建子窗口部件
{
    MdiChild *child = new MdiChild; // 创建MdiChild部件
    ui->mdiArea->addSubWindow(child); // 向多文档区域添加子窗口,child为中心部件

    // 根据QTextEdit类的是否可以复制信号设置剪切复制动作是否可用
    connect(child,SIGNAL(copyAvailable(bool)),ui->actionCut,
            SLOT(setEnabled(bool)));
    connect(child,SIGNAL(copyAvailable(bool)),ui->actionCopy,
            SLOT(setEnabled(bool)));

    // 根据QTextDocument类的是否可以撤销恢复信号设置撤销恢复动作是否可用
    connect(child->document(),SIGNAL(undoAvailable(bool)),
            ui->actionUndo,SLOT(setEnabled(bool)));
    connect(child->document(),SIGNAL(redoAvailable(bool)),
            ui->actionRedo,SLOT(setEnabled(bool)));

    // 每当编辑器中的光标位置改变,就重新显示行号和列号
    connect(child,SIGNAL(cursorPositionChanged()),this,SLOT(showTextRowAndCol()));

    return child;
}

void MainWindow::updateMenus() // 更新菜单
{
    bool hasMdiChild = (activeMdiChild() != 0); // 是否有活动窗口
    ui->actionSave->setEnabled(hasMdiChild);   // 设置各个动作是否可用
    ui->actionSaveAs->setEnabled(hasMdiChild);
    ui->actionPaste->setEnabled(hasMdiChild);
    ui->actionClose->setEnabled(hasMdiChild);
    ui->actionCloseAll->setEnabled(hasMdiChild);
    ui->actionTile->setEnabled(hasMdiChild);
    ui->actionCascade->setEnabled(hasMdiChild);
    ui->actionNext->setEnabled(hasMdiChild);
    ui->actionPrevious->setEnabled(hasMdiChild);
    actionSeparator->setVisible(hasMdiChild); // 设置间隔器是否显示

    bool hasSelection = (activeMdiChild()
                         && activeMdiChild()->textCursor().hasSelection());

    // 有活动窗口且有被选择的文本,剪切复制才可用
    ui->actionCut->setEnabled(hasSelection);
    ui->actionCopy->setEnabled(hasSelection);

    ui->actionUndo->setEnabled(activeMdiChild() // 有活动窗口且文档有撤销操作
                          && activeMdiChild()->document()->isUndoAvailable());
    ui->actionRedo->setEnabled(activeMdiChild() // 有活动窗口且文档有恢复操作
                          && activeMdiChild()->document()->isRedoAvailable());
}

MdiChild * MainWindow::activeMdiChild() // 活动窗口
{
    // 如果有活动窗口,则将其内的中心部件转换为MdiChild类型
    if (QMdiSubWindow *activeSubWindow = ui->mdiArea->activeSubWindow())
        return qobject_cast<MdiChild *>(activeSubWindow->widget());
    return 0; // 没有活动窗口,直接返回0
}

void MainWindow::on_actionOpen_triggered() // 打开文件菜单
{
    QString fileName = QFileDialog::getOpenFileName(this); // 获取文件路径
    if (!fileName.isEmpty()) { // 如果路径不为空,则查看该文件是否已经打开
        QMdiSubWindow *existing = findMdiChild(fileName);
        if (existing) { // 如果已经存在,则将对应的子窗口设置为活动窗口
            ui->mdiArea->setActiveSubWindow(existing);
            return;
        }

        MdiChild *child = createMdiChild(); // 如果没有打开,则新建子窗口
        if (child->loadFile(fileName)) {
            ui->statusBar->showMessage(codec->toUnicode("打开文件成功"), 2000);
            child->show();
        } else {
            child->close();
        }
    }
}

QMdiSubWindow * MainWindow::findMdiChild(const QString &fileName) // 查找子窗口
{

    QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();

    // 利用foreach语句遍历子窗口列表,如果其文件路径和要查找的路径相同,则返回该窗口
    foreach (QMdiSubWindow *window, ui->mdiArea->subWindowList()) {
        MdiChild *mdiChild = qobject_cast<MdiChild *>(window->widget());
        if (mdiChild->currentFile() == canonicalFilePath)
            return window;
    }
    return 0;
}

void MainWindow::setActiveSubWindow(QWidget *window) // 设置活动子窗口
{
    if (!window) // 如果传递了窗口部件,则将其设置为活动窗口
        return;
    ui->mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(window));
}

void MainWindow::updateWindowMenu() // 更新窗口菜单
{
    ui->menuW->clear(); // 先清空菜单,然后再添加各个菜单动作
    ui->menuW->addAction(ui->actionClose);
    ui->menuW->addAction(ui->actionCloseAll);
    ui->menuW->addSeparator();
    ui->menuW->addAction(ui->actionTile);
    ui->menuW->addAction(ui->actionCascade);
    ui->menuW->addSeparator();
    ui->menuW->addAction(ui->actionNext);
    ui->menuW->addAction(ui->actionPrevious);
    ui->menuW->addAction(actionSeparator);

    QList<QMdiSubWindow *> windows = ui->mdiArea->subWindowList();
    actionSeparator->setVisible(!windows.isEmpty());
    // 如果有活动窗口,则显示间隔器
    for (int i = 0; i < windows.size(); ++i) { // 遍历各个子窗口
        MdiChild *child = qobject_cast<MdiChild *>(windows.at(i)->widget());

        QString text;
        if (i < 9) { // 如果窗口数小于9,则设置编号为快捷键
            text = tr("&%1 %2").arg(i + 1)
                               .arg(child->userFriendlyCurrentFile());
        } else {
            text = tr("%1 %2").arg(i + 1)
                              .arg(child->userFriendlyCurrentFile());
        }
        QAction *action  = ui->menuW->addAction(text); // 添加动作到菜单
        action->setCheckable(true); // 设置动作可以选择

        // 设置当前活动窗口动作为选中状态
        action ->setChecked(child == activeMdiChild());

        // 关联动作的触发信号到信号映射器的map()槽函数上,这个函数会发射mapped()信号
        connect(action, SIGNAL(triggered()), windowMapper, SLOT(map()));

        // 将动作与相应的窗口部件进行映射,在发射mapped()信号时就会以这个窗口部件为参数
        windowMapper->setMapping(action, windows.at(i));

    }
}

/********************1.3.3小节对下面这些代码进行了部分省略****************************************/

void MainWindow::on_actionSave_triggered() // 保存菜单
{
    if(activeMdiChild() && activeMdiChild()->save())
        ui->statusBar->showMessage(codec->toUnicode("文件保存成功"),2000);
}

void MainWindow::on_actionSaveAs_triggered()  // 另存为菜单
{
    if(activeMdiChild() && activeMdiChild()->saveAs())
        ui->statusBar->showMessage(codec->toUnicode("文件保存成功"),2000);
}

void MainWindow::on_actionUndo_triggered() // 撤销菜单
{
    if(activeMdiChild()) activeMdiChild()->undo();
}

void MainWindow::on_actionRedo_triggered() // 恢复菜单
{
    if(activeMdiChild()) activeMdiChild()->redo();
}

void MainWindow::on_actionCut_triggered() // 剪切菜单
{
    if(activeMdiChild()) activeMdiChild()->cut();
}

void MainWindow::on_actionCopy_triggered() // 复制菜单
{
    if(activeMdiChild()) activeMdiChild()->copy();
}

void MainWindow::on_actionPaste_triggered() // 粘贴菜单
{
    if(activeMdiChild()) activeMdiChild()->paste();
}

void MainWindow::on_actionClose_triggered() // 关闭菜单
{
    ui->mdiArea->closeActiveSubWindow();
}

void MainWindow::on_actionCloseAll_triggered() // 关闭所有窗口菜单
{
    ui->mdiArea->closeAllSubWindows();
}

void MainWindow::on_actionTile_triggered() // 平铺菜单
{
    ui->mdiArea->tileSubWindows();
}

void MainWindow::on_actionCascade_triggered() // 层叠菜单
{
    ui->mdiArea->cascadeSubWindows();
}

void MainWindow::on_actionNext_triggered() // 下一个菜单
{
    ui->mdiArea->activateNextSubWindow();
}

void MainWindow::on_actionPrevious_triggered() // 前一个菜单
{
    ui->mdiArea->activatePreviousSubWindow();
}

void MainWindow::on_actionAbout_triggered() // 关于菜单
{
    QMessageBox::about(this,codec->toUnicode("关于本软件"),codec->toUnicode("欢迎访问我的csdn主页:https://blog.csdn.net/qq_46424406?spm=1003.2020.3001.5343"));
}

void MainWindow::on_actionAboutQt_triggered() // 关于Qt菜单
{
    qApp->aboutQt(); // 这里的qApp是QApplication对象的全局指针,
                     // 这行代码相当于QApplication::aboutQt();
}



void MainWindow::on_actionExit_triggered() // 退出菜单
{
    qApp->closeAllWindows(); // 等价于QApplication::closeAllWindows();
}

void MainWindow::closeEvent(QCloseEvent *event) // 关闭事件
{
    ui->mdiArea->closeAllSubWindows(); // 先执行多文档区域的关闭操作
    if (ui->mdiArea->currentSubWindow()) {
        event->ignore(); // 如果还有窗口没有关闭,则忽略该事件
    } else {
        writeSettings(); // 在关闭前写入窗口设置
        event->accept();
    }
}

void MainWindow::writeSettings() // 写入窗口设置
{
    QSettings settings("yafeilinux", "myMdi");
    settings.setValue("pos", pos());   // 写入位置信息
    settings.setValue("size", size()); // 写入大小信息
}

void MainWindow::readSettings() // 读取窗口设置
{
    QSettings settings("yafeilinux", "myMdi");
    QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
    QSize size = settings.value("size", QSize(400, 400)).toSize();
    move(pos);
    resize(size);
}

void MainWindow::showTextRowAndCol() // 显示文本的行号和列号
{
    // 如果有活动窗口,则显示其中光标所在的位置
    if(activeMdiChild()){

        // 因为获取的行号和列号都是从0开始的,所以我们这里进行了加1
        int rowNum = activeMdiChild()->textCursor().blockNumber()+1;
        int colNum = activeMdiChild()->textCursor().columnNumber()+1;

        ui->statusBar->showMessage(tr("%1行 %2列")
                                   .arg(rowNum).arg(colNum),2000);
    }
}

void MainWindow::initWindow() // 初始化窗口
{
    setWindowTitle(codec->toUnicode("筱忆多文档编辑器"));

    // 我们在工具栏上单击鼠标右键时,可以关闭工具栏
    ui->mainToolBar->setWindowTitle(codec->toUnicode("工具栏"));

    // 当多文档区域的内容超出可视区域后,出现滚动条
    ui->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    ui->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);

    ui->statusBar->showMessage(codec->toUnicode("欢迎使用筱忆多文档编辑器"));

    QLabel *label = new QLabel(this);
    label->setFrameStyle(QFrame::Box | QFrame::Sunken);
    label->setText(
          tr("<a href=\"https://blog.csdn.net/qq_46424406?spm=1003.2020.3001.5343\">xiaoyi.com</a>"));
    label->setTextFormat(Qt::RichText); // 标签文本为富文本
    label->setOpenExternalLinks(true);  // 可以打开外部链接
    ui->statusBar->addPermanentWidget(label);

    ui->actionNew->setStatusTip(codec->toUnicode("创建一个文件"));




    ui->actionOpen->setStatusTip(codec->toUnicode("打开一个已经存在的文件"));
    ui->actionSave->setStatusTip(codec->toUnicode("保存文档到硬盘"));
    ui->actionSaveAs->setStatusTip(codec->toUnicode("以新的名称保存文档"));
    ui->actionExit->setStatusTip(codec->toUnicode("退出应用程序"));
    ui->actionUndo->setStatusTip(codec->toUnicode("撤销先前的操作"));
    ui->actionRedo->setStatusTip(codec->toUnicode("恢复先前的操作"));
    ui->actionCut->setStatusTip(codec->toUnicode("剪切选中的内容到剪贴板"));
    ui->actionCopy->setStatusTip(codec->toUnicode("复制选中的内容到剪贴板"));
    ui->actionPaste->setStatusTip(codec->toUnicode("粘贴剪贴板的内容到当前位置"));
    ui->actionClose->setStatusTip(codec->toUnicode("关闭活动窗口"));
    ui->actionCloseAll->setStatusTip(codec->toUnicode("关闭所有窗口"));
    ui->actionTile->setStatusTip(codec->toUnicode("平铺所有窗口"));
    ui->actionCascade->setStatusTip(codec->toUnicode("层叠所有窗口"));
    ui->actionNext->setStatusTip(codec->toUnicode("将焦点移动到下一个窗口"));
    ui->actionPrevious->setStatusTip(codec->toUnicode("将焦点移动到前一个窗口"));
    ui->actionAbout->setStatusTip(codec->toUnicode("显示本软件的介绍"));



}






1.3主函数

main.cpp

#include <QtWidgets/QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

   MainWindow w;
    w.show();

    return a.exec();
}

以上就是全部代码块。

运行成功就已经实现了一个记事本基本功能了;

三、程序发布

发布QT程序需要对程序设置图标也就是我那个鲨鱼图标,只需要去设计一个.ico文件,文件名称设置为my.ico(方便代码调用),然后在.pro文件中添加

RC_ICONS = my.ico

然后编译,编译时使用Release编译,编译成功后可以在工程目录找到一个release文件,在此文件里面有一个.exe文件,这里我就是myMdi.exe

但是这个文件直接发给别人是不能直接运行的(原因是没有运行环境)所以说我们需要去进行打包发布。

可以通过Qt命令窗口来添加,在Qt命令输入

windeployqt 路径

 我这里输入的是

windeployqt C:\Users\XiaoYi\Desktop\myapp

在原文件夹就有了添加的一些文件如下

 

现在压缩就可以发布了;

总结

这就是Qt写一个记事本的全部代码,在前文有发布文件和全部项目代码。本次代码大多数基于《Qt及Qt Quick开发实战精解》的源代码,只是使其在Qt5上实现,内容可能会有逻辑不太合理请指正。

 

 

 

 

 

  • 11
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值