第35课 - 文本编辑器中的数据存取和功能交互

1、QAction的信号 

QAction被点击之后会产生一个triggered信号 

         - 通过信号与槽的机制能够捕捉对QAction对象的操作 

         - 项目中可以将多个信号映射到同一个槽函数 

 

2、文件打开操作 

3、文件保存操作 

4、文件另存为操作 

5、思考 

如何判断是否存在未保存的数据? 

6、QPlainTextEdit中的信号 

QPlainTextEdit能够触发与编辑操作相关的信号 

      - void textChanged()   // 字符发生变化时触发 

      - void copyAvailable(bool) 

      - void cursorPositionChanged() 

      - void redoAvailable(bool) 

      - void undoAvailable(bool) 

解决方案 

      1. 定义槽函数void onTextChanged() 

      2. 映射textChanged()到槽函数 

      3. 定义成员变量bool m_isTextChanged = false

      4 文本框中的字符发生变化时: m_isTextChanged = true

      5. 当m_isTextChanged为真,则存在未保存的数据 

 

7、文件新建操作 

8、编程实验

文本编辑器持续开发    NotePad.pro 

代码在最后

 

9、小结 

Qt项目中尽量将界面代码与功能代码分离开 

Qt项目开发时尽量复用平台中提供的相关组件 

Qt项目中的多数情况都是编写相应的槽函数 

       -槽函数用于相应用户操作 

       -槽函数是具体功能的触发点 

文本编辑组件能够触发与编辑操作相关的信号 

textChanged()信号能够用于检测数据变化 

文本编辑器项目中需要设置状态变量 

功能间的交互通过状态变量完成 

代码

MainWindow.h

#ifndef _MAINWINDOW_H_
#define _MAINWINDOW_H_

#include <QtGui/QMainWindow>
#include <QKeySequence>
#include <QMenuBar>
#include <QToolBar>
#include <QAction>
#include <QPlainTextEdit>
#include <QLabel>
#include <QFileDialog>

class MainWindow : public QMainWindow
{
    Q_OBJECT

private:
    QPlainTextEdit mainEditor;
    QLabel statusLbl;
    QString m_filePath;
    bool m_isTextChanged;

    MainWindow();
    MainWindow(const MainWindow&);
    MainWindow& operator= (const MainWindow&);

    bool construct();
    bool initMenuBar();
    bool initToolBar();
    bool initStatusBar();
    bool initMainEditor();
    bool initFileMenu(QMenuBar* mb);
    bool initEditMenu(QMenuBar* mb);
    bool initFormatMenu(QMenuBar* mb);
    bool initViewMenu(QMenuBar* mb);
    bool initHelpMenu(QMenuBar* mb);
    bool initFileToolItem(QToolBar* tb);
    bool initEditToolItem(QToolBar* tb);
    bool initFormatToolItem(QToolBar* tb);
    bool initViewToolItem(QToolBar* tb);
    bool makeAction(QAction*& action, QWidget* parent, QString text, int key);
    bool makeAction(QAction*& action, QWidget* parent, QString tip, QString icon);

    QString showFileDialog(QFileDialog::AcceptMode mode, QString title);
    int showQueryMessage(QString message);
    void showErrorMessage(QString message);
    QString saveCurrentData(QString path = "");
    void preEditorChange();
private slots:
    void onFileNew();
    void onFileOpen();
    void onFileSave();
    void onFileSaveAs();
    void onTextChanged();
public:
    static MainWindow* NewInstance();
    ~MainWindow();
};

#endif // _MAINWINDOW_H_

MainWindowUI.cpp

#include "MainWindow.h"
#include <QMenu>
#include <QIcon>
#include <QSize>
#include <QStatusBar>
#include <QLabel>
#include <QDebug>

MainWindow::MainWindow()
{
    setWindowTitle("NotePad - [ New ]");

    m_filePath = "";

    m_isTextChanged = false;
}

MainWindow* MainWindow::NewInstance()
{
    MainWindow* ret = new MainWindow();

    if( (ret == NULL) || !ret->construct() )
    {
        delete ret;
        ret = NULL;
    }

    return ret;
}

bool MainWindow::construct()
{
    bool ret = true;

    ret = ret && initMenuBar();
    ret = ret && initToolBar();
    ret = ret && initStatusBar();
    ret = ret && initMainEditor();

    return ret;
}

bool MainWindow::initMenuBar()
{
    bool ret = true;
    QMenuBar* mb = menuBar();

    ret = ret && initFileMenu(mb);
    ret = ret && initEditMenu(mb);
    ret = ret && initFormatMenu(mb);
    ret = ret && initViewMenu(mb);
    ret = ret && initHelpMenu(mb);

    return ret;
}

bool MainWindow::initToolBar()
{
    bool ret = true;
    QToolBar* tb = addToolBar("Tool Bar");

    tb->setIconSize(QSize(16, 16));

    ret = ret && initFileToolItem(tb);

    tb->addSeparator();

    ret = ret && initEditToolItem(tb);

    tb->addSeparator();

    ret = ret && initFormatToolItem(tb);

    tb->addSeparator();

    ret = ret && initViewToolItem(tb);

    return ret;
}

bool MainWindow::initStatusBar()
{
    bool ret = true;
    QStatusBar* sb = statusBar();
    QLabel* label = new QLabel("D.T.Software");

    if( label != NULL )
    {
        statusLbl.setMinimumWidth(200);
        statusLbl.setAlignment(Qt::AlignCenter);
        statusLbl.setText("Ln: 1    Col: 1");

        label->setMinimumWidth(200);
        label->setAlignment(Qt::AlignCenter);

        sb->addPermanentWidget(new QLabel());
        sb->addPermanentWidget(&statusLbl);
        sb->addPermanentWidget(label);
    }
    else
    {
        ret = false;
    }

    return ret;
}

bool MainWindow::initMainEditor()
{
    bool ret = true;

    mainEditor.setParent(this);

    connect(&mainEditor, SIGNAL(textChanged()), this, SLOT(onTextChanged()));

    setCentralWidget(&mainEditor);

    return ret;
}

bool MainWindow::initFileMenu(QMenuBar* mb)
{
    QMenu* menu = new QMenu("File(&F)", mb);
    bool ret = (menu != NULL);

    if( ret )
    {
        QAction* action = NULL;

        ret = ret && makeAction(action, menu, "New(&N)", Qt::CTRL + Qt::Key_N);

        if( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onFileNew()));
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Open(&O)...", Qt::CTRL + Qt::Key_O);

        if( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onFileOpen()));
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Save(&S)", Qt::CTRL + Qt::Key_S);

        if( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onFileSave()));
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Save As(&A)...", 0);

        if( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onFileSaveAs()));
            menu->addAction(action);
        }

        menu->addSeparator();

        ret = ret && makeAction(action, menu, "Print(&P)...", Qt::CTRL + Qt::Key_P);

        if( ret )
        {
            menu->addAction(action);
        }

        menu->addSeparator();

        ret = ret && makeAction(action, menu, "Exit(&X)", 0);

        if( ret )
        {
            menu->addAction(action);
        }
    }

    if( ret )
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }

    return ret;
}

bool MainWindow::initEditMenu(QMenuBar* mb)
{
    QMenu* menu = new QMenu("Edit(&E)", mb);
    bool ret = (menu != NULL);

    if( ret )
    {
        QAction* action = NULL;

        ret = ret && makeAction(action, menu, "Undo(&U)", Qt::CTRL + Qt::Key_Z);

        if( ret )
        {
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Redo(&R)...", Qt::CTRL + Qt::Key_Y);

        if( ret )
        {
            menu->addAction(action);
        }

        menu->addSeparator();

        ret = ret && makeAction(action, menu, "Cut(&T)", Qt::CTRL + Qt::Key_X);

        if( ret )
        {
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Copy(&C)...", Qt::CTRL + Qt::Key_C);

        if( ret )
        {
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Paste(&P)...", Qt::CTRL + Qt::Key_V);

        if( ret )
        {
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Delete(&L)", Qt::Key_Delete);

        if( ret )
        {
            menu->addAction(action);
        }

        menu->addSeparator();

        ret = ret && makeAction(action, menu, "Find(&F)...", Qt::CTRL + Qt::Key_F);

        if( ret )
        {
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Replace(&R)...", Qt::CTRL + Qt::Key_H);

        if( ret )
        {
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Goto(&G)...", Qt::CTRL + Qt::Key_G);

        if( ret )
        {
            menu->addAction(action);
        }

        menu->addSeparator();

        ret = ret && makeAction(action, menu, "Select All(&A)", Qt::CTRL + Qt::Key_A);

        if( ret )
        {
            menu->addAction(action);
        }
    }

    if( ret )
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }

    return ret;
}

bool MainWindow::initFormatMenu(QMenuBar* mb)
{
    QMenu* menu = new QMenu("Format(&O)", mb);
    bool ret = (menu != NULL);

    if( ret )
    {
        QAction* action = NULL;

        ret = ret && makeAction(action, menu, "Auto Wrap(&W)", 0);

        if( ret )
        {
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Font(&F)...", 0);

        if( ret )
        {
            menu->addAction(action);
        }
    }

    if( ret )
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }

    return ret;
}

bool MainWindow::initViewMenu(QMenuBar* mb)
{
    QMenu* menu = new QMenu("View(&V)", mb);
    bool ret = (menu != NULL);

    if( ret )
    {
        QAction* action = NULL;

        ret = ret && makeAction(action, menu, "Tool Bar(&T)", 0);

        if( ret )
        {
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "Status Bar(&S)", 0);

        if( ret )
        {
            menu->addAction(action);
        }
    }

    if( ret )
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }

    return ret;
}

bool MainWindow::initHelpMenu(QMenuBar* mb)
{
    QMenu* menu = new QMenu("Help(&H)", mb);
    bool ret = (menu != NULL);

    if( ret )
    {
        QAction* action = NULL;

        ret = ret && makeAction(action, menu, "User Manual", 0);

        if( ret )
        {
            menu->addAction(action);
        }

        ret = ret && makeAction(action, menu, "About NotePad...", 0);

        if( ret )
        {
            menu->addAction(action);
        }
    }

    if( ret )
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }

    return ret;
}

bool MainWindow::initFileToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction* action = NULL;

    ret = ret && makeAction(action, tb, "New", ":/res/pic/new.png");

    if( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onFileNew()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Open", ":/res/pic/open.png");

    if( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onFileOpen()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Save", ":/res/pic/save.png");

    if( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onFileSave()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Save As", ":/res/pic/saveas.png");

    if( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onFileSaveAs()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Print", ":/res/pic/print.png");

    if( ret )
    {
        tb->addAction(action);
    }


    return ret;
}

bool MainWindow::initEditToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction* action = NULL;

    ret = ret && makeAction(action, tb, "Undo", ":/res/pic/undo.png");

    if( ret )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Redo", ":/res/pic/redo.png");

    if( ret )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Cut", ":/res/pic/cut.png");

    if( ret )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Copy", ":/res/pic/copy.png");

    if( ret )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Paste", ":/res/pic/paste.png");

    if( ret )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Find", ":/res/pic/find.png");

    if( ret )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Replace", ":/res/pic/replace.png");

    if( ret )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Goto", ":/res/pic/goto.png");

    if( ret )
    {
        tb->addAction(action);
    }

    return ret;
}

bool MainWindow::initFormatToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction* action = NULL;

    ret = ret && makeAction(action, tb, "Auto Wrap", ":/res/pic/wrap.png");

    if( ret )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Font", ":/res/pic/font.png");

    if( ret )
    {
        tb->addAction(action);
    }

    return ret;
}

bool MainWindow::initViewToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction* action = NULL;

    ret = ret && makeAction(action, tb, "Tool Bar", ":/res/pic/tool.png");

    if( ret )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Status Bar", ":/res/pic/status.png");

    if( ret )
    {
        tb->addAction(action);
    }

    return ret;
}

bool MainWindow::makeAction(QAction*& action, QWidget* parent, QString text, int key)
{
    bool ret = true;

    action = new QAction(text, parent);

    if( action != NULL )
    {
        action->setShortcut(QKeySequence(key));
    }
    else
    {
        ret = false;
    }

    return ret;
}

bool MainWindow::makeAction(QAction*& action, QWidget* parent, QString tip, QString icon)
{
    bool ret = true;

    action = new QAction("", parent);

    if( action != NULL )
    {
        action->setToolTip(tip);
        action->setIcon(QIcon(icon));
    }
    else
    {
        ret = false;
    }

    return ret;
}

MainWindow::~MainWindow()
{
    
}

MainWindowSlots.cpp

#include "MainWindow.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QFile>
#include <QTextStream>
#include <QDebug>

void MainWindow::showErrorMessage(QString message)//显示错误消息对话框
{
    QMessageBox msg(this);

    msg.setWindowTitle("Error");
    msg.setText(message);
    msg.setIcon(QMessageBox::Critical);
    msg.setStandardButtons(QMessageBox::Ok);

    msg.exec();
}

int MainWindow::showQueryMessage(QString message)//显示询问是否保存对话框
{
    QMessageBox msg(this);

    msg.setWindowTitle("Query");
    msg.setText(message);
    msg.setIcon(QMessageBox::Question);
    msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);

    return msg.exec();//返回值为是否保存
}

QString MainWindow::showFileDialog(QFileDialog::AcceptMode mode, QString title)//显示文件对话框
{
    QString ret = "";   //返回选择文件路径
    QFileDialog fd(this);
    QStringList filters;

    filters.append("Text Files (*.txt)");
    filters.append("All Files (*)");

    fd.setWindowTitle(title);
    fd.setAcceptMode(mode);
    fd.setFilters(filters);

    if( mode == QFileDialog::AcceptOpen )//mode == 0
    {
        fd.setFileMode(QFileDialog::ExistingFile);
    }

    if( fd.exec() == QFileDialog::Accepted )
    {
        ret = fd.selectedFiles()[0];
    }

    return ret;
}

void MainWindow::preEditorChange() //是否存在未保存数据并处理
{
    if( m_isTextChanged )//存在未保存数据
    {
        int r = showQueryMessage("Do you want to save the changes to file?");//是否保存?

        switch(r)
        {
        case QMessageBox::Yes:
            saveCurrentData(m_filePath);//保存当前数据
            break;
        case QMessageBox::No:
            m_isTextChanged = false;//不保存,即状态变量false
            break;
        case QMessageBox::Cancel:
            break;
        }
    }
}

void MainWindow::onFileNew()//新建文件
{
    preEditorChange();//是否存在未保存数据?处理

    if( !m_isTextChanged )
    {
        mainEditor.clear();

        setWindowTitle("NotePad - [ New ]");

        m_filePath = "";

        m_isTextChanged = false;
    }
}

void MainWindow::onFileOpen()//文件打开
{
    preEditorChange();//是否存在未保存数据?处理

    if( !m_isTextChanged )//
    {
        QString path = showFileDialog(QFileDialog::AcceptOpen, "Open");//显示文件对话框,返回路径

        if( path != "" )//读取文件内容设为编辑框内容
        {
            QFile file(path);

            if( file.open(QIODevice::ReadOnly | QIODevice::Text) )
            {
                mainEditor.setPlainText(QString(file.readAll()));

                file.close();

                m_filePath = path;//保存数据源

                m_isTextChanged = false;

                setWindowTitle("NotePad - [ " + m_filePath + " ]");
            }
            else
            {
                showErrorMessage(QString("Open file error! \n\n") + "\"" + path + "\"");
            }
        }
    }
}

QString MainWindow::saveCurrentData(QString path)//保存当前数据
{
    QString ret = path;

    if( ret == "" )
    {
        ret = showFileDialog(QFileDialog::AcceptSave, "Save");
    }

    if( ret != "" )//将编辑框内容保存到文件中
    {
        QFile file(ret);

        if( file.open(QIODevice::WriteOnly | QIODevice::Text) )
        {
            QTextStream out(&file);

            out << mainEditor.toPlainText();

            file.close();

            setWindowTitle("NotePad - [ " + ret + " ]");

            m_isTextChanged = false;
        }
        else
        {
            showErrorMessage(QString("Save file error! \n\n") + "\"" + ret + "\"");

            ret = "";
        }
    }

    return ret;
}

void MainWindow::onFileSave()//文件保存
{
    QString path = saveCurrentData(m_filePath);

    if( path != "" )
    {
        m_filePath = path;//保存数据源
    }
}

void MainWindow::onFileSaveAs()//文件另存为
{
    QString path = saveCurrentData();

    if( path != "" )
    {
        m_filePath = path;
    }
}

void MainWindow::onTextChanged()//编辑框内容改变时状态变量置为true
{
    if( !m_isTextChanged )
    {
        setWindowTitle("*" + windowTitle());//未保存标识
    }

    m_isTextChanged = true;
}

main.cpp

#include <QtGui/QApplication>
#include "MainWindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow* w = MainWindow::NewInstance();
    int ret = -1;

    if( w != NULL )
    {
        w->show();

        ret = a.exec();
    }

    delete w;

    return ret;
}

猜你喜欢

转载自blog.csdn.net/qq_39654127/article/details/81506927