QT開發(三十一)——NotePad實例開發

QT開發(三十一)——NotePad實例開發

1、界面開發

wKiom1hSSpSiZmhfAABtE76gs-s877.png

    NotePad使用主窗口做爲頂層窗口組件,使用QMainWindow做爲基類,QMainWindow內部封裝了菜單欄、工具欄、中央組件、停靠組件、狀態欄等。QMainWindow內置了佈局管理器,基本的組件佈局以下:數據庫

wKiom1h***LzObjuAAAwa6zVz9o749.png

    使用二階構造模式構建NotePad界面。架構

MainWindow::MainWindow()
{
    resize(800, 600);
}
 
MainWindow::~MainWindow()
{
 
}
 
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;
}

1、菜單欄

QT中提供了預約義的與菜單相關的類組件,菜單欄QMenuBar,下拉菜單QMenu,菜單項QAction。app

wKiom1hSSvTTsVUtAACpyc1o3iY304.png

    QMenuBar* mb = menuBar();框架

    QMenu* menu = new QMenu("File(&F)");編輯器

    QAction *action = new QAction(text, NULL);ide

    menu->addAction(action);函數

    mb->addMenu(menu);工具

    快捷鍵設置佈局

     action->setShortcut(QKeySequence(KEY));字體

    QKeySequence是QT中與快捷鍵相關的類,KEY是QT中表明鍵值的常量。

    NotePad菜單欄共有文件、編輯、格式、查看、幫助五組下拉菜單,每組下拉菜單使用一個函數構建。

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::initFileMenu(QMenuBar *mb)
{
    QMenu *menu = new QMenu("File(&F)");
    bool ret = (menu != NULL);
    if(ret)
    {
        QAction *action = NULL;
        ret = ret && makeAction(action, "New(&N)", Qt::CTRL + Qt::Key_N);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Open(&O)", Qt::CTRL + Qt::Key_O);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Save(&S)", Qt::CTRL + Qt::Key_S);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Save As(&A)", 0);
        if(ret)
        {
            menu->addAction(action);
        }
        menu->addSeparator();
 
        ret = ret && makeAction(action, "Page Setting(&U)", 0);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Print(&P)", Qt::CTRL + Qt::Key_P);
        if(ret)
        {
            menu->addAction(action);
        }
        menu->addSeparator();
 
        ret = ret && makeAction(action, "Exit(&X)", 0);
        if(ret)
        {
            menu->addAction(action);
        }
    }
 
    if(ret)
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }
    return ret;
}
 
bool MainWindow::makeAction(QAction *&action, QString text, int key)
{
    bool ret = true;
    action = new QAction(text, NULL);
    if(action != NULL)
    {
        action->setShortcut(QKeySequence(key));
    }
    else
    {
        ret = false;
    }
    return ret;
}
 
bool MainWindow::initEditMenu(QMenuBar *mb)
{
    QMenu *menu = new QMenu("Edit(&E)", NULL);
    bool ret = (menu != NULL);
    if(ret)
    {
        QAction *action = NULL;
        ret = ret && makeAction(action, "Undo(&U)", Qt::CTRL + Qt::Key_Z);
        if(ret)
        {
            menu->addAction(action);
        }
        menu->addSeparator();
 
        ret = ret && makeAction(action, "Cut(&T)", Qt::CTRL + Qt::Key_X);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Copy(&C)", Qt::CTRL + Qt::Key_C);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Paste(&P)", Qt::CTRL + Qt::Key_V);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Delete(&L)", Qt::Key_Delete);
        if(ret)
        {
            menu->addAction(action);
        }
        menu->addSeparator();
 
        ret = ret && makeAction(action, "Find(&F)", Qt::CTRL + Qt::Key_F);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Find Next(&N)", Qt::Key_F3);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Replace(&R)", Qt::CTRL + Qt::Key_H);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Goto(&G)", Qt::CTRL + Qt::Key_G);
        if(ret)
        {
            menu->addAction(action);
        }
        menu->addSeparator();
 
        ret = ret && makeAction(action, "All(&A)", Qt::CTRL + Qt::Key_A);
        if(ret)
        {
            menu->addAction(action);
        }
 
        ret = ret && makeAction(action, "Time/Date(&D)", Qt::Key_F5);
        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)", NULL);
    bool ret = (menu != NULL);
    if(ret)
    {
        QAction *action = NULL;
        ret = ret && makeAction(action, "Auto Wrap(&W)", 0);
        if(ret)
        {
            menu->addAction(action);
        }
        menu->addSeparator();
 
        ret = ret && makeAction(action, "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)", NULL);
    bool ret = (menu != NULL);
    if(ret)
    {
        QAction *action = NULL;
        ret = ret && makeAction(action, "Status(&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)", NULL);
    bool ret = (menu != NULL);
    if(ret)
    {
        QAction *action = NULL;
        ret = ret && makeAction(action, "Help(&H)", 0);
        if(ret)
        {
            menu->addAction(action);
        }
        menu->addSeparator();
 
        ret = ret && makeAction(action, "About NotePad(&A)", 0);
        if(ret)
        {
            menu->addAction(action);
        }
    }
    if(ret)
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }
    return ret;
}

二、工具欄

工具欄是應用程序中集成各類功能使用快捷方式的區域,不是應用程序必須存在的組件,工具欄的元素能夠是各類窗口組件,但一般以圖標按鈕的方式存在。

QT中提供了預約義的工具欄相關組件,工具欄QToolBar和快捷項QAction。

wKioL1hSSyCghUU7AACF2kKVHlg045.png

    //建立工具欄

    QToolBar *tb = addToolBar("ToolBar");

        //建立工具欄選項

        QAction *action = new QAction("", NULL);

    action->setToolTip(「Open」);

    action->setIcon(QIcon(「/res/pic/open.png」));

        //將工具欄選項加入工具欄

    tb->addAction(action);

    void setFloatable(bool floatable)設置工具欄爲浮動

    void setMovable(bool movable)設置工具欄爲可移動

    void setIconSize(const QSize & iconSize)設置工具欄的圖標大小

    QTollBar組件中能夠加入QT中的任意QWidget組件。

    將菜單欄中的主要經常使用功能添加到工具欄中,按照功能所屬的菜單欄進行分組建立。

bool MainWindow::initToolBar()
{
    bool ret = true;
    QToolBar *tb = addToolBar("ToolBar");
    tb->setMovable(false);
    tb->setIconSize(QSize(16, 16));
    ret = ret && initFileToolItem(tb);//建立文件菜單欄的功能到工具欄
    ret = ret && initEditToolItem(tb);//建立編輯菜單欄到工具欄
    ret = ret && initFormatToolItem(tb);//建立格式菜單欄到工具欄
    ret = ret && initViewToolItem(tb);//建立查看菜單欄到工具欄
 
    return ret;
 
}
bool MainWindow::initFileToolItem(QToolBar *tb)
{
    bool ret = true;
    QAction *action = NULL;
    ret = ret && makeAction(action, "New", ":/res/pic/new.png");
 
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Open", ":/res/pic/open.png");
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Save", ":/res/pic/save.png");
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "SaveAs", ":/res/pic/saveas.png");
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Print", ":/res/pic/print.png");
    if( ret )
    {
        tb->addAction(action);
    }
    tb->addSeparator();
    return ret;
}
 
bool MainWindow::initEditToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction *action = NULL;
    ret = ret && makeAction(action, "Undo", ":/res/pic/undo.png");
 
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Redo", ":/res/pic/redo.png");
 
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Cut", ":/res/pic/cut.png");
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Copy", ":/res/pic/copy.png");
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Paste", ":/res/pic/paste.png");
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Find", ":/res/pic/find.png");
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Replace", ":/res/pic/replace.png");
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Goto", ":/res/pic/goto.png");
    if( ret )
    {
        tb->addAction(action);
    }
    tb->addSeparator();
    return ret;
}
 
bool MainWindow::initFormatToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction *action = NULL;
    ret = ret && makeAction(action, "Auto Wrap", ":/res/pic/wrap.png");
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Font", ":/res/pic/font.png");
    if( ret )
    {
        tb->addAction(action);
    }
    tb->addSeparator();
    return ret;
}
 
bool MainWindow::initViewToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction *action = NULL;
    ret = ret && makeAction(action, "ToolBar", ":/res/pic/tool.png");
 
    if( ret )
    {
        tb->addAction(action);
    }
 
    ret = ret && makeAction(action, "Status", ":/res/pic/status.png");
 
    if( ret )
    {
        tb->addAction(action);
    }
    return ret;
}
 
bool MainWindow::makeAction(QAction*& action, QString tip, QString icon)
{
    bool ret = true;
 
    action = new QAction("", NULL);
 
    if( action != NULL )
    {
        action->setToolTip(tip);
        action->setIcon(QIcon(icon));
    }
    else
    {
        ret = false;
    }
 
    return ret;
}

三、狀態欄

    狀態欄是應用程序中輸出簡要信息的區域,通常位於窗口的底部。狀態欄顯示的消息類型以下:

A、實時消息,如當前程序狀態

B、永久消息,如程序版本,開發機構

C、進度消息,進度顯示

QT中提供了預約義的狀態欄相關組件狀態欄QStatusBar,QStatusBar是容器型組件,能夠是任意組件QWidget的父組件。

wKiom1hSS0ixGRL6AABSeazyFAg432.png

QT狀態欄的通常設計原則:

A、狀態欄左邊區域用於輸出實時消息

B、狀態欄右邊區域用於輸出永久消息

所以,addWidget函數用於在狀態欄左邊區域添加組件,addPermanentWidget函數用於在狀態欄右邊區域添加組件。

bool MainWindow::initStatusBar()
{
    bool ret = true;
    QStatusBar *sb = statusBar();
    QLabel *label = new QLabel("CopyRight @Scorpio Studio");
    if(label != NULL)
    {
        label->setMinimumWidth(150);
        label->setAlignment(Qt::AlignCenter);
        sb->addPermanentWidget(label);
    }
    else
    {
        ret = false;
    }
    return ret;
}

4、中央組件

    中央組件是多行文本編組件,使用QPlainTextEdit組件。

bool MainWindow::initMainEditor()
{
    bool ret = true;
    //設置mainEditor的父組件
    mainEditor.setParent(this);
    //設置中央組件爲mainEditor
    setCentralWidget(&mainEditor);
    //設置mainEditor的背景色爲豆沙綠
    QPalette p = mainEditor.palette();
    p.setColor(QPalette::Base, QColor(204, 232, 207));
    mainEditor.setPalette(p);
    return ret;
}

2、核心功能開發

1、信號與槽函數

    考慮到用戶界面與業務邏輯代碼的分離,槽函數實現須要與界面實現向分離,槽函數在新建MainwWindowSlots.cpp文件中實現,界面文件名稱改成MainWindowUI.cpp。

    菜單欄與工具欄中的QAction對象在鼠標點擊後會發送triggered()信號,經過信號與槽機制能夠實現對QAction對象的操做的處理。

    connect(action, SIGNAL(triggered()), this, SLOT(slotfunction));

    在QAction對象建立的時候鏈接信號與槽函數。

二、文件的存取操做

建立文件對話框:

QString MainWindow::createFileDialog(QFileDialog::AcceptMode mode, QString title)
{
    QString ret = "";
    QFileDialog filedialog(this);
    QStringList filter;
    filter.append("Text Files (*.txt)");
    filter.append("All Files (*.*)");
    filedialog.setWindowTitle(title);
    filedialog.setAcceptMode(mode);
    filedialog.setNameFilters(filter);
    if(mode == QFileDialog::AcceptOpen)
    {
        filedialog.setFileMode(QFileDialog::ExistingFile);
    }
    if(filedialog.exec() == QFileDialog::Accepted)
    {
        ret = filedialog.selectedFiles()[0];
    }
    return ret;
}

錯誤消息提示框:

void MainWindow::showErrorMessage(const QString& title, const QString & text, QMessageBox::StandardButtons buttons)
{
    QMessageBox::critical(this, title, text, buttons);
}

打開文件:

void MainWindow::onFileOpen()
{
    QString path = createFileDialog(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;
            setWindowTitle("NotePad - [" + m_filepath + "]");
        }
        else
        {
            showErrorMessage(QString("Error"), QString("Open file error: " + m_filepath), QMessageBox::Ok);
        }
    }
}

保存文件:

void MainWindow::onFileSave()
{
    if(m_filepath == "")
    {
        m_filepath = createFileDialog(QFileDialog::AcceptSave, "Save");
    }
    if(m_filepath != "")
    {
        QFile file(m_filepath);
        if(file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            QTextStream out(&file);
            out << mainEditor.toPlainText();
            file.close();
            setWindowTitle("NotePad - [ " + m_filepath + " ]");
        }
        else
        {
            showErrorMessage(QString("Error"), QString("Save file error: " + m_filepath), QMessageBox::Ok);
            m_filepath = "";
        }
    }
}

另存文件:

void MainWindow::onFileSaveAs()
{
    QString path = createFileDialog(QFileDialog::AcceptSave, "Save As");
    if(path != "")
    {
        QFile file(path);
        if(file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            QTextStream out(&file);
            out << mainEditor.toPlainText();
            file.close();
            m_filepath = path;
            setWindowTitle("NotePad - [ " + m_filepath + " ]");
        }
        else
        {
            showErrorMessage(QString("Error"), QString("Save as error: " + m_filepath), QMessageBox::Ok);
        }
    }
}

建立新文件:

void MainWindow::onFileNew()
{
    preTextChanged();
    if(!m_isTextChanged)
    {
        mainEditor.clear();
        setWindowTitle("NotePad - [New ]");
        m_filepath = "";
        m_isTextChanged = false;
    }
}

 

三、編輯區的數據交互

    QPlainTextEdit編輯器組件提供了編輯交互功能接口。

    QPlainTextEdit內置的信號以下:

    void textChanged()

    void copyAvailable(bool yes)

    void redoAvailable(bool available)

    void undoAvailable(bool available)

    void cursorPositionChanged()

        void modificationChanged(bool changed)

    QPlainTextEdit內置的槽函數以下:

    void copy()

    void cut()

    void paste()

    void redo()

    void selectAll()

    void undo()

將菜單欄、工具欄中的copy、cut、paste、redo、undo等編輯操做QAction對象的triggered()信號鏈接到QPlainTextEdit對象的相應操做的槽函數,便可實現編輯操做。

    connect(action, SIGNAL(triggered(bool)), &mainEditor, SLOT(undo());

    connect(action, SIGNAL(triggered()), &mainEditor, SLOT(cut()));

    connect(action, SIGNAL(triggered()), &mainEditor, SLOT(copy()));

    connect(action, SIGNAL(triggered()), &mainEditor, SLOT(paste());

工具欄QAction對象的界面狀態的設置

在建立Copy、Undo、Redo的QAction對象時設置爲不可用狀態。

QPlainTextEdit對象的copyAvailableundoAvailableredoAvailable信號鏈接到自定義槽函數。

   connect(&mainEditor, SIGNAL(copyAvailable(bool)), this, SLOT(onCopyAvailable(bool)));

   connect(&mainEditor, SIGNAL(undoAvailable(bool)), this, SLOT(onUndoAvailable(bool)));

   connect(&mainEditor, SIGNAL(redoAvailable(bool)), this, SLOT(onRedoAvailable(bool)));

在自定義槽函數中根據信號的參數available設置QAction對象的狀態

void MainWindow::onCopyAvailable(bool available)
{
    findMenuBarItem("Copy")->setEnabled(available);
    findMenuBarItem("Cut")->setEnabled(available);
    findToolBarItem("Copy")->setEnabled(available);
    findToolBarItem("Cut")->setEnabled(available);
}
 
void MainWindow::onUndoAvailable(bool available)
{
    findMenuBarItem("Undo")->setEnabled(available);
    findToolBarItem("Undo")->setEnabled(available);
}
 
void MainWindow::onRedoAvailable(bool available)
{
    findToolBarItem("Redo")->setEnabled(available);
}

4、拖放支持

拖放一個文件進入窗口時將觸發拖放事件,QWidget對象都能處理拖放事件。

設置窗口支持拖放事件:

在構造函數調用setAcceptDrops(true);

重寫拖放事件的處理函數:

void dragEnterEvent(QDragEnterEvent *event);

void dropEvent(QDropEvent *event);

    默認狀況下,QPlainTextEdit接受來自其餘應用程序拖拽來的文本,把文件名顯示出來。因爲DropEvent是由子組件向父組件傳播的,經過禁止QPlainTextEdit的DropEvent,主窗口能夠獲取DropEventMainWindow中就能夠處理DropEvent

    在MainWwindow構造函數中須要禁止QPlainTextEdit接受DropEvent,容許MainWindow接受DropEvent。

 mainEditor.setAcceptDrops(false);

    setAcceptDrops(true);

重寫事件處理函數:

void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    if(event->mimeData()->hasFormat("text/uri-list"))
    {
        event->acceptProposedAction();
    }
    else
    {
        event->ignore();
    }
}
 
void MainWindow::dropEvent(QDropEvent *event)
{
    if(event->mimeData()->hasUrls())
    {
        QList<QUrl> list = event->mimeData()->urls();
        QString path = list[0].toLocalFile();
        QFileInfo fi(path);
 
        if( fi.isFile() )
        {
            preTextChanged();
 
            if(!m_isTextChanged)
            {
                loadFile(path);
            }
        }
        else
        {
            showMessage(this, QMessageBox::Critical, "Error", "Open file error", QMessageBox::Ok);
        }
    }
    else
    {
        event->ignore();
    }
}

5、打印支持

QTextDocument是表示文本及文本屬性的數據類。能夠設置文本屬性如:排版、字體、標題;獲取文本參數如:行數、文本寬度、文本信息;實現標準操做如:撤銷、重作、查找、打印。

打印功能實現以下:

A、鏈接打印功能的QAction對象到打印功能槽函數

B、在打印槽函數中定義打印對話框

C、根據用戶選擇獲取QPrinter對象

D、使用QTextDocument對象進行打印

void MainWindow::onPrint()
{
    QPrintDialog printdialog(this);
    printdialog.setWindowTitle("Print");
    if(printdialog.exec() == QPrintDialog::Accepted)
    {
        QPrinter *printer = printdialog.printer();
        mainEditor.document()->print(printer);
    }
}

6、光標定位

QPlainTextEdit編輯框內部包含QTextCursor對象。

    [signal] void QPlainTextEdit::cursorPositionChanged()

    QTextCursor QPlainTextEdit::textCursor() const

    int QTextCursor::position() const

 

void MainWindow::onCursorChanged()
{
    int pos = mainEditor.textCursor().position();
    QString text = mainEditor.toPlainText();
    int colum = 0;
    int row = 0;
    int flag = -1;
    for(int i = 0; i < pos; i++)
    {
        if( text[i] == '\n' )
        {
            row++;
            flag = i;
        }
    }
    flag++;
    colum = pos - flag;
    m_status.setText("Line: " + QString::number(row + 1) + "   Colum: " + QString::number(colum + 1));
}


七、查找功能

wKioL1hSTBSBjwGpAAAX0GjlKqA980.png

1)查找對話框的功能:

A、可複用的組件

B、查找文本框中的指定字符串

C、可以指定查找方向

D、支持大小寫敏感查找

2)查找對話框架構設計以下:

wKiom1hSTFTT-MVTAAC2Vcp0A9A441.png

3)查找對話框的界面佈局:

wKioL1hSTHaQykWBAABPxwK3xhs421.png

4)查找功能的實現:

A、獲取當前光標的位置做爲起始點

B、查找目標第一次出現的位置

C、經過目標位置和目標長度在文本框內進行標記

    QString類提供了字符串中查找子串的函數:

    int QString::indexOf(const QString &str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

從指定位置向後查找子串的下標位置

    int QString::lastIndexOf(const QString &str, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

從指定位置向前查找子串的下標位置

    QPlainTextEdit文本框中選中子串的標記

    QTextCursor cursor = m_textedit->textCursor();//獲取當前光標

    cursor.setPosition(index);//設置光標到下標index

    cursor.setPosition(index + target.length(), QTextCursor::KeepAnchor);//設置文本選擇範圍

    m_textedit->setTextCursor(cursor);//設置光標信息到文本

 

5)FindDailog類與MainWindow類的弱耦合關係

經過setPlainTextEdit(pText)設置FindDailog查找對話框指向的文本框,確立了FindDailog類與MainWindow類的弱耦合關係。


8、調色板設置

 //設置mainEditor的背景色爲豆沙綠

    QPalette p = mainEditor.palette();

    p.setColor(QPalette::Base, QColor(204, 232, 207));

    p.setColor(QPalette::Inactive, QPalette::Highlight, p.color(QPalette::Active, QPalette::Highlight));

    p.setColor(QPalette::Inactive, QPalette::HighlightedText, p.color(QPalette::Active, QPalette::HighlightedText));

    mainEditor.setPalette(p);

九、替換功能

wKiom1hSTJey2_K9AAAgzur2pjk641.png

替換對話框的功能:

A、可複用的組件

B、查找文本框中的字符串

C、替換當前查找到的字符串

D、替換全部的字符串

E、點擊關閉按鈕後隱藏

替換對話框的架構設計:

wKioL1hSTLLhEEhnAABDHg-QRtM531.png

    考慮到FindDialog類代碼複用,RepalceDialog類繼承自FindDialog。

替換對話框界面設計:

wKiom1hSTM-TA4Z7AAB2XwxgqYg206.png

 

   m_replacelabel.setText("Replace To:");
    m_replacebutton.setText("Replace");
    m_replaceallbutton.setText("Replace All");
 
    m_layout.removeWidget(&m_check);
    m_layout.removeWidget(&m_radiogroup);
    m_layout.removeWidget(&m_cancelbutton);
 
    m_layout.addWidget(&m_replacelabel, 1, 0);
    m_layout.addWidget(&m_replaceedit, 1, 1);
    m_layout.addWidget(&m_replacebutton, 1, 2);
 
    m_layout.addWidget(&m_check, 2, 0);
    m_layout.addWidget(&m_radiogroup, 2, 1);
    m_layout.addWidget(&m_replaceallbutton, 2, 2);
 
    m_layout.addWidget(&m_cancelbutton, 3, 2);

替換功能的實現:

要實現替換操做,首先須要查找文本框中是否存在的字符串。若是存在字符串,則將鼠標標記的字符串替換。

void ReplaceDialog::onReplace()
{
    QString target = m_edit.text();
    QString to = m_replaceedit.text();
    if((m_textedit != NULL) && (target != NULL) && (to != NULL))
    {
        QString select = m_textedit->textCursor().selectedText();
        if(select == target)
        {
            m_textedit->insertPlainText(to);
        }
        onFind();
    }
}
 
void ReplaceDialog::onRepalceAll()
{
    QString target = m_edit.text();
    QString to = m_replaceedit.text();
    if((m_textedit != NULL) && (target != NULL) && (to != NULL))
    {
        QString text = m_textedit->toPlainText();
        text.replace(target, to, m_check.isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive);
        m_textedit->clear();
        m_textedit->insertPlainText(text);
    }
}

十、工具欄、狀態欄的顯示隱藏

在構建菜單欄、工具欄中ToolBar、StatusBar的QAction對象時,設置QAction對象的屬性。

        action->setCheckable(true);

        action->setChecked(true);

        connect(action, SIGNAL(triggered()), this, SLOT(onViewToolBar()));

槽函數以下:

void MainWindow::onViewStatusBar()
{
    QStatusBar *sb = statusBar();
    bool visible = sb->isVisible();
    sb->setVisible(!visible);
    findToolBarItem("Status Bar")->setChecked(!visible);
    findMenuBarItem("Status Bar")->setChecked(!visible);
}
 
void MainWindow::onViewToolBar()
{
    const QObjectList& list = children();
    for(int i = 0; i < list.count(); i++)
    {
        QToolBar *tb = dynamic_cast<QToolBar*>(list[i]);
        if(tb != NULL)
        {
            bool visible = tb->isVisible();
            tb->setVisible(!visible);
            findMenuBarItem("Tool Bar")->setChecked(!visible);
            findToolBarItem("Tool Bar")->setChecked(!visible);
            break;
        }
    }
}

11、關於對話框

關於對話框用於標識軟件的信息,如:Logo、版本號、開發者信息、版權、聯繫方式、項目信息等。

經典的關於對話框界面設計:

wKioL1hSTPWw_gq1AAAlw9og1PY957.png

AboutDialog::AboutDialog(QWidget* parent)
    :QDialog(parent, Qt::WindowCloseButtonHint), m_logo(this), m_info(this), m_close(this)
{
    QPixmap pm(":/res/pic/dt.png");
    pm = pm.scaled(120,120, Qt::KeepAspectRatio);
    m_logo.setPixmap(pm);
    m_logo.move(20, 20);
    m_logo.resize(120, 120);
 
    QPalette p = m_info.palette();
    p.setColor(QPalette::Active, QPalette::Base, palette().color(QPalette::Active, QPalette::Background));
    p.setColor(QPalette::Inactive, QPalette::Base, palette().color(QPalette::Inactive, QPalette::Background));
    m_info.setPalette(p);
    m_info.move(200, 30);
    m_info.resize(180, 130);
    m_info.setFrameStyle(QPlainTextEdit::NoFrame);
    m_info.setReadOnly(true);
    m_info.insertPlainText("NotePad Project\n\nPlatform: Qt 5.6.2\n\nVersion: 1.0.0\n\nAuthor: Scorpio");
 
    m_close.setText("Close");
    m_close.move(273, 175);
    m_close.resize(100, 30);
 
    setWindowTitle("About NotePad");
    setFixedSize(395, 230);
    connect(&m_close, SIGNAL(clicked()), this, SLOT(onClose()));
}

十二、字體設置

設置文本框中的字體的屬性。

字體設置經過QFontDialog對話框實現

槽函數以下:

void MainWindow::onFormatFont()
{
    bool ok = false;
    QFont font = QFontDialog::getFont(&ok, mainEditor.font(), this);
    if(ok)
    {
        mainEditor.setFont(font);
    }
}

13、換行

QPlainTextEdit支持換行操做。在菜單欄、工具欄建立QAction對象時設置屬性。

       action->setCheckable(true);

        action->setChecked(true);

        connect(action, SIGNAL(triggered()), this, SLOT(onFormatWrap()));

槽函數以下:

void MainWindow::onFormatWrap()
{
    QPlainTextEdit::LineWrapMode mode = mainEditor.lineWrapMode();
    if(mode == QPlainTextEdit::NoWrap)
    {
        mainEditor.setLineWrapMode(QPlainTextEdit::WidgetWidth);
        findMenuBarItem("Auto Wrap")->setChecked(true);
        findToolBarItem("Auto Wrap")->setChecked(true);
    }
    else
    {
        mainEditor.setLineWrapMode(QPlainTextEdit::NoWrap);
        findMenuBarItem("Auto Wrap")->setChecked(false);
        findToolBarItem("Auto Wrap")->setChecked(false);
    }
}

14、幫助文檔

    QDesktopServices提供了一系列桌面開發的服務接口。

    經過QDesktopServices的成員函數打開幫助文檔。

    [static] bool QDesktopServices::openUrl(const QUrl &url)

打開網頁:

    QDesktopServices::openUrl(QUrl("http://9291927.blog.51cto.com/"));

打開文檔:

    QDesktopServices::openUrl(QUrl("file:///C:/Documents and Settings/All Users/Desktop/help.pdf"));

 

15、程序配置文件

程序狀態的保存能夠經過在程序退出前保存程序狀態參數到文件(數據庫),程序啓動時從配置文件讀出狀態參數並恢復。

程序狀態參數的存儲方式:

A、文本文件格式(XML、Json等)

B、輕量級數據庫(Access、SQLite等)

C、二進制文件格式

經過二進制數據流將狀態參數直接存儲帶文件中。

Appconfig.h文件:

#ifndef APPCONFIG_H
#define APPCONFIG_H
 
#include <QObject>
#include <QFont>
#include <QFile>
#include <QDataStream>
#include <QApplication>
 
class AppConfig : public QObject
{
    Q_OBJECT
public:
    explicit AppConfig(QObject *parent = 0);
    explicit AppConfig(QFont editorfont, bool isautowrap, bool istoolbarvisible, bool isstatusbarvisible, QObject *parent = 0);
    bool store();
    QFont editorFont();
    bool isAutoWrap();
    bool isToolBarVisible();
    bool isStatusBarVisible();
    bool isValid();
private:
    bool restore();
private:
    QFont m_editorFont;
    bool m_isAutoWrap;
    bool m_isToolBarVisible;
    bool m_isStatusBarVisible;
 
    bool m_isValid;
};
#endif // APPCONFIG_H

Appconfig.cpp文件:

#include "AppConfig.h"
 
AppConfig::AppConfig(QObject *parent) : QObject(parent)
{
    m_isValid = restore();
}
 
AppConfig::AppConfig(QFont editorfont, bool isautowrap, bool istoolbarvisible, bool isstatusbarvisible, QObject *parent)
{
    m_editorFont = editorfont;
    m_isAutoWrap = isautowrap;
    m_isToolBarVisible = istoolbarvisible;
    m_isStatusBarVisible = isstatusbarvisible;
    m_isValid = true;
}
 
QFont AppConfig::editorFont()
{
    return m_editorFont;
}
 
bool AppConfig::isAutoWrap()
{
    return m_isAutoWrap;
}
 
bool AppConfig::isStatusBarVisible()
{
    return m_isStatusBarVisible;
}
 
bool AppConfig::isToolBarVisible()
{
    return m_isToolBarVisible;
}
 
bool AppConfig::isValid()
{
    return m_isValid;
}
 
bool AppConfig::store()
{
    bool ret = true;
    QFile file(QApplication::applicationDirPath() + "/config.dat");
    if(file.open(QIODevice::WriteOnly))
    {
        QDataStream out(&file);
        out.setVersion(QDataStream::Qt_5_6);
        out << m_editorFont;
        out << m_isAutoWrap;
        out << m_isToolBarVisible;
        out << m_isStatusBarVisible;
        file.close();
    }
    else
    {
        ret = false;
    }
    return ret;
}
 
bool AppConfig::restore()
{
    bool ret = true;
    QFile file(QApplication::applicationDirPath() + "/config.dat");
    if(file.open(QIODevice::ReadOnly))
    {
        QDataStream in(&file);
        in.setVersion(QDataStream::Qt_5_6);
 
        in >> m_editorFont;
        in >> m_isAutoWrap;
        in >> m_isToolBarVisible;
        in >> m_isStatusBarVisible;
        file.close();
    }
    else
    {
        ret = false;
    }
    return ret;
}

從配置文件的讀取狀態參數恢復程序狀態在構造函數中:

bool MainWindow::construct()
{
    bool ret = true;
 
    AppConfig config;
 
    ret = ret && initMenuBar();
    ret = ret && initToolBar();
    ret = ret && initStatusBar();
    ret = ret && initMainEditor();
 
    if(config.isValid())
    {
        mainEditor.setFont(config.editorFont());
        if(!config.isAutoWrap())
        {
            mainEditor.setLineWrapMode(QPlainTextEdit::NoWrap);
            findToolBarItem("Auto Wrap")->setCheckable(false);
            findMenuBarItem("Auto Wrap")->setChecked(false);
        }
        if(!config.isToolBarVisible())
        {
            toolBar()->setVisible(false);
            findMenuBarItem("Tool Bar")->setChecked(false);
            findToolBarItem("Tool Bar")->setChecked(false);
        }
        if(!config.isStatusBarVisible())
        {
            statusBar()->setVisible(false);
            findMenuBarItem("Status Bar")->setChecked(false);
            findToolBarItem("Status Bar")->setChecked(false);
        }
    }
    return ret;
}

狀態參數保存到配置文件在析構函數中:

MainWindow::~MainWindow()
{
    QFont font = mainEditor.font();
    bool isautowrap = (mainEditor.lineWrapMode() == QPlainTextEdit::WidgetWidth);
    bool istoolbarvisible = (findMenuBarItem("Tool Bar")->isChecked() && findToolBarItem("Tool Bar")->isChecked());
    bool isstatusbarvisible = (findMenuBarItem("Status Bar")->isChecked() && findToolBarItem("Status Bar")->isChecked());
 
    AppConfig config(font, isautowrap, istoolbarvisible, isstatusbarvisible);
    config.store();
}

3、源碼

開發環境QT 5.6

源碼見附件:NotePad.zip

相關文章
相關標籤/搜索