打赏

界面编程之实例学习,系统记事本是个极好的参考,初学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

posted on 2018-06-22 15:47  楚人无衣  阅读(1978)  评论(2编辑  收藏  举报