多文档编辑器--(2)创建子窗口类

为了更好的在MDI Area中添加子窗口,那就子类化子窗口,它继承自 QTexiEdit 类。

1. 添加新文件

选择新建一个 类
在这里插入图片描述
类名为: MdiChild,继承自 QTextEdit。
在这里插入图片描述

2. 子窗口类的头文件
#ifndef MDICHILD_H
#define MDICHILD_H
#include <QWidget>									// 头文件包含
#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;}          // 返回当前文件路径(返回文件的pathname)

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

private:
    void documentWasModified();                     // 文件被更改时,显示更改状态标志

private:
    bool maybeSave();                           // 判断是否需要保存
    void setCurrentFile(const QString &filename); // 设置当前文件
    QString curFile;                            // 保存当前文件路径 pathname
    bool isUntitled;                            // 作为是否保存到硬盘上的标志
};
#endif // MDICHILD_H
3. 子窗口的源文件

对于子窗口,需要有一些基本功能,这些功能由类中的函数来实现。

主要包括的功能有:
(1)新建文件,对应成员函数 newFile
这里的新建文件不是主窗口中点击"new"对应的槽函数,而是在已经有了子窗口之后的新建文件。
点击"New"会创建新的子窗口,创建新的子窗口之后,子窗口会执行"新建文件",主要作用是子窗口的标题栏的文件名,还有就是文件被改动之后显示 " [*] "。

void MdiChild::newFile()
{
    static int sequenceNumber = 1;
    isUntitled = true;
    curFile = tr("新建文档 %1.txt").arg(sequenceNumber++);
    setWindowTitle(curFile + "[*]" + tr("-多文档编辑器"));

    connect(document(), &QTextDocument::contentsChanged, this, &MdiChild::documentWasModified);
}

**(2)加载文件,对应的成员函数 loadFile **
功能就是:把文件的内容读到子窗口中。具体就是给子窗口一个文件名,子窗口就根据文件名把文件的内容全部读到子窗口中。

bool MdiChild::loadFile(const QString &fileName)
{
    QFile file(fileName);
    if (!file.open(QFile::ReadOnly | QFile::Text)){
        QMessageBox::warning(this, tr("多文档编辑器"), tr("无法读取文件 %1:\n%2.").arg(fileName).arg(file.errorString()));
        return false;
    }
    QTextStream in(&file);                              // 新建文本流对象
    QApplication::setOverrideCursor(Qt::WaitCursor);    // 设置鼠标状态为等待状态
    setPlainText(in.readAll());                         // 读取文件的全部内容
    QApplication::restoreOverrideCursor();              // 恢复鼠标状态
    setCurrentFile(fileName);                           // 设置当前文件

    connect(document(), &QTextDocument::contentsChanged, this, &MdiChild::documentWasModified);

    return true;
}

(3)保存文件操作
保存其实分两种,一种是另存为(不知道要存的的路径,需要先询问),另一种是保存(已经知道路径,直接保存到已知路径中)。

有一个变量 isUntitled 来作为是否保存到硬盘上的标志。例如,在新建窗口时,isUntitled 就为true,表示没有保存到硬盘上,而打开文件(也就是加载文件)时,isUntitled为false。因为是从硬盘加载来的。

所以关于保存操作,要先判断 isUntitled, 然后执行saveFile 或 saveAs。

bool MdiChild::save()
{
    if (isUntitled){
        return saveAs();
    }
    else{
        return saveFile(curFile);
    }
}

bool MdiChild::saveAs()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("另存为"), curFile);
    if (fileName.isEmpty()){
        return false;
    }
    else{
        return saveFile(fileName);
    }
}

bool MdiChild::saveFile(const QString &fileName)
{
    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text)){
        QMessageBox::warning(this, tr("多文档编辑器"), tr("无法写入文件%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;
}

saveAs——另存为,就是先获取要保存的路径,然后执行保存文件。
保存文件就是把子窗口中的内容写到硬盘中的一个文件中去。
(4)获取文件名
curFile是私有成员变量,表示子窗口的文件的路径名(pathname),userFriendlyCurrentFile是用户友好的意思,是只获取它的文件名name。去掉path。

QString MdiChild::userFriendlyCurrentFile()
{
    return QFileInfo(curFile).fileName();
}

(5)获取pathname
直接返回私有成员变量curFile的值。

QString currentFile(){return curFile;}

(6)关闭事件
用户点击了关闭,要进行一些判断啊,(用户修改了文件并没有保存的情况)

void MdiChild::closeEvent(QCloseEvent *event)
{
    if (maybeSave())
        event->accept();
    else
        event->ignore();
}

只有maybeSave()1 时,才可以关闭子窗口。接下来看 maybeSave() 是什么样的。

(7)maybesave 关闭之前的判断

bool MdiChild::maybeSave()
{
    if (document()->isModified()){
        QMessageBox box;
        box.setWindowTitle(tr("多文档编辑器"));
        box.setText(tr("是否保存对“%1”的修改?").arg(userFriendlyCurrentFile()));
        box.setIcon(QMessageBox::Warning);
        QPushButton* yesBtn = box.addButton(tr("是(&Y)"), QMessageBox::YesRole);
        box.addButton(tr("否(&N)"), QMessageBox::NoRole);
        QPushButton* cancleBtn = box.addButton(tr("取消"), QMessageBox::RejectRole);
        box.exec();

        if (box.clickedButton() == yesBtn)
            return save();
        else if (box.clickedButton() == cancleBtn)
            return false;
    }
    return true;
}

从函数可以看出,当用户修改了内容且没保存时,回弹出窗口询问是否保存,当正确保存(点击是) 或者 决定不保存(点击否),都会返回 true。当用户点击取消时,返回false。
结合关闭事件来看,当返回true时会关闭。反之则不关闭子窗口。

(8)设置当前文件
作用有三:
一、更新成员变量curFile.
二、更新isUntitled,作为已经保存在硬盘上的标志。
三、子窗口标题不显示 [*]。

void MdiChild::setCurrentFile(const QString &filename)
{
    curFile = QFileInfo(filename).canonicalFilePath();

    isUntitled = false;
    document()->setModified(false);
    setWindowTitle(userFriendlyCurrentFile() + "[*]");

}

(9)最后一个函数 文件内容被更改后

void MdiChild::documentWasModified()
{
    setWindowModified(document()->isModified());
}

这个函数的目的是,显示 “[*]”,这是调用Qt 自带的函数。

最后

至此,子窗口的类写完了,接下来就是把主窗口中的动作(action)和子窗口中的函数相关联起来。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值