Qt: 記事本源代碼


界面編程之實例學習,系統記事本是個極好的參考,初學Delphi及后之c#,皆以記事本為參考,今以Qt學習,亦是如此。

期間搭建開發環境,復習c++知識,尋找模塊對應功能,不一而足;現刻錄其模塊代碼,以做助記,功能接近系統記事本之95%。

學習了Qt事件驅動之信號槽機投、窗體間數據傳遞方法、文件編碼、本地化等功能,然而初接觸,仍不能得心應手。

IDE: VS2015+Qt5.8.0

 

界面如下:

Qt記事本

 

直貼源代碼吧!完成源碼包,附於文后。

1、入口程序(main.cpp):

#pragma execution_character_set("utf-8")

#include <QtWidgets/QApplication>
#include "qtranslator.h"
#include "notepad.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    //對話框類應用中文
    QTranslator user;
    bool ok = user.load("qt_zh_CN.qm", ".");
    a.installTranslator(&user);

    NotePad np;
    if (argc >= 2)
    {
        QString s = QString::fromLocal8Bit(argv[1]);
        np.loadFromFile(s);
    }

    np.show();
    return a.exec();
}

 

2、主模塊(notepad.cpp):

#include <Windows.h>
#include <qfileinfo.h>
#include <qfile.h>
#include <qmimedata.h>
#include <qtextstream.h>
#include <qprinter.h>
#include <qprintdialog.h>
#include <qpagesetupdialog.h>
#include <qfiledialog.h>
#include <qfontdialog.h>
#include <qmessagebox.h>
#include <qtextobject.h>
#include <qdatetime.h>
#include <qsettings.h>

#include "notepad.h"

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

    //searchDialog = new SearchDialog(Q_NULLPTR, ui.textEdit);
    lblStatus = new QLabel();
    lblStatus->setAlignment(Qt::AlignRight);
    statusBar()->addPermanentWidget(lblStatus);

    setActionState();
    initTextEdifUI();
    loadSettings();
}

void NotePad::loadSettings()
{
    //大小&位置
    QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Notepad", QSettings::NativeFormat);
    int x = settings.value("iWindowPosX", 0).toInt();
    int y = settings.value("iWindowPosY", 0).toInt();
    int w = settings.value("iWindowPosDX", 800).toInt();
    int h = settings.value("iWindowPosDY", 600).toInt();
    this->setGeometry(x, y, w, h);
    ui.actWordWrap->setChecked(settings.value("fWrap", true).toBool());
    ui.actStatus->setChecked(settings.value("StatusBar", true).toBool());
    ui.statusBar->setVisible(ui.actStatus->isChecked());
}

void NotePad::saveSettings()
{
    //大小&位置
    QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Notepad", QSettings::NativeFormat);
    settings.setValue("iWindowPosX", this->x());
    settings.setValue("iWindowPosY", this->y());
    settings.setValue("iWindowPosDX", this->width());
    settings.setValue("iWindowPosDY", this->height());
    settings.setValue("fWrap", ui.actWordWrap->isChecked());
    settings.setValue("StatusBar", ui.actStatus->isChecked());
}

void NotePad::setFileName(QString fileName)
{
    this->fileName = fileName;
    ui.textEdit->document()->setModified(false);

    QString shownName;
    if (fileName.isEmpty())
        shownName = tr("未命名");
    else
        shownName = QFileInfo(fileName).fileName();
    setWindowTitle(tr("%1[*] - %2").arg(shownName, tr("記事本")));
    setWindowModified(false);

    lastDir = QFileInfo(fileName).absoluteDir().absolutePath();
}

void NotePad::loadFromFile(QString fileName)
{
    QFileInfo fileInfo(fileName);
    if (!fileInfo.isFile())
        return;

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly))
    {
        QMessageBox::warning(this, tr("提示"), tr("不能打開此文件!"), tr("確定"));
        return;
    }

    setFileName(fileName);
    QTextStream in(&file);
    ui.textEdit->setText(in.readAll());
}

void NotePad::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat("text/uri-list"))
        event->acceptProposedAction();
}

void NotePad::dropEvent(QDropEvent *event)
{
    QList<QUrl> urls = event->mimeData()->urls();
    if (urls.isEmpty())
        return;

    QString fileName = urls.first().toLocalFile();
    if (!fileName.isEmpty())
        loadFromFile(fileName);
}

void NotePad::closeEvent(QCloseEvent * event)
{
    if (confirmSave())
    {
        saveSettings();
        event->accept();
    }
    else
        event->ignore();
}

bool NotePad::confirmSave()
{
    if (!ui.textEdit->document()->isModified())
        return true;

    QMessageBox::StandardButtons sb = QMessageBox::question(this, tr("提示"), tr("是否將更改保存到 %1?").arg(this->windowTitle().replace(tr(" - 記事本"), "")),
        tr("保存(&S)"), tr("不保存(&N)"), tr("取消"));

    switch (sb)
    {
    case 0:
        return saveFile();
    case 1:
        return true;
    case 2:
        return false;
    default:
        return true;
    }
}

bool NotePad::saveFile()
{
    if (this->fileName.isEmpty())
        return saveFileAs();

    return saveFile(this->fileName);
}

bool NotePad::saveFile(QString fileName)
{
    if (!ui.textEdit->document()->isModified())
        return false;

    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text))
    {
        QMessageBox::critical(this, tr("提示"), tr("不能寫入文件!"), tr("確定"));
        return false;
    }

    QTextStream out(&file);
    out << ui.textEdit->toPlainText();
    setFileName(fileName);
    return true;
}

bool NotePad::saveFileAs()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("另存為"),
        lastDir + tr("./未命名.txt"), tr("文本文檔(*.txt);;所有文件(*.*)"));
    if (fileName.isEmpty())
        return false;

    return saveFile(fileName);
}

void NotePad::setActionState()
{
    ui.actUndo->setEnabled(false);
    ui.actCopy->setEnabled(false);
    ui.actCut->setEnabled(false);
    ui.actDelete->setEnabled(false);

    ui.actFind->setEnabled(false);
    ui.actFindNext->setEnabled(false);
    ui.actGoto->setEnabled(false);
}

void NotePad::initTextEdifUI()
{
    QPalette palette = ui.textEdit->palette();
    palette.setColor(QPalette::Highlight, Qt::darkGreen);
    palette.setColor(QPalette::HighlightedText, Qt::white);
    ui.textEdit->setPalette(palette);

    ui.textEdit->setAcceptDrops(false);
    setAcceptDrops(true);
}

//槽函數
void NotePad::slotNew()
{
    if (!confirmSave())
        return;

    ui.textEdit->clear();
    setFileName("");
}

void NotePad::slotOpen()
{
    if (!confirmSave())
        return;

    QString fileName = QFileDialog::getOpenFileName(this, tr("另存為"),
        lastDir, tr("文本文檔(*.txt);;所有文件(*.*)"));
    if (!fileName.isEmpty())
        loadFromFile(fileName);
}

void NotePad::slotSave()
{
    saveFile();
}

void NotePad::slotSaveAs()
{
    saveFileAs();
}

void NotePad::slotPageSetup()
{
    QPrinter printer;
    QPageSetupDialog pageSetUpdlg(&printer, this);
    if (pageSetUpdlg.exec() == QDialog::Accepted)
        printer.setOrientation(QPrinter::Landscape);
    else
        printer.setOrientation(QPrinter::Portrait);
}

void NotePad::slotPrint()
{
    QPrinter printer;
    QString printerName = printer.printerName();
    if (printerName.size() == 0)
        return;

    QPrintDialog dlg(&printer, this);
    if (ui.textEdit->textCursor().hasSelection())
        dlg.addEnabledOption(QAbstractPrintDialog::PrintSelection);
    // 如果在對話框中按下了打印按鈕,則執行打印操作
    if (dlg.exec() == QDialog::Accepted)
        ui.textEdit->print(&printer);
}

void NotePad::slotExit()
{
    this->close();
}

void NotePad::slotUndo()
{
    ui.textEdit->undo();
}

void NotePad::slotCut()
{
    ui.textEdit->cut();
}

void NotePad::slotCopy()
{
    ui.textEdit->copy();
}

void NotePad::slotPaste()
{
    ui.textEdit->paste();
}

void NotePad::slotDelete()
{
    ui.textEdit->textCursor().removeSelectedText();
}

void NotePad::slotFind()
{
    if (replaceDialog != Q_NULLPTR && replaceDialog->isVisible())
    {
        replaceDialog->activateWindow();
        return;
    }

    if (searchDialog == Q_NULLPTR)
        searchDialog = new SearchDialog(this, ui.textEdit);
    searchDialog->show();
    searchDialog->activateWindow();
}

void NotePad::slotFindNext()
{
    if (searchDialog == Q_NULLPTR)
        searchDialog = new SearchDialog(this, ui.textEdit);
    searchDialog->search();
}

void NotePad::slotReplace()
{
    if (searchDialog != Q_NULLPTR && searchDialog->isVisible())
    {
        searchDialog->activateWindow();
        return;
    }

    if (replaceDialog == Q_NULLPTR)
        replaceDialog = new ReplaceDialog(this, ui.textEdit);
    replaceDialog->show();
    replaceDialog->activateWindow();
}

void NotePad::slotGoto()
{
    //跳轉...傳this以此做為其窗主,Modal狀態標題欄閃爍
    GotoDialog gotoDialog(this);
    gotoDialog.setLineNumber(ui.textEdit->textCursor().blockNumber() + 1, ui.textEdit->document()->lineCount());
    if (gotoDialog.exec() == QDialog::Accepted)
    {
        int line = gotoDialog.gotoLine;
        QTextCursor cursor = ui.textEdit->textCursor();
        int position = ui.textEdit->document()->findBlockByNumber(line - 1).position();
        cursor.setPosition(position, QTextCursor::MoveAnchor);
        ui.textEdit->setTextCursor(cursor);
    }
}

void NotePad::slotSelectAll()
{
    ui.textEdit->selectAll();
}

void NotePad::slotDatetime()
{
    QString dateTime = QDateTime::currentDateTime().toString(Qt::SystemLocaleDate);
    ui.textEdit->textCursor().insertText(dateTime);
}

void NotePad::slotWordWrap()
{
    if (ui.actWordWrap->isChecked())
        ui.textEdit->setWordWrapMode(QTextOption::WordWrap);
    else
        ui.textEdit->setWordWrapMode(QTextOption::NoWrap);

    ui.actGoto->setEnabled(!ui.actWordWrap->isChecked());
    ui.actStatus->setEnabled(ui.actWordWrap->isChecked());
    if (!ui.actWordWrap->isChecked())
    {
        if (ui.actStatus->isChecked())
        {
            ui.actStatus->setChecked(false);
            ui.statusBar->setVisible(ui.actStatus->isChecked());
        }
    }
    else if (this->statusChecked)
        ui.actStatus->trigger();
}

void NotePad::slotFont()
{
    bool ok;
    QFont font = QFontDialog::getFont(&ok, ui.textEdit->font());
    if (ok)
        ui.textEdit->setFont(font);
}

void NotePad::slotStatus()
{
    this->statusChecked = ui.actStatus->isChecked();
    ui.statusBar->setVisible(ui.actStatus->isChecked());
}

void NotePad::slotHelp()
{
    QMessageBox::warning(this, tr("提示"), tr("黔驢技窮,搞不定[IHxHelpPane->(\"mshelp://windows/?id=e725b43f-94e4-4410-98e7-cc87ab2739aa\")]"), tr("確定"));

    //HxHelpPane *helpPane = new HxHelpPane();
    //CoInitialize(NULL);
    //IHxHelpPane *helpPane = NULL;
    //HRESULT hr = ::CoCreateInstance(CLSID_HxHelpPane, NULL, CLSCTX_ALL, IID_IHxHelpPane, reinterpret_cast<void**>(&helpPane));
    //if (SUCCEEDED(hr))
    //    helpPane->DisplayTask(BSTR("mshelp://windows/?id=e725b43f-94e4-4410-98e7-cc87ab2739aa"));
}

void NotePad::slotAbout()
{
    QString appPath = QApplication::applicationFilePath();
    HICON icon = ExtractIcon(NULL, appPath.toStdWString().c_str(), 0);
    ShellAbout((HWND)this->winId(), tr("Qt記事本").toStdWString().c_str(), tr("作者:劉景威").toStdWString().c_str(), icon);
}

void NotePad::slotCopyAvailable(bool enabled)
{
    ui.actCopy->setEnabled(enabled);
}

void NotePad::slotCursorPositionChanged()
{
    QTextCursor tc = ui.textEdit->textCursor();
    QString info = tr("第%1行,第%2列  ").arg(tc.blockNumber() + 1).arg(tc.columnNumber());
    lblStatus->setText(info);
}

void NotePad::slotRedoAvailable(bool enabled)
{
}

void NotePad::slotSelectionChanged()
{
    QString selecdedText = ui.textEdit->textCursor().selectedText();
    //ui.actUndo
    ui.actCopy->setEnabled(!selecdedText.isEmpty());
    ui.actCut->setEnabled(!selecdedText.isEmpty());
    ui.actDelete->setEnabled(!selecdedText.isEmpty());
}

void NotePad::slotTextChanged()
{
    slotSelectionChanged();

    QString text = ui.textEdit->toPlainText();
    ui.actFind->setEnabled(text != "");
    ui.actFindNext->setEnabled(text != "");
    ui.actGoto->setEnabled(text != "" && !ui.actWordWrap->isChecked());
}

void NotePad::slotUndoAvailable(bool enabled)
{
    ui.actUndo->setEnabled(enabled);
}

 

3、跳轉模塊(goto.cpp)

#include "qmessagebox.h"
#include "goto.h"

GotoDialog::GotoDialog(QWidget *parent) :
    QDialog(parent)
{
    ui.setupUi(this);
    setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint | Qt::MSWindowsFixedSizeDialogHint);

    ui.label->setBuddy(ui.lineEdit);
    QRegExp regx("[0-9]+$");
    QValidator *validator = new QRegExpValidator(regx, this);
    ui.lineEdit->setValidator(validator);
}

GotoDialog::~GotoDialog()
{
}

void GotoDialog::setLineNumber(int currLine, int maxLineCount)
{
    ui.lineEdit->setText(QString::number(currLine));
    ui.lineEdit->selectAll();
    this->maxLineCount = maxLineCount;
}

void GotoDialog::accept()
{
    QString value = ui.lineEdit->text().trimmed();
    if (value.isEmpty())
    {
        this->showMessage(tr("請輸入要跳到的行數。"));
        return;
    }
    if (value.toInt() > this->maxLineCount)
    {
        this->showMessage(tr("行數超過了總行數。"));
        return;
    }

    this->gotoLine = value.toInt();
    return QDialog::accept();
}

void GotoDialog::showMessage(QString title)
{
    QMessageBox::warning(this, tr("記事本 - 跳行"), title, tr("確定"));
}

 

4、查找功能(search.cpp):

#include "qmessagebox.h"
#include "qtextedit.h"
#include "qtextdocument.h"
#include "search.h"

SearchDialog::SearchDialog(QWidget *parent, QTextEdit *textEdit) :
    QDialog(parent),
    textEdit(textEdit)
{
    ui.setupUi(this);
    setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint | Qt::MSWindowsFixedSizeDialogHint);

    ui.label->setBuddy(ui.lineEdit);
    ui.searchButton->setEnabled(false);
    QObject::connect(ui.searchButton, SIGNAL(clicked()), this, SLOT(search()));
    QObject::connect(ui.lineEdit, &QLineEdit::textChanged, [=]()
    {
        ui.searchButton->setEnabled(ui.lineEdit->text() != "");
    });
}

SearchDialog::~SearchDialog()
{
}

void SearchDialog::activateWindow()
{
    QDialog::activateWindow();

    ui.lineEdit->setText(textEdit->textCursor().selectedText());
    ui.lineEdit->selectAll();
}

//此重載方法實現選擇數據填充,置入上面函數中
//void SearchDialog::show(QString text)
//{
//    QDialog::show();
//    if (text != "")
//        ui.lineEdit->setText(text);
//}

void SearchDialog::search()
{
    QString text = ui.lineEdit->text();
    if (text.isEmpty())
        return;

    QTextDocument::FindFlags findFlags;
    if (ui.cbCaseSensitive->isChecked())
        findFlags = QTextDocument::FindCaseSensitively;
    if (ui.rbUp->isChecked())
        findFlags |= QTextDocument::FindBackward;
    bool found = textEdit->find(text, findFlags);

    if (!found)
        QMessageBox::information(this, tr("記事本"), tr("找不到\"%1\"").arg(text), QMessageBox::Ok);
}

 

5、替換功能(replace.cpp):

#include "qmessagebox.h"
#include "qtextedit.h"
#include "qtextdocument.h"
#include "replace.h"

ReplaceDialog::ReplaceDialog(QWidget *parent, QTextEdit *textEdit) :
    QDialog(parent),
    textEdit(textEdit)
{
    ui.setupUi(this);
    setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint | Qt::MSWindowsFixedSizeDialogHint);

    initDialog();
}

ReplaceDialog::~ReplaceDialog()
{
}

void ReplaceDialog::initDialog()
{
    ui.label->setBuddy(ui.lineEdit);
    ui.lblReplace->setBuddy(ui.replaceEdit);
    ui.searchButton->setEnabled(false);
    ui.replaceButton->setEnabled(false);
    ui.replaceAllButton->setEnabled(false);
    QObject::connect(ui.searchButton, SIGNAL(clicked()), this, SLOT(search()));
    QObject::connect(ui.replaceButton, SIGNAL(clicked()), this, SLOT(replace()));
    QObject::connect(ui.replaceAllButton, SIGNAL(clicked()), this, SLOT(replaceAll()));
    QObject::connect(ui.lineEdit, &QLineEdit::textChanged, [=]()
    {
        ui.searchButton->setEnabled(ui.lineEdit->text() != "");
        ui.replaceButton->setEnabled(ui.lineEdit->text() != "");
        ui.replaceAllButton->setEnabled(ui.lineEdit->text() != "");
    });
}

void ReplaceDialog::activateWindow()
{
    QDialog::activateWindow();

    ui.lineEdit->setText(textEdit->textCursor().selectedText());
    ui.lineEdit->selectAll();
}

bool ReplaceDialog::search(bool showWarn)
{
    QString text = ui.lineEdit->text();
    if (text.isEmpty())
        return false;

    QTextDocument::FindFlags findFlags;
    if (ui.cbCaseSensitive->isChecked())
        findFlags = QTextDocument::FindCaseSensitively;
    bool found = textEdit->find(text, findFlags);

    if (!found && showWarn)
        QMessageBox::information(this, tr("記事本"), tr("找不到\"%1\"").arg(text), QMessageBox::Ok);
    return found;
}

void ReplaceDialog::replace()
{
    bool found = search();
    if (!found)
        return;

    QTextCursor textCursor = textEdit->textCursor();
    QString replaceText = ui.replaceEdit->text();
    textCursor.insertText(replaceText);

    //尋找下一個
    search();
}

void ReplaceDialog::replaceAll()
{
    QString text = ui.lineEdit->text();
    if (text.isEmpty())
        return;

    QTextDocument::FindFlags findFlags;
    if (ui.cbCaseSensitive->isChecked())
        findFlags = QTextDocument::FindCaseSensitively;
    QString replaceText = ui.replaceEdit->text();
    while (textEdit->find(text, findFlags))
    {
        QTextCursor textCursor = textEdit->textCursor();
        textCursor.insertText(replaceText);
    }
    //往回找
    findFlags |= QTextDocument::FindBackward;
    while (textEdit->find(text, findFlags))
    {
        QTextCursor textCursor = textEdit->textCursor();
        textCursor.insertText(replaceText);
    }
}

 

源碼下載:

https://files.cnblogs.com/files/crwy/qt_notepad.rar


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM