Qt : 记事本demo(附全部源码)

回想起学习Qt已经快四个多月了,还记得我写的第一个小项目,就是windows系统下的记事本程序,也就是我们习惯称为的notepad.早上把之前写的代码拿出来看了,说真的,看笑了自己,以前写的代码感觉好幼稚,很多地方写的都很不好,包括命名习惯,函数的封装等等…所以我今天花了点时间,把这个程序重新写了一遍,基本上让别人看我的代码,看上去思路还是挺清晰好懂的!

notead主要实现了以下功能:
1.常规上的文件打开保存等功能,包括其他windows系统上的notepad所有的功能.
2.添加了修改字体和修改颜色的功能.
3.当第二次以上打开程序时,会自动配置用户上一次使用时的状态,主要用到了QSettings进行配置.
4.代码精炼易懂.
5.具有相当丰富的注释.

下面是效果图:

这里写图片描述

下面贴出源码:如果想直接使用的话,可以在最后进行源码的下载!

“c.h”

#ifndef C_H
#define C_H

#include <QtWidgets/QMainWindow>
#include "ui_c.h"
#include <QTextEdit>
#include <QMenu>
#include <QAction>
#include <QHBoxLayout>
#include <QIcon>
#include <QMessageBox>
#include <QFile>
#include <QFileDialog>
#include <QTextStream>
#include <QPageSetupDialog>
#include <QPrintPreviewDialog>
#include <QPrintDialog>
#include <QPrinter>
#include <QEvent>
#include <QCloseEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QClipboard>
#include <QTextCursor>
#include "FindDialog.h"
#include <QDateTime>
#include <QFontDialog>
#include <QColorDialog>
#include <QInputDialog>
#include <QSettings>
#include "ReplaceDialog.h"

**//新加入的头文件.**
#include <QTextBlock>

class c : public QMainWindow
{
    Q_OBJECT
    typedef enum{
        tag_save = 0,
        tag_notSave = 1,
        tag_cancel = 2
    }Mes_status;
public:
    c(QWidget *parent = 0);
    ~c();
protected:
    void closeEvent(QCloseEvent *event);
    void dragEnterEvent(QDragEnterEvent *event);
    void dropEvent(QDropEvent *event);
    void enterEvent(QEvent *event);
private slots:
    void createNewFileSlot();
    void openFileSlot();
    void saveFileSlot();
    int saveAsFileSlot();
    void setPageSlot();
    void exitAppSlot();
    void showPrintDialogSlot();
    void showContextMenuSlot(const QPoint&);
    void undoSlot(bool);
    void copySlot(bool);
    void delSelectedTextSlot();
    void enableButtonSlot();
    void showFindDialogSlot();
    void findTextSlot(QString, bool, int);
    void findAnotherSlot();
    void gotoLineSlot();
    void appendDateSlot();
    void setFontSlot();
    void setColorSlot();
    void lineWrapSlot(bool);
    void showStatusBarSlot(bool);
    void showStatusBarTextSlot();
    void showWriterSlot();
    void cancelTextSelectedSlot();
    void showReplaceDialogSlot();
    void findSlot(QString, bool);
    void replaceTextSlot(QString, QString, bool);
    void replaceAllSlot(QString, QString, bool);
private:
    Ui::cClass ui;
    //初始化TextEdit.
    void initTextEdit();
    void initMenuBar();
    void initConnect();
    void initContextMenu();
    void initStatusBar();
    //show是否保存的对话框.
    int showSavedDialog();
    //
    QString getFileName();
    //
    void saveFile(QString);
    //
    void readFile(QString);
    //
    void initGotoDialog();
    //
    void saveUsersStatus();
    void initUsersStatus();
    void initToolBar();

    QTextEdit *m_textEdit;
    //主菜单中的按钮.
    QMenu *m_fileMenu;
    QMenu *m_editMenu;
    QMenu *m_formatMenu;
    QMenu *m_lookMenu;
    QMenu *m_helptMenu;
    QAction *m_newAction;
    QAction *m_openAction;
    QAction *m_saveAction;
    QAction *m_saveAsAction;
    QAction *m_pageSetAction;
    QAction *m_printAction;
    QAction *m_exitAction;
    QAction *m_undoAction;
    QAction *m_cutAction;
    QAction *m_copyAction;
    QAction *m_pasteAction;
    QAction *m_delAction;
    QAction *m_findAction;
    QAction *m_findAnotherAction;
    QAction *m_replaceAction;
    QAction *m_gotoAction;
    QAction *m_selectAllAction;
    QAction *m_dateAction;
    QAction *m_lineWrapAction;
    QAction *m_fontAction;
    QAction *m_colorAction;
    QAction *m_statusBarAction;
    QAction *m_aboutAction;

    //右键菜单中的按钮.
    QMenu *m_contextMenu;
    QAction *m_contextMenuUndoAction;
    QAction *m_contextMenuCutAction;
    QAction *m_contextMenuCopyAction;
    QAction *m_contextMenuPasteAction;
    QAction *m_contextMenuDelAction;
    QAction *m_contextMenuSelectAllAction;
    QAction *m_contextMenuReSelectAction;

    //记录文件是否被保存.
    bool m_isSaved;
    bool m_isChanged;
    QString m_filePath;
    QString m_tempPath;
    bool m_isFinded;
    QString m_findText;
    QString m_replaceText;
    bool m_sSign;
    int m_dir;
    QLabel *m_firstStatusLabel;
    QLabel *m_secondStatusLabel;
    bool m_isChecked;
    QInputDialog *m_gotoDialog;
    FindDialog *m_findDialog;
    ReplaceDialog *m_replaceDialog;

};

#endif // C_H

“c.cpp”

#include "c.h"


void c::saveUsersStatus()
{
    QSettings app("notepad", "selectStatus");
    //保存用户的选择以及窗口的位置和大小.
    app.setValue("lineWrap", m_lineWrapAction->isChecked());
    app.setValue("statusBar", m_statusBarAction->isChecked());
    app.setValue("pos", this->pos());
    app.setValue("size", this->size());
    //对于字体,颜色就不进行保存了...
}
void c::initUsersStatus()
{
    QSettings app("notepad", "selectStatus");
    //保存用户的选择以及窗口的位置和大小.
    bool lineWrapSign = app.value("lineWrap").toBool();
    bool statusBarSign = app.value("statusBar").toBool();
    QPoint pos = app.value("pos").toPoint();
    QSize size = app.value("size").toSize();

    this->move(pos);
    this->resize(size);
    m_lineWrapAction->setChecked(lineWrapSign);
    m_statusBarAction->setChecked(statusBarSign);

    if (lineWrapSign)
        lineWrapSlot(true);
    if (statusBarSign)
        showStatusBarSlot(true);
}

c::c(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    m_isChanged = false;
    m_isSaved = false;
    m_isFinded = false;
    m_isChecked = false;
    m_filePath = QString::fromLocal8Bit("新建文本文档.txt");

    m_findDialog = new FindDialog(this);
    m_replaceDialog = new ReplaceDialog(this);

    initTextEdit();
    initMenuBar();
    initToolBar();
    initGotoDialog();
    initStatusBar();
    initContextMenu();
    initConnect();

    //如果是第一次登陆的话,那么注册表中的这项基本都是0.如果不是第一次登陆的话,会自动根据上一次的登陆情况进行信息配置.
    QSettings app("notepad", "selectStatus");
    QPoint pos = app.value("pos").toPoint();

    if (!pos.isNull())
    {
        //初始化用户上一次登录的选择.
        initUsersStatus();
    }
}

c::~c()
{
    delete m_textEdit;
}
void c::initTextEdit()
{
    //创建一个widget.
    QWidget *widget = new QWidget();

    //设置widget的布局.
    QHBoxLayout *layout = new QHBoxLayout();
    m_textEdit = new QTextEdit();
    layout->addWidget(m_textEdit);

    //设置它的布局.主窗口自定义布局就要按照这样的方式.
    widget->setLayout(layout);
    this->setCentralWidget(widget);

    //设置文本编辑框的滚动条策略.默认是Qt::ScrollBarAsNeeded.初始化时设置为开启.
    m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);

    //刚开始文本编辑框的换行模式是不换行的.
    m_textEdit->setLineWrapMode(QTextEdit::NoWrap);

    //设置文本编辑框的右键菜单策略.
    m_textEdit->setContextMenuPolicy(Qt::CustomContextMenu);

    //禁用文本编辑框的接受拖拽.因为QTextEdit默认实现了有关拖拽的虚函数.会吞噬掉拖拽进来的信号,所以要关闭,不懂也没事,关闭就行.
    m_textEdit->setAcceptDrops(false);
    //打开主窗口接受拖放的功能.
    this->setAcceptDrops(true);

    //设置主窗口的标题.
    this->setWindowTitle(m_filePath + QString::fromLocal8Bit(" - 记事本"));
    //设置主窗口左上角的图标.
    this->setWindowIcon(QIcon("Resources/Icons/document.png"));
    //设置主窗口的初始大小.1000.800
    this->resize(600,400);

    //设置被选中的颜色.
    m_textEdit->setStyleSheet("selection-background-color: rgb(85, 85, 255);");
}
void c::initGotoDialog()
{
    m_gotoDialog = new QInputDialog;
    m_gotoDialog->setWindowTitle(QString::fromLocal8Bit("转到指定行"));
    m_gotoDialog->setOkButtonText(QString::fromLocal8Bit("转到"));
    m_gotoDialog->setCancelButtonText(QString::fromLocal8Bit("取消"));
    m_gotoDialog->setTextEchoMode(QLineEdit::Normal);
    m_gotoDialog->setLabelText(QString::fromLocal8Bit("行号(&L)"));
    m_gotoDialog->setInputMode(QInputDialog::IntInput);

    m_gotoDialog->setIntMinimum(1);
    m_gotoDialog->setIntMaximum(10000000000000);
}
void c::initMenuBar()
{
    //创建菜单和按钮.
    m_fileMenu = new QMenu(QString::fromLocal8Bit("文件(&F)"));
    m_editMenu = new QMenu(QString::fromLocal8Bit("编辑(&E)"));
    m_formatMenu = new QMenu(QString::fromLocal8Bit("格式(&O)"));
    m_lookMenu = new QMenu(QString::fromLocal8Bit("查看(&V)"));
    m_helptMenu = new QMenu(QString::fromLocal8Bit("帮助(&H)"));
    m_newAction = new QAction(QString::fromLocal8Bit("新建(&N)"), this); m_newAction->setShortcut(tr("Ctrl+N")); m_newAction->setIcon(QIcon("./Resources/Icons/new.png"));
    m_openAction = new QAction(QString::fromLocal8Bit("打开(&O)..."), this); m_openAction->setShortcut(tr("Ctrl+O")); m_openAction->setIcon(QIcon("./Resources/Icons/open.png"));
    m_saveAction = new QAction(QString::fromLocal8Bit("保存(&S)"), this); m_saveAction->setShortcut(tr("Ctrl+S")); m_saveAction->setIcon(QIcon("./Resources/Icons/save.png"));
    m_saveAsAction = new QAction(QString::fromLocal8Bit("另存为(&A)..."), this); m_saveAsAction->setIcon(QIcon("./Resources/Icons/saveAs.png"));
    m_pageSetAction = new QAction(QString::fromLocal8Bit("页面设置(&U)..."), this);
    m_printAction = new QAction(QString::fromLocal8Bit("打印(&P)..."), this); m_printAction->setShortcut(tr("Ctrl+P")); m_printAction->setIcon(QIcon("./Resources/Icons/print.png"));
    m_exitAction = new QAction(QString::fromLocal8Bit("退出(&X)"), this); m_exitAction->setIcon(QIcon("./Resources/Icons/exit.png"));
    m_undoAction = new QAction(QString::fromLocal8Bit("撤销(&U)"), this); m_undoAction->setShortcut(tr("Ctrl+Z")); m_undoAction->setIcon(QIcon("./Resources/Icons/undo.png"));
    m_cutAction = new QAction(QString::fromLocal8Bit("剪切(&T)"), this); m_cutAction->setShortcut(tr("Ctrl+X")); m_cutAction->setIcon(QIcon("./Resources/Icons/cut.png"));
    m_copyAction = new QAction(QString::fromLocal8Bit("复制(&C)"), this); m_copyAction->setShortcut(tr("Ctrl+C")); m_copyAction->setIcon(QIcon("./Resources/Icons/copy.png"));
    m_pasteAction = new QAction(QString::fromLocal8Bit("粘贴(&P)"), this); m_pasteAction->setShortcut(tr("Ctrl+V")); m_pasteAction->setIcon(QIcon("./Resources/Icons/paste.png"));
    m_delAction = new QAction(QString::fromLocal8Bit("删除(&L)"), this); m_delAction->setShortcut(tr("Del")); m_delAction->setIcon(QIcon("./Resources/Icons/del.png"));
    m_findAction = new QAction(QString::fromLocal8Bit("查找(&F)..."), this); m_findAction->setShortcut(tr("Ctrl+F"));
    m_findAnotherAction = new QAction(QString::fromLocal8Bit("查找下一个(&N)"), this); m_findAnotherAction->setShortcut(tr("F3"));
    m_replaceAction = new QAction(QString::fromLocal8Bit("替换(&R)..."), this); m_replaceAction->setShortcut(tr("Ctrl+H"));
    m_gotoAction = new QAction(QString::fromLocal8Bit("转到(&G)..."), this); m_gotoAction->setShortcut(tr("Ctrl+G")); m_gotoAction->setIcon(QIcon("./Resources/Icons/goto.png"));
    m_selectAllAction = new QAction(QString::fromLocal8Bit("全选(&A)"), this); m_selectAllAction->setShortcut(tr("Ctrl+A"));
    m_dateAction = new QAction(QString::fromLocal8Bit("时间/日期(&D)"), this); m_dateAction->setShortcut(tr("F5")); m_dateAction->setIcon(QIcon("./Resources/Icons/date.png"));
    m_lineWrapAction = new QAction(QString::fromLocal8Bit("自动换行(&W)"), this);
    m_fontAction = new QAction(QString::fromLocal8Bit("字体(&F)..."), this); m_fontAction->setIcon(QIcon("./Resources/Icons/font.png"));
    m_colorAction = new QAction(QString::fromLocal8Bit("颜色(&C)"), this); m_colorAction->setIcon(QIcon("./Resources/Icons/color.png"));
    m_statusBarAction = new QAction(QString::fromLocal8Bit("状态栏(&S)"), this);
    m_aboutAction = new QAction(QString::fromLocal8Bit("关于作者(&A)"), this);

    //分别把按钮项加入到菜单中.
    m_fileMenu->addAction(m_newAction);
    m_fileMenu->addAction(m_openAction);
    m_fileMenu->addAction(m_saveAction);
    m_fileMenu->addAction(m_saveAsAction);
    m_fileMenu->addSeparator();
    m_fileMenu->addAction(m_pageSetAction);
    m_fileMenu->addAction(m_printAction);
    m_fileMenu->addSeparator();
    m_fileMenu->addAction(m_exitAction);
    //
    m_editMenu->addAction(m_undoAction);
    m_editMenu->addSeparator();
    m_editMenu->addAction(m_cutAction);
    m_editMenu->addAction(m_copyAction);
    m_editMenu->addAction(m_pasteAction);
    m_editMenu->addAction(m_delAction);
    m_editMenu->addSeparator();
    m_editMenu->addAction(m_findAction);
    m_editMenu->addAction(m_findAnotherAction);
    m_editMenu->addAction(m_replaceAction);
    m_editMenu->addAction(m_gotoAction);
    m_editMenu->addSeparator();
    m_editMenu->addAction(m_selectAllAction);
    m_editMenu->addAction(m_dateAction);
    //
    m_formatMenu->addAction(m_lineWrapAction);
    m_formatMenu->addAction(m_fontAction);
    m_formatMenu->addAction(m_colorAction);
    //
    m_lookMenu->addAction(m_statusBarAction);
    //
    m_helptMenu->addAction(m_aboutAction);
    //把菜单项加入到主菜单中.
    ui.menuBar->addMenu(m_fileMenu);
    ui.menuBar->addMenu(m_editMenu);
    ui.menuBar->addMenu(m_formatMenu);
    ui.menuBar->addMenu(m_lookMenu);
    ui.menuBar->addMenu(m_helptMenu);

    //初始设置以下按钮不能被点击.
    m_undoAction->setEnabled(false);
    m_cutAction->setEnabled(false);
    m_copyAction->setEnabled(false);
    m_delAction->setEnabled(false);
    m_findAction->setEnabled(false);
    m_findAnotherAction->setEnabled(false);

    //设置以下按钮可以被按下.
    m_lineWrapAction->setCheckable(true);
    m_statusBarAction->setCheckable(true);


}
void c::initStatusBar()
{
    m_firstStatusLabel = new QLabel();
    m_secondStatusLabel = new QLabel();

    //把label加入到状态栏中,并且设置拉伸比例.
    ui.statusBar->addWidget(m_firstStatusLabel,3);
    ui.statusBar->addWidget(m_secondStatusLabel,1);
    //修改对齐格式.
    m_secondStatusLabel->setAlignment(Qt::AlignCenter);

    //隐藏.
    ui.statusBar->hide();
}
void c::initConnect()
{
    connect(m_textEdit, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenuSlot(const QPoint&)));
    connect(m_textEdit, SIGNAL(undoAvailable(bool)),this, SLOT(undoSlot(bool)));
    connect(m_textEdit, SIGNAL(copyAvailable(bool)), this, SLOT(copySlot(bool)));
    connect(m_textEdit, SIGNAL(textChanged()), this, SLOT(enableButtonSlot()));
    connect(m_textEdit, SIGNAL(cursorPositionChanged()), this, SLOT(showStatusBarTextSlot()));  

    connect(m_findDialog, SIGNAL(findText(QString, bool, int)), this, SLOT(findTextSlot(QString, bool, int)));
    connect(m_replaceDialog, SIGNAL(findText(QString,bool)), this, SLOT(findSlot(QString,bool)));
    connect(m_replaceDialog, SIGNAL(replaceText(QString, QString, bool)), this, SLOT(replaceTextSlot(QString, QString, bool)));
    connect(m_replaceDialog, SIGNAL(replaceAllText(QString,QString,bool)), this, SLOT(replaceAllSlot(QString,QString,bool)));

    //连接按钮的信号与槽.
    //文件菜单.
    connect(m_newAction, SIGNAL(triggered()),this, SLOT(createNewFileSlot()));
    connect(m_openAction, SIGNAL(triggered()), this, SLOT(openFileSlot()));
    connect(m_saveAction, SIGNAL(triggered()), this, SLOT(saveFileSlot()));
    connect(m_saveAsAction, SIGNAL(triggered()), this, SLOT(saveAsFileSlot()));
    connect(m_pageSetAction, SIGNAL(triggered()),this, SLOT(setPageSlot()));
    connect(m_printAction, SIGNAL(triggered()),this, SLOT(showPrintDialogSlot()));
    connect(m_exitAction, SIGNAL(triggered()),this, SLOT(exitAppSlot()));

    //编辑菜单.
    connect(m_undoAction, SIGNAL(triggered()), m_textEdit, SLOT(undo()));
    connect(m_contextMenuUndoAction, SIGNAL(triggered()), m_textEdit, SLOT(undo()));
    connect(m_cutAction, SIGNAL(triggered()), m_textEdit, SLOT(cut())); 
    connect(m_contextMenuCutAction, SIGNAL(triggered()), m_textEdit, SLOT(cut()));
    connect(m_copyAction, SIGNAL(triggered()), m_textEdit, SLOT(copy()));
    connect(m_contextMenuCopyAction, SIGNAL(triggered()), m_textEdit, SLOT(copy()));
    connect(m_pasteAction, SIGNAL(triggered()), m_textEdit, SLOT(paste()));
    connect(m_contextMenuPasteAction, SIGNAL(triggered()), m_textEdit, SLOT(paste()));
    connect(m_delAction, SIGNAL(triggered()), this, SLOT(delSelectedTextSlot()));
    connect(m_contextMenuDelAction, SIGNAL(triggered()), this, SLOT(delSelectedTextSlot()));
    connect(m_findAction, SIGNAL(triggered()), this, SLOT(showFindDialogSlot()));
    connect(m_findAnotherAction, SIGNAL(triggered()), this, SLOT(findAnotherSlot()));
    connect(m_replaceAction, SIGNAL(triggered()), this, SLOT(showReplaceDialogSlot()));
    connect(m_gotoAction, SIGNAL(triggered()), this, SLOT(gotoLineSlot()));
    connect(m_selectAllAction, SIGNAL(triggered()), m_textEdit, SLOT(selectAll()));
    connect(m_contextMenuSelectAllAction, SIGNAL(triggered()), m_textEdit, SLOT(selectAll()));
    connect(m_dateAction, SIGNAL(triggered()), this, SLOT(appendDateSlot()));
    connect(m_lineWrapAction, SIGNAL(toggled(bool)), this, SLOT(lineWrapSlot(bool)));
    connect(m_fontAction, SIGNAL(triggered()), this, SLOT(setFontSlot()));
    connect(m_colorAction, SIGNAL(triggered()), this, SLOT(setColorSlot()));
    connect(m_contextMenuReSelectAction, SIGNAL(triggered()), this, SLOT(cancelTextSelectedSlot()));

    connect(m_statusBarAction, SIGNAL(toggled(bool)), this, SLOT(showStatusBarSlot(bool)));

    connect(m_aboutAction, SIGNAL(triggered()), this, SLOT(showWriterSlot()));

}
void c::createNewFileSlot()
{
    int status = 0;
    //判断文本的内容是否被修改过.
    if (m_isChanged)
    {
        status = showSavedDialog();
    }
    if (status == tag_cancel)
        return;

    //以下为必要动作,无论用户如何选择.
    //修改标识符.清空编辑框.
    **//这里的代码位置如下:先把文本编辑框清零.**
    m_textEdit->clear();
    m_isSaved = false;
    m_isChanged = false;
    m_filePath = QString::fromLocal8Bit("无标题.txt");
    this->setWindowTitle(m_filePath + QString::fromLocal8Bit("-记事本"));
}
int c::showSavedDialog()
{
    QMessageBox mes(this);
    //修改标题和文本.
    mes.setText(QString::fromLocal8Bit("是否将更改保存到:") + m_filePath);
    mes.setWindowTitle(QString::fromLocal8Bit("记事本"));
    //设置默认按钮.
    mes.setStandardButtons(QMessageBox::Save | QMessageBox::No | QMessageBox::Cancel);
    mes.setDefaultButton(QMessageBox::Save);
    //修改按钮显示的文本.
    mes.setButtonText(QMessageBox::Save, QString::fromLocal8Bit("保存(&S)"));
    mes.setButtonText(QMessageBox::No, QString::fromLocal8Bit("不保存(&N)"));
    mes.setButtonText(QMessageBox::Cancel, QString::fromLocal8Bit("取消"));

    //用户的选择.
    int status = mes.exec();
    if (status == QMessageBox::Save)
    {
        //如果文件存在.
        if (m_isSaved)
        {
            saveFile(m_filePath);
            m_isSaved = true;
            m_isChanged = false;
        }
        else
            saveAsFileSlot();
        return tag_save;
    }
    else if (status == QMessageBox::No)
    {
        return tag_notSave;
    }
    else
    {
        return tag_cancel;
    }
    //其他两个选项,选择了会自动关闭对话框.
}

void c::saveFile(QString filePath)
{
    //只写的方式打开文件.
    QFile *file = new QFile(filePath);
    bool ok = file->open(QIODevice::WriteOnly);
    if (ok)
    {
        **//在这里修改代码,下面的代码是正确的做法.**
        //连接到文本流中.
        QTextStream stream(file);
        QTextDocument *document = m_textEdit->document();

        int pos = 0;
        while (pos <= document ->blockCount())
        {
            QString blockText = document ->findBlockByLineNumber(pos++).text() + "\r\n";
            stream << blockText;
        }
    }
    //关闭文件.
    file->close();
}
void c::readFile(QString filePath)
{
    //记录新打开文件的路径.
    m_filePath = filePath;

    QFile *file = new QFile(filePath);
    bool ok = file->open(QIODevice::ReadOnly);
    if (ok)
    {
        QTextStream stream(file);
        this->setWindowTitle(getFileName() + QString::fromLocal8Bit(" - 记事本"));
        m_textEdit->setPlainText(stream.readAll());
        file->close();
    }
}
QString c::getFileName()
{
    QFileInfo info(m_filePath);
    return info.fileName();
}

//
void c::openFileSlot()
{
    if (m_isChanged)
    {
        int status = showSavedDialog();
        //如果是取消,则不会打开文件.
        if (status == tag_cancel)
            return;
    }

    QString filePath = QFileDialog::getOpenFileName(this, QString::fromLocal8Bit("打开"), QDir::currentPath(), QString::fromLocal8Bit("文本文档(*.txt);;所有文件(*.*)"));
    //检查是否为空.如果为空,说明用户没有选择文件,直接关闭了对话框.
    if (filePath.isEmpty())
        return;
    readFile(filePath);
    //修改标识符.
    m_isSaved = true;
    m_isChanged = false;
}
void c::saveFileSlot()
{
    int status = 0;
    //如果文件存在.
    if (m_isSaved)
    {
        saveFile(m_filePath);
        m_isSaved = true;
        m_isChanged = false;
    }
    else
    {
        status = saveAsFileSlot();
        if (status == tag_save)
        {
            m_isSaved = true;
            m_isChanged = false;
            m_filePath = m_tempPath;
            //修改标题.
            this->setWindowTitle(getFileName() + QString::fromLocal8Bit(" - 记事本"));
        }
        else
        {
            m_isSaved = false;
        }
    }
}
int c::saveAsFileSlot()
{
    //跳出保存对话框并且保存文件.
    QString filePath = QFileDialog::getSaveFileName(this, QString::fromLocal8Bit("另存为"), QDir::currentPath(), QString::fromLocal8Bit("文本文档(*.txt);;所有文件(*.*)"));
    if (!filePath.isEmpty())
    {
        m_tempPath = filePath;
        saveFile(filePath);
        return tag_save;
    }
    return tag_cancel;
}
void c::setPageSlot()
{
    QPrinter printer;
    //设置页面对话框.
    QPageSetupDialog pageSetUpdlg(&printer, this);
    if (pageSetUpdlg.exec() == QDialog::Accepted)
    {
        printer.setOrientation(QPrinter::Landscape);
    }
    else
    {
        printer.setOrientation(QPrinter::Portrait);
    }
}
void c::showPrintDialogSlot()
{
    QPrinter q;
    //打印对话框.
    QPrintDialog s(&q, this);
    if (s.exec() == QDialog::Accepted)
        m_textEdit->print(&q);
}
void c::exitAppSlot()
{
    int status = 0;

    //如果被修改过.
    if (m_isChanged)
    {
        status = showSavedDialog();
        if (status == tag_cancel)
            return;
    }

    //关闭app.
    saveUsersStatus();
    QApplication::exit();
}

void c::enableButtonSlot()
{
    if (m_textEdit->document()->isEmpty())
    {
        m_contextMenuSelectAllAction->setEnabled(false);
        m_contextMenuReSelectAction->setEnabled(false);
        m_findAction->setEnabled(false);
        m_findAnotherAction->setEnabled(false);
    }
    else
    {
        m_contextMenuSelectAllAction->setEnabled(true);
        m_contextMenuReSelectAction->setEnabled(true);
        m_findAction->setEnabled(true);
        m_findAnotherAction->setEnabled(true);
    }
    m_isChanged = true;
}
void c::undoSlot(bool canUndo)
{
    if (canUndo)
    {
        m_undoAction->setEnabled(true);
        m_contextMenuUndoAction->setEnabled(true);
    }
    else
    {
        m_undoAction->setEnabled(false);
        m_contextMenuUndoAction->setEnabled(false);
    }
}
void c::copySlot(bool canCopy)
{
    if (canCopy)
    {
        m_cutAction->setEnabled(true);
        m_copyAction->setEnabled(true);
        m_delAction->setEnabled(true);
        m_contextMenuCutAction->setEnabled(true);
        m_contextMenuCopyAction->setEnabled(true);
        m_contextMenuDelAction->setEnabled(true);
    }
    else
    {
        m_cutAction->setEnabled(false);
        m_copyAction->setEnabled(false);
        m_delAction->setEnabled(false);
        m_contextMenuCutAction->setEnabled(false);
        m_contextMenuCopyAction->setEnabled(false);
        m_contextMenuDelAction->setEnabled(false);
    }
}
//重写的虚函数.
void c::closeEvent(QCloseEvent *event)
{
    exitAppSlot();
    //如果用户点击取消,则不关闭程序.
    event->ignore();
}
void c::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasUrls())
    {
        event->setDropAction(Qt::CopyAction);
        event->accept();
    }
}
void c::dropEvent(QDropEvent *event)
{
    int status = 0;

    //如果被修改过.
    if (m_isChanged)
    {
        status = showSavedDialog();
    }

    //获取拖入的文件的路径.
    QList<QUrl> s = event->mimeData()->urls();
    QString path = s[0].toLocalFile();
    //读取文件内容.
    readFile(path);
    m_isChanged = false;
    m_isSaved = true;
}
void c::enterEvent(QEvent *event)
{
    QString contents = QApplication::clipboard()->text();
    if (contents.isEmpty())
    {
        m_pasteAction->setEnabled(false);
        m_contextMenuPasteAction->setEnabled(false);
    }
    else
    {
        m_pasteAction->setEnabled(true);
        m_contextMenuPasteAction->setEnabled(true);
    }
}
void c::initContextMenu()
{
    m_contextMenu = new QMenu;
    m_contextMenuUndoAction = new QAction(QString::fromLocal8Bit("撤销(U)"), this);
    m_contextMenuCutAction = new QAction(QString::fromLocal8Bit("剪切(T)"), this);
    m_contextMenuCopyAction = new QAction(QString::fromLocal8Bit("复制(C)"), this);
    m_contextMenuPasteAction = new QAction(QString::fromLocal8Bit("粘贴(P)"), this);
    m_contextMenuDelAction = new QAction(QString::fromLocal8Bit("删除(D)"), this);
    m_contextMenuSelectAllAction = new QAction(QString::fromLocal8Bit("全选(A)"), this);
    m_contextMenuReSelectAction = new QAction(QString::fromLocal8Bit("汉字重选(R)"), this);

    m_contextMenu->addAction(m_contextMenuUndoAction);
    m_contextMenu->addSeparator();
    m_contextMenu->addAction(m_contextMenuCutAction);
    m_contextMenu->addAction(m_contextMenuCopyAction);
    m_contextMenu->addAction(m_contextMenuPasteAction);
    m_contextMenu->addAction(m_contextMenuDelAction);
    m_contextMenu->addSeparator();
    m_contextMenu->addAction(m_contextMenuSelectAllAction);
    m_contextMenu->addSeparator();
    m_contextMenu->addAction(m_contextMenuReSelectAction);

    m_contextMenuUndoAction->setEnabled(false);
    m_contextMenuCopyAction->setEnabled(false);
    m_contextMenuCopyAction->setEnabled(false);
    m_contextMenuDelAction->setEnabled(false);
    m_contextMenuCutAction->setEnabled(false);
}
void c::showContextMenuSlot(const QPoint& pos)
{
    m_contextMenu->exec(QCursor::pos());
}
void c::delSelectedTextSlot()
{
    //取得文本编辑框中的光标.
    QTextCursor *textCursor = new QTextCursor(m_textEdit->textCursor());
    //调用成员方法删除被选中文本.
    textCursor->removeSelectedText();
}
void c::showFindDialogSlot()
{
    m_findDialog->clear();
    m_findDialog->setFindText(m_findText);
    //如果被隐藏了.则显示.
    if (m_findDialog->isHidden())
        m_findDialog->show();
    //反之,让它上升到顶层且属于激活状态.
    else
    {
        m_findDialog->raise();
        m_findDialog->activateWindow();
    }   
}
void c::findTextSlot(QString findText, bool checkSign, int dirSign)
{
    m_findText = findText;
    m_sSign = checkSign;
    m_dir = dirSign;

    //获取当前的光标位置.查找时作为当前光标的参数.
    QTextCursor *textCursor = new QTextCursor(m_textEdit->textCursor());
    //获取文本编辑看的文档格式.因为QTextDocument下有可以直接使用的查找方法.
    QTextDocument *document = m_textEdit->document();

    QTextDocument::FindFlag s; 
    QTextDocument::FindFlag dir;

    if (checkSign)      //如果区分大小写.
        s = QTextDocument::FindCaseSensitively;
    if (dirSign == 1)       //如果向上被选中.
        dir = QTextDocument::FindBackward;

    //找到匹配的位置.
    QTextCursor matchPos = document->find(findText, *textCursor, s | dir);
    if (!matchPos.isNull())     //如果不为空.
    {
        m_textEdit->setTextCursor(matchPos);
    }
    else
    {
        QMessageBox::information(this, QString::fromLocal8Bit("记事本"), QString::fromLocal8Bit("找不到") + "\"" + findText + "\"");
    }
    //修改标识符,已经查找过,所以在点击查找下一个就不会跳出对话框了.
    m_isFinded = true;
}
void c::findAnotherSlot()
{
    //如果没有查找过.则先显示查找对话框.
    if (!m_isFinded)
        showFindDialogSlot();
    //这里应该有其他的办法吧,没去细想.
    else
        findTextSlot(m_findText, m_sSign, m_dir);

}
void c::gotoLineSlot()
{
    QTextCursor *textCursor = new QTextCursor(m_textEdit->textCursor());
    //设置当前行数.
    m_gotoDialog->setIntValue(textCursor->blockNumber() + 1);

    QTextDocument *document = m_textEdit->document();
    int totalLineCount = document->blockCount();

    Goto_action:int status = m_gotoDialog->exec();
    if (status == QDialog::Accepted)
    {
        int n = m_gotoDialog->intValue();   //要求转到的行数.
        int m = textCursor->blockNumber() + 1;  //当前光标所在的行数.

        if (n <= totalLineCount)
        {
            if (n < m)      //如果要求转到的行在当前行的前面,就是让光标往前移.
            {
                textCursor->movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor, m - n);
            }
            else if (n > m)
            {
                textCursor->movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, n - m);
            }
            m_textEdit->setTextCursor(*textCursor);
        }
        else
        {
            QMessageBox::information(NULL, QString::fromLocal8Bit("记事本-跳行"), QString::fromLocal8Bit("行数超过了总行数"), QMessageBox::Ok);
            m_gotoDialog->setIntValue(totalLineCount);
            gotoLineSlot();
        }
    }
}
void c::appendDateSlot()
{
    //获取当前的时间日期,转化为指定格式.插入到文本的最后面,且不换行.
    QString str = QDateTime::currentDateTime().toString("hh:mm yyyy/M/d");
    m_textEdit->insertPlainText(str);
    //下面这种方法会自动换行.
    //m_textEdit->append(str);
}
void c::setFontSlot()
{
    bool ok;
    QFont currentFont = QFontDialog::getFont(&ok);
    if (ok)
    {
        m_textEdit->setFont(currentFont);
    }
}
void c::setColorSlot()
{
    QColor color = QColorDialog::getColor(Qt::black, this);
    if (color.isValid())
    {
        m_textEdit->setTextColor(color);
    }
}
void c::lineWrapSlot(bool sign)
{
    if (sign)
    {
        m_gotoAction->setEnabled(false);
        m_statusBarAction->setEnabled(false);
        //如果显示状态栏被按下了.
        if (m_statusBarAction->isChecked())
        {
            m_statusBarAction->setChecked(false);
            ui.statusBar->hide();
            m_isChecked = true;
        }

        //设置水平滚动策略总是关闭的,因为自动换行了嘛.
        m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        //同时也需要修改换行模式为根据当前窗口的大小进行换行,这里只是单纯的换行,不管被分割的单词.
        m_textEdit->setLineWrapMode(QTextEdit::WidgetWidth);
    }
    else
    {
        m_gotoAction->setEnabled(true);
        m_statusBarAction->setEnabled(true);

        m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
        m_textEdit->setLineWrapMode(QTextEdit::NoWrap);

        if (m_isChecked)
        {
            m_statusBarAction->setChecked(true);
            ui.statusBar->show();
        }
    }
}
void c::showStatusBarSlot(bool sign)
{
    if (sign)
    {
        ui.statusBar->show();
        showStatusBarTextSlot();
        m_isChecked = true;
    }
    else
    {
        ui.statusBar->hide();
        m_isChecked = false;
    }

}
void c::showStatusBarTextSlot()
{
    QTextCursor *textCursor = new QTextCursor(m_textEdit->textCursor());
    //获取行数.
    QString lineCount = QString::number(textCursor->blockNumber() + 1);
    //获取列数.
    QString columnCount = QString::number(textCursor->columnNumber() + 1);

    m_secondStatusLabel->setText(QString::fromLocal8Bit("第%1行,第%2列").arg(lineCount).arg(columnCount));
}
void c::showWriterSlot()
{
    QMessageBox::information(this, QString::fromLocal8Bit("关于作者"), QString::fromLocal8Bit("<a href='http://blog.csdn.net/qq_37233607' > 通往作者博客 </a>"));
}
void c::cancelTextSelectedSlot()
{
    QTextCursor cursor = m_textEdit->textCursor();
    //清空被选中的文本.
    cursor.clearSelection();
    //设置为文本编辑框的光标选择.
    m_textEdit->setTextCursor(cursor);
}
void c::showReplaceDialogSlot()
{
    m_replaceDialog->clear();
    m_replaceDialog->setFindText(m_findText);
    m_replaceDialog->setReplaceText(m_replaceText);
    //如果被隐藏了.则显示.
    if (m_replaceDialog->isHidden())
        m_replaceDialog->show();
    //反之,让它上升到顶层且属于激活状态.
    else
    {
        m_replaceDialog->raise();
        m_replaceDialog->activateWindow();
    }
}
void c::findSlot(QString text, bool sign)
{
    m_findText = text;
    m_sSign = sign;

    //获取当前的光标位置.查找时作为当前光标的参数.
    QTextCursor *textCursor = new QTextCursor(m_textEdit->textCursor());
    //获取文本编辑看的文档格式.因为QTextDocument下有可以直接使用的查找方法.
    QTextDocument *document = m_textEdit->document();

    QTextDocument::FindFlag s;

    if (sign)       //如果区分大小写.
        s = QTextDocument::FindCaseSensitively;

    //找到匹配的位置.
    QTextCursor matchPos = document->find(text, *textCursor, s);
    if (!matchPos.isNull())     //如果不为空.
    {
        m_textEdit->setTextCursor(matchPos);
    }
    else
    {
        QMessageBox::information(this, QString::fromLocal8Bit("记事本"), QString::fromLocal8Bit("找不到") + "\"" + text + "\"");
    }
    //修改标识符,已经查找过,所以在点击查找下一个就不会跳出对话框了.
    m_isFinded = true;
}
void c::replaceTextSlot(QString text, QString replaceText, bool sign)
{
    QTextCursor *textCursor = new QTextCursor(m_textEdit->textCursor());
    textCursor->movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
    m_replaceText = replaceText;

    QTextDocument *document = m_textEdit->document();

    QTextDocument::FindFlag s;
    if (sign)       //如果选择了 区分大小写.
        s = QTextDocument::FindCaseSensitively;

    auto temp = document->find(text, *textCursor, s);
    if (!temp.isNull())
    {
        temp.insertText(replaceText);
        temp.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, replaceText.size());
        m_textEdit->setTextCursor(temp);
    }
    else
    {
        QMessageBox::information(this, QString::fromLocal8Bit("记事本"), QString::fromLocal8Bit("找不到") + "\"" + text + "\"");
    }
    //修改标识符,已经查找过,所以在点击查找下一个就不会跳出对话框了.
    m_isFinded = true;
}
void c::replaceAllSlot(QString text, QString replaceText, bool sign)
{
    QTextCursor *textCursor = new QTextCursor(m_textEdit->textCursor());
    textCursor->movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);  //设置鼠标从文档的开头开始.

    QTextDocument *document = m_textEdit->document();

    m_findText = text;
    m_replaceText = replaceText;

    QTextDocument::FindFlags s;
    if (sign)
        s = QTextDocument::FindCaseSensitively;
    while (1)
    {
        QTextCursor temp = document->find(text, *textCursor, s);

        if (!temp.isNull())
        {
            temp.insertText(replaceText);
            m_textEdit->setTextCursor(temp);
        }
        else
        {
            return;
        }
    }
    //修改标识符,已经查找过,所以在点击查找下一个就不会跳出对话框了.
    m_isFinded = true;
}

void c::initToolBar()
{
    ui.mainToolBar->addAction(m_newAction);
    ui.mainToolBar->addAction(m_openAction);
    ui.mainToolBar->addAction(m_saveAction);
    ui.mainToolBar->addAction(m_saveAsAction);
    ui.mainToolBar->addAction(m_undoAction);
    ui.mainToolBar->addAction(m_cutAction);
    ui.mainToolBar->addAction(m_copyAction);
    ui.mainToolBar->addAction(m_pasteAction);
    ui.mainToolBar->addAction(m_delAction);
    ui.mainToolBar->addAction(m_gotoAction);
    ui.mainToolBar->addAction(m_dateAction);
    ui.mainToolBar->addAction(m_fontAction);
    ui.mainToolBar->addAction(m_colorAction);
    ui.mainToolBar->addAction(m_exitAction);
}

“FindDialog.h”

#ifndef FINDDIALOG_H
#define FINDDIALOG_H

#include <QDialog>
#include "ui_FindDialog.h"
#include <QCloseEvent>

class FindDialog : public QDialog
{
    Q_OBJECT
    typedef enum
    {
        tag_down = 0,
        tag_up = 1
    }Tag_Director;

public:
    FindDialog(QWidget *parent = 0);
    ~FindDialog();
    void clear();
    QString getFindText();
    bool getSSign();
    int getDirSign();
    void setFindText(QString);
signals:
    void findText(QString,bool,int);
private slots:
    void onFindSlot();
protected:
    void closeEvent(QCloseEvent *event);
private:
    Ui::FindDialog ui;
    QString m_text;
};

#endif // FINDDIALOG_H

“FindDialog.cpp”

#include "FindDialog.h"

FindDialog::FindDialog(QWidget *parent)
: QDialog(parent)
{
    ui.setupUi(this);
    clear();
    ui.findButton->setDefault(true);
    this->setFixedSize(this->size());
    this->setWindowTitle(QString::fromLocal8Bit("查找"));

    connect(ui.findButton, SIGNAL(clicked()), this, SLOT(onFindSlot()));
    connect(ui.cancelButton, SIGNAL(clicked()), this, SLOT(close()));
}

FindDialog::~FindDialog()
{

}
void FindDialog::onFindSlot()
{
    int dir = 0;
    if (ui.upButton->isChecked())
        dir = 1;

    m_text = ui.findLineEdit->text();

    //发出信号.
    emit findText(m_text, ui.checkBox->isChecked(), dir);
}
void FindDialog::clear()
{
    //给控件进行初始化.
    ui.checkBox->setChecked(false);
    ui.downButton->setChecked(true);
}
void FindDialog::closeEvent(QCloseEvent *event)
{
    event->accept();
}
QString FindDialog::getFindText()
{
    return m_text;
}
bool FindDialog::getSSign()
{
    return ui.checkBox->isChecked();
}
int FindDialog::getDirSign()
{
    int dir = 0;
    if (ui.upButton->isChecked())
        dir = 1;
    return dir;
}
void FindDialog::setFindText(QString text)
{
    m_text = text;
    ui.findLineEdit->setText(text);
}

“ReplaceDialog.h”

#ifndef REPLACEDIALOG_H
#define REPLACEDIALOG_H

#include <QDialog>
#include "ui_ReplaceDialog.h"

class ReplaceDialog : public QDialog
{
    Q_OBJECT

public:
    ReplaceDialog(QWidget *parent = 0);
    ~ReplaceDialog();
    void clear();
    void setFindText(QString);
    void setReplaceText(QString);
signals:
    void findText(QString, bool);
    void replaceText(QString,QString,bool);
    void replaceAllText(QString,QString,bool);
private slots:
    void enabledButtonSlot(QString);
    void findTextSlot();
    void replaceTextSlot();
    void replaceAllSlot();
private:
    Ui::ReplaceDialog ui;
    QString m_findText;
    QString m_replaceText;
};

#endif // REPLACEDIALOG_H

“ReplaceDialog.cpp”

#include "ReplaceDialog.h"

ReplaceDialog::ReplaceDialog(QWidget *parent)
    : QDialog(parent)
{
    ui.setupUi(this);
    ui.findButton->setEnabled(false);
    ui.replaceButton->setEnabled(false);
    ui.replaceAllButton->setEnabled(false);
    this->setFixedSize(this->size());
    this->setWindowTitle(QString::fromLocal8Bit("替换"));


    connect(ui.textLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enabledButtonSlot(QString)));
    connect(ui.cancelButton, SIGNAL(clicked()), this, SLOT(close()));
    connect(ui.findButton, SIGNAL(clicked()), this, SLOT(findTextSlot()));
    connect(ui.replaceButton, SIGNAL(clicked()), this, SLOT(replaceTextSlot()));
    connect(ui.replaceAllButton, SIGNAL(clicked()), this, SLOT(replaceAllSlot()));
}

ReplaceDialog::~ReplaceDialog()
{

}
void ReplaceDialog::enabledButtonSlot(QString text)
{
    if (!text.isEmpty())
    {
        ui.findButton->setEnabled(true);
        ui.replaceButton->setEnabled(true);
        ui.replaceAllButton->setEnabled(true);
    }
    else
    {
        ui.findButton->setEnabled(false);
        ui.replaceButton->setEnabled(false);
        ui.replaceAllButton->setEnabled(false);
    }
}
void ReplaceDialog::findTextSlot()
{
    m_findText = ui.textLineEdit->text();
    emit findText(m_findText,ui.checkBox->isChecked());
}
void ReplaceDialog::replaceTextSlot()
{
    m_replaceText = ui.replaceLineEdit->text();
    emit replaceText(ui.textLineEdit->text(), m_replaceText, ui.checkBox->isChecked());
}
void ReplaceDialog::replaceAllSlot()
{
    m_replaceText = ui.replaceLineEdit->text();
    emit replaceAllText(ui.textLineEdit->text(), m_replaceText, ui.checkBox->isChecked());
}
void ReplaceDialog::clear()
{
    //给控件进行初始化.
    ui.checkBox->setChecked(false);
    ui.textLineEdit->clear();
    ui.replaceLineEdit->clear();
    ui.findButton->setEnabled(false);
    ui.replaceButton->setEnabled(false);
    ui.replaceAllButton->setEnabled(false);
}
void ReplaceDialog::setFindText(QString text)
{
    m_findText = text;
    ui.textLineEdit->setText(text);
}
void ReplaceDialog::setReplaceText(QString text)
{
    m_replaceText = text;
    ui.replaceLineEdit->setText(text);
}

“main.cpp”:

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

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    c w;
    w.show();
    return a.exec();
}

想要全部打包好的文件的请点击http://download.csdn.net/download/qq_37233607/10218702进行下载!
有朋友提出,在saveFile函数里有点小问题,文本没有换行.我在代码块中重点标出修改后的代码!!!…还有个问题就是,在createNewFileSlot函数中,把一句代码的位置提前.我也做了重点标注.

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页