多文档文本编辑器(Qt)

      废了一下午的时间,结合着课本终于把这个实例给弄出来了,中间错误百出,真是学习的过程贼痛苦。

      原来写过一篇java实现的多文档编辑器,那个确实是自己写的,界面及其难看,毫无健壮性,操作稍微错一步就得崩,不过用这玩 意应付老师还可以的哈哈。

      下面写的是使用C++的Qt界面设计的一个多文本编辑器,界面好看了许多,而且操作起来不存在bug,功能上可能少一点,没有添加颜色和字体功能,但是看着比较舒服,可以实现多文档的平铺和层叠,有一定的可操作性。还有我这个是使用Qt creator编辑器写的,可以去Qt中文社区下载安装,很简单。

多文档文本编辑器(Qt)

      这是我的一个项目文件目录,其中.ui文件是界面设计文件,Qt是所使用xml文件保存界面设计的代码,和java有所区别。源文件的三个C++文件是具体的实现方法和子窗口实现方法。头文件中定义和相关的函数。代码挺多的大约四五百行左右,所以不太容易看懂,但是里面添加了许多的注释,应该大致的调用结构可以看得懂,一些具体的方法就不用管了。

下面展示一下成果界面

多文档文本编辑器(Qt)

       可以实现文件的打开,保存,多文档平铺和层叠,关闭,撤销,复制,粘贴,剪切以及前一个和后一个文档的切换,我觉得比较好的是细节做得还是挺好的,比如没有打开文件的时候工具栏禁止操作,对文档是否被修改进行*号标记,显示文本的行号和列号信息,自动显示滚动条,操作成功的信息提醒等一些细节上的实现。

        下面代码段是其中mdichild.cpp文件的源码,主要是实现一些子窗口的功能,比如文件的打开和加载,文件的另存为等一些操作。

#include "mdichild.h"
#include<QFile>
#include<QTextStream>
#include<QMessageBox>
#include<QFileInfo>
#include<QApplication>
#include<QFileDialog>
#include<QCloseEvent>
#include<QPushButton>
MdiChild::MdiChild(QWidget *parent) :
    QTextEdit(parent)
{
    setAttribute(Qt::WA_DeleteOnClose);

    isUntitled = true;

}
//新建文件
void MdiChild::newFile()
{
    static int sequenceNumber = 1;

    isUntitled = true;

    curFile = tr("未命名文档%1.txt").arg(sequenceNumber++);

    setWindowTitle(curFile+"[*]"+tr("-多文档编辑器"));

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

}
//文档是否被修改
void MdiChild::documentWasModified()
{
    setWindowModified(document()->isModified());
}

void MdiChild::setCurrentFile(const QString &fileName)
{   //canonicalFilePath可以出去路径中的符号
    curFile = QFileInfo(fileName).canonicalFilePath();
    //文件已经被保存过了
    isUntitled = false;
    //文档没有被更改
    document()->setModified(false);

    //窗口不显示*号
    setWindowModified(false);

    //设置窗口标题,userFriendlyCurrentFile()返回文件名
    setWindowTitle(userFriendlyCurrentFile()+"[*]");
}
//加载文件
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(),SIGNAL(contentsChanged()),this,SLOT(documentWasModified()));
    return true;
}

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

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

//另存为
bool MdiChild::saveAs()
{
    QString fileName = QFileDialog::getSaveFileName(this,tr("另存为"),curFile);
    //获取文件路径,如果为空,则返回false,否则保存文件
    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;
}

//关闭操作
void MdiChild::colseEvent(QCloseEvent *event)
{
    if(maybeSave()){
        event->accept();
    }else{
        event->ignore();
    }
}

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("是"),QMessageBox::YesRole);
        box.addButton(tr("否"),QMessageBox::NoRole);
        QPushButton *cancelBtn = box.addButton(tr("取消"),QMessageBox::RejectRole);

        //弹出对话框,让用户选择是否保存修改
        box.exec();
        if(box.clickedButton() == yesBtn){
            return save();
        }else if(box.clickedButton()==cancelBtn){
            return false;
        }
    }
    //如果没有更改,直接返回true
    return true;
}

另外一个cpp文件的代码较多就不贴了,而且中间图片都是在项目文件夹之下,还要环境配置的问题,有代码也不一定能运行,而且****很多资源都是半成品就传了上去,深受其害。所以我把项目打包成了exe文件,加上一些配置文件可以在电脑上直接运行,省去了很多事。压缩包里面包括可执行文件和项目所有的源文件。

附上下载链接:

https://download.****.net/download/cumtlz/10727791