界面编程之实例学习,系统记事本是个极好的参考,初学Delphi及后之c#,皆以记事本为参考,今以Qt学习,亦是如此。

期间搭建开发环境,复习c++知识,寻找模块对应功能,不一而足;现刻录其模块代码,以做助记,功能接近系统记事本之95%。

学习了Qt事件驱动之信号槽机投、窗体间数据传递方法、文件编码、本地化等功能,然而初接触,仍不能得心应手。

IDE: VS2015+Qt5.8.0

界面如下:

直贴源代码吧!完成源码包,附于文后。

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 >= )
{
QString s = QString::fromLocal8Bit(argv[]);
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", ).toInt();
int y = settings.value("iWindowPosY", ).toInt();
int w = settings.value("iWindowPosDX", ).toInt();
int h = settings.value("iWindowPosDY", ).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 :
return saveFile();
case :
return true;
case :
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() == )
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() + , 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 - ).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(), );
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() + ).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

Qt: 记事本源代码的更多相关文章

  1. 23.QT记事本

    描述 主要功能有: 新建,打开,保存,另存为,打印, 编辑,撤销,,拖放,xml配置文件读写,字体更改,查找替换 菜单栏,工具栏,状态栏的实现 如下图所示: 效果如下所示:   源码下载地址: htt ...

  2. 在QtCreater中配置Artistic Style格式化Qt程序源代码!!

    Qt很吸引人,可能是我对Qt开发工具QtCreater不熟悉,只发现里面提供了一个快捷键:"ctrl+i",很多人说这就是格式化代码快捷键,我发现这仅仅是代码缩进,并不是真正意义上 ...

  3. QT 记事本小程序

    //mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <Q ...

  4. Qt记事本,美化版

    主体代码实现 #include "mainwindow.h" #include "ui_mainwindow.h" #include<QMenu> ...

  5. qt creator 源代码中含有中文编译报错

    Tools-Options-Text Editor-Behavior-File Encoding-Default encoding:UTF-8 Tools-Options-Text Editor-Be ...

  6. 记事本源代码 python3

    已实现基本功能,显示行号功能暂时实现不了(后面学会了再加,右下角可以实现定位光标所在行.列) 可能会有些bug 1 from tkinter import * from tkinter.message ...

  7. Qt核心剖析: 寻找 QObject 的源代码

    本来打算把<Qt学习之路>作为一个类似教程的东西,所以就不打算把一些关系到源代码的内容放在那个系列之中啦.因此今天就先来看一个新的开始吧!这个系列估计不会进展很快,因为最近公司里面要做 f ...

  8. QT的三种协议说明

    关于Qt的三种协议以及是否收费,有以下引文: 引文一: 最近一直在学习 Qt.Qt 有两个许可证:LGPL 和商业协议.这两个协议在现在的 Qt 版本中的代码是完全一致的(潜在含义是,Qt 的早期版本 ...

  9. Qt中,当QDockWidget的父窗口是一个不可以拖动的QTabWidget的时候实现拖动的方法

    之前在做有关QDockWidget的内容时候遇到了瓶颈,那就是窗口弹出来之后拖动不了,也不可以放大和缩小,若是弹出来之后设置成了window的flags,也不可以拖动,而且也不是需要的效果. 1.弹出 ...

随机推荐

  1. Spring cloud Eureka 和 Zookeeper 比较

    Eureka       AP Zookeeper CP 好处: 

  2. Django--URL(路由层)

    一.django 静态文件配置 在配置文件中settings.py STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR ...

  3. easyUi弹出window窗口传值与调用父页面的方法,子页面给父页面赋值

    <!-- 父页面 --> <!DOCTYPE html PUBLIC "-/W3C/DTD HTML 4.01 Transitional/EN" "ht ...

  4. vue:vue引入组建的多种写法

    vue的路由组件中,引入模块的两种写法:(@等价于..)死的写法:不是按需加载1:import Index from '@/components/Index'(import Index from '. ...

  5. ReactiveX 学习笔记(4)过滤数据流

    Filtering Observables 本文主题为过滤 Observable 的操作符. 这里的 Observable 实质上是可观察的数据流. RxJava操作符(三)Filtering Deb ...

  6. tar 打包当前目录下文件但不包括该录

    今天想打包一些文件,但是不想把该目录打包进去 比如我想把test目录下文件打个包,安装正常的命令来 tar zcf test.tar.gz test 这样肯定会把test目录也打进去,解压后肯定是te ...

  7. 如何配置windows定时任务

    Windows上配置任务定时执行有两种方法.一是通过控制面板中的界面配置,另外一种是通过schtasks命令配置.如果是简单的定时任务配置(比如每天单次执行)建议选择界面的方式,简洁.直观.易上手.如 ...

  8. webpack 自动发现 entry 的配置和引用方式

    假定我们的项目目录为如下的样子: - root/ - assets/ - app/ - global.js - index/ - index.js - auth/ - login.js - regis ...

  9. [PHP]PHP自定义遍历目录下所有文件的方法

    header('content-type:text/html;charset=utf-8');/** *   方法一:使用readir()遍历目录 */function listDir($dir){  ...

  10. zabbix 监控端口

    监控HTTPD端口的shell #!/bin/bash #2019年4月19日18:: ####### httpd=` netstat -tnlp|grep httpd|awk '{print $4} ...