首先分析需求,对于一个简单的文本编辑器,起码要实现以下功能和要求:
1. 主窗口菜单栏包括以下功能:新建文本文件、打开文本文件、保存文本文件、文本文件另存为、文本剪切、文本复制和文本粘贴;
2. 具有查找文本功能(通过主窗口菜单选择),设计一个对话框在正在编辑的文本中查找特定字符串;
3. 具有字体设置功能(通过主窗口菜单选择),弹出一个对话框让用户选择字体、尺寸、是否加粗、是否加下划线等字体设置,用户确认后应用到文本编辑区;
4. 当用户准备新建另一个编辑实例时,同时打开或者已保存的文件的内容存在变更时,提示用户是否保存更改。
说实话,这个玩意真心没有什么技术含量,主要就是考查对Qt的常用控件和实用类使用的熟练度、以及信号槽的处理。我来说一下要点:
创建菜单栏使用QMenuBar,打开/保存文件时弹出选择文件/路径对话框用QFileDialog实现,文本编辑区使用QTextEdit实现,复制粘贴和剪切直接调用QTextEdit的成员函数就好;
打开文件时用QTextStream从文件流读入文本字符串,写入文件时也是用它将字符串写入文件流,构造文件路径对象则采用QFile;
弹出查找文段和设置字体的对话框,可以直接采用Qt自带的QInputDialog和QFontDialog实现;
查找文段采用QTextDocument搜索,由于还要实现查找下一个功能,还需要记录当前查找的光标,用QTextCursor实现即可;
设置的字体选项采用QSettings进行持久化保存,下次打开程序时可以直接加载设置以设置默认字体;
记录文件是否变更,这个可以直接定义一个全局字符串变量,在每次文件打开和保存的时候用文本内容更新之,用户欲新建文本时,若当前文本和先前的不同,那么就说明更改了;
最后就是一堆信号槽的设置了,使用connect函数即可,第一个参数是信号发送者,第三个参数是信号接收者(一般为整个窗体的对象),这一点不要搞混淆了。
下面直接上代码,首先是源文件:
#include <QApplication>
#include <QtGui>
#include <QMenuBar>
#include <QFileDialog>
#include <QMessageBox>
#include <QInputDialog>
#include <QFontDialog>
#include <QTextCursor>
#include <QSettings>
#include <QScreen>
#include "QtTextEditor.h"
bool MainWindow::isTextChanged()
{
QString currentText = textEdit1->toPlainText();
return currentText != originalText;
}
void MainWindow::fileNew()
{
if (!textEdit1->toPlainText().isEmpty()) {
if (isTextChanged()) {
QMessageBox::StandardButton reply = QMessageBox::question(nullptr,
"Confirmation", "Do you want to save the changes of original text?", QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
fileSave();
}
}
}
textEdit1->clear();
}
void MainWindow::fileOpen()
{
QFileDialog dialog(this, tr("Open File"));
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilter(tr("Text Files (*.txt);;All Files (*)"));
dialog.setDirectory("");
if (dialog.exec() == QDialog::Accepted) {
QString fileName = dialog.selectedFiles().first();
QFile file(fileName);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
originalText = in.readAll();
textEdit1->setPlainText(originalText);
file.close();
currentFile = fileName;
}
else {
QMessageBox::warning(this, tr("Error"), tr("Could not open file."));
}
}
}
void MainWindow::fileSave()
{
if (currentFile.isEmpty()) {
fileSaveAs();
} else {
QFile file(currentFile);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&file);
originalText = textEdit1->toPlainText();
out << originalText;
file.close();
} else {
QMessageBox::warning(this, tr("Error"), tr("Could not save file."));
}
}
}
void MainWindow::fileSaveAs()
{
QFileDialog dialog(this, tr("Save File As"));
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDefaultSuffix("txt");
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilter(tr("Text Files (*.txt);;All Files (*)"));
dialog.setDirectory("");
if (dialog.exec() == QDialog::Accepted) {
QString fileName = dialog.selectedFiles().first();
currentFile = fileName;
fileSave();
}
}
void MainWindow::fileExit()
{
this->close();
}
void MainWindow::editCut()
{
textEdit1->cut();
}
void MainWindow::editCopy()
{
textEdit1->copy();
}
void MainWindow::editPaste()
{
textEdit1->paste();
}
void MainWindow::searchFind()
{
QString searchString = QInputDialog::getText(this, tr("Find"), tr("Enter search string:"));
if (!searchString.isEmpty()) {
QTextCursor cursor = textEdit1->textCursor();
QTextDocument* document = textEdit1->document();
if (!cursor.isNull() && document) {
QTextCursor searchCursor(document);
while (!searchCursor.isNull() && !searchCursor.atEnd()) {
searchCursor = document->find(searchString, searchCursor);
if (!searchCursor.isNull()) {
if (searchCursor.hasSelection()) {
textEdit1->setTextCursor(searchCursor);
break;
}
}
}
if (searchCursor.isNull() || searchCursor.atEnd()) {
QMessageBox::information(this, tr("Find"), tr("No matching text found."));
}
}
}
}
void MainWindow::searchFindNext()
{
QString searchString = textEdit1->textCursor().selectedText();
if (!searchString.isEmpty()) {
QTextCursor cursor = textEdit1->textCursor();
QTextDocument* document = textEdit1->document();
if (!cursor.isNull() && document) {
QTextCursor searchCursor = cursor;
searchCursor.setPosition(cursor.position() + cursor.selectionStart());
searchCursor = document->find(searchString, searchCursor);
if (!searchCursor.isNull()) {
textEdit1->setTextCursor(searchCursor);
}
else {
QMessageBox::information(this, tr("Find"), tr("No more matching text found."));
}
}
}
}
void MainWindow::formatFont()
{
bool ok;
QFont currentFont = textEdit1->currentFont();
QFont font = QFontDialog::getFont(&ok, currentFont, this, tr("Select Font"));
if (ok) {
QSettings settings("Ernesto", "QtTextEditor");
settings.setValue("font", font.toString());
textEdit1->setFont(font);
}
}
void MainWindow::loadFontSettings()
{
QSettings settings("Ernesto", "QtTextEditor");
QString fontString = settings.value("font").toString();
if (!fontString.isEmpty()) {
QFont font;
font.fromString(fontString);
textEdit1->setFont(font);
}
}
MainWindow::MainWindow()
{
fileMenu = this->menuBar()->addMenu(tr("&File"));
fileNewAct = new QAction(tr("&New"), this);
fileMenu->addAction(fileNewAct);
fileOpenAct = new QAction(tr("&Open..."), this);
fileMenu->addAction(fileOpenAct);
fileSaveAct = new QAction(tr("&Save"), this);
fileMenu->addAction(fileSaveAct);
fileSaveAsAct = new QAction(tr("Save &As..."), this);
fileMenu->addAction(fileSaveAsAct);
fileExitAct = new QAction(tr("E&xit"), this);
fileMenu->addAction(fileExitAct);
editMenu = this->menuBar()->addMenu(tr("&Edit"));
editCutAct = new QAction(tr("Cu&t"), this);
editMenu->addAction(editCutAct);
editCopyAct = new QAction(tr("&Copy"), this);
editMenu->addAction(editCopyAct);
editPasteAct = new QAction(tr("&Paste"), this);
editMenu->addAction(editPasteAct);
searchMenu = this->menuBar()->addMenu(tr("&Search"));
searchFindAct = new QAction(tr("&Find..."), this);
searchMenu->addAction(searchFindAct);
searchFindNextAct = new QAction(tr("Find &Next"), this);
searchMenu->addAction(searchFindNextAct);
formatMenu = this->menuBar()->addMenu(tr("&Format"));
formatFontAct = new QAction(tr("&Font..."), this);
formatMenu->addAction(formatFontAct);
textEdit1 = new QTextEdit;
setCentralWidget(textEdit1);
connect(fileNewAct, SIGNAL(triggered()), this, SLOT(fileNew()));
connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(fileOpen()));
connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(fileSave()));
connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(fileSaveAs()));
connect(fileExitAct, SIGNAL(triggered()), this, SLOT(fileExit()));
connect(editCutAct, SIGNAL(triggered()), this, SLOT(editCut()));
connect(editCopyAct, SIGNAL(triggered()), this, SLOT(editCopy()));
connect(editPasteAct, SIGNAL(triggered()), this, SLOT(editPaste()));
connect(searchFindAct, SIGNAL(triggered()), this, SLOT(searchFind()));
connect(searchFindNextAct, SIGNAL(triggered()), this, SLOT(searchFindNext()));
connect(formatFontAct, SIGNAL(triggered()), this, SLOT(formatFont()));
loadFontSettings();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QCoreApplication::setOrganizationName("Ernesto");
QCoreApplication::setApplicationName("QtTextEditor");
MainWindow mainWin1;
QScreen* screen = QGuiApplication::primaryScreen();
int screenWidth = screen->geometry().width();
int screenHeight = screen->geometry().height();
int windowWidth = screenWidth / 2;
int windowHeight = screenHeight / 2;
int x = (screenWidth - windowWidth) / 2;
int y = (screenHeight - windowHeight) / 2;
mainWin1.setWindowTitle(QObject::tr("Text Editor Sample"));
mainWin1.resize(windowWidth, windowHeight);
mainWin1.move(x, y);
mainWin1.show();
return app.exec();
}
最后是头文件:
#include <QMainWindow>
#include <QMenu>
#include <QAction>
#include <QTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
private slots:
void fileNew();
void fileOpen();
void fileSave();
void fileSaveAs();
void fileExit();
void editCut();
void editCopy();
void editPaste();
void searchFind();
void searchFindNext();
void formatFont();
private:
QString currentFile;
QString originalText;
QMenu *fileMenu;
QAction *fileNewAct;
QAction *fileOpenAct;
QAction *fileSaveAct;
QAction *fileSaveAsAct;
QAction *fileExitAct;
QMenu *editMenu;
QAction *editCutAct;
QAction *editCopyAct;
QAction *editPasteAct;
QMenu *searchMenu;
QAction *searchFindAct;
QAction *searchFindNextAct;
QMenu *formatMenu;
QAction *formatFontAct;
QTextEdit *textEdit1;
bool isTextChanged();
void loadFontSettings();
public:
MainWindow();
};
效果如图所示: