1.界面设计
我们通过选用基本的控件来设计出下面的ui界面:

当然我们的效果还要有选项中的图形显示,如下图所示:

这里的图标我们可以通过阿里巴巴图标库获取,然后将其添加到我们的资源文件中即可,因为对于软件图标只能使用ico格式图片,但是阿里巴巴图标库里面并没有提供该图片格式,所以我们可以通过我们前面开发的图片格式转化工具来进行格式的转化。
2.程序详解
我们设计好了界面之后我们就可以开始进行程序的编写了。程序及详解如下:
cpp
void MainWindow::on_textEdit_textChanged()
{
if(fileName.isEmpty())
{
this->setWindowTitle(tr("*无标题 - 记事本"));
}
else
{
this->setWindowTitle(tr("*") + QFileInfo(fileName).fileName() + tr(" - 记事本"));
}
saveflag = true; //textedit没有保存
}
首先我们来编写文本改变的槽函数,但我们像文本框控件中输入了文本后就会进入到该槽函数,该函数的主要功能就是实现在我们输入文本后窗口的标题会多出一个*,表示未被保存。当打开文件改变文本里面的内容后窗口标题则显示出*,同样表示未保存。
cpp
void MainWindow::on_action_new_triggered()
{
if(saveflag)
{
QMessageBox msgBox;
msgBox.setText("记事本");
msgBox.setInformativeText("Do you want to save your changes?");
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
qDebug() << "ret:" <<ret;
switch (ret) {
case QMessageBox::Save:
// Save was clicked
//保存textedit
on_action_save_triggered(); //这里的保存直接调用保存的槽函数即可
break;
case QMessageBox::Discard:
// Don't Save was clicked
//清空textedit
break;
case QMessageBox::Cancel:
// Cancel was clicked
//不做处理
return;
break;
default:
// should never be reached
break;
}
}
ui->textEdit->clear();
fileName.clear(); //清空文件路径名
this->setWindowTitle(tr("无标题 - 记事本")); //再次设置一遍窗口标题,解决新建时的显示问题
saveflag = false;
}
该槽函数的功能是在新建时如果有文本,我们就会提示是否保存通过你的选择来对文本进行操作。我们的提示时通过一个新的窗口进行提示,那么这个是怎么来实现呢,我们看可以通过qt软件里面一个非常强大的功能来找到完成的思路。我们可以通过qt软件里面的搜索功能,搜索到对应的类的详解,如下:


通过阅读官方给我们例程然后修改即可来实现我们想要一个提示窗的功能了,以及选了提示窗对应的处理,我们只需要实现对应分支里面的处理即可。
cpp
void MainWindow::on_action_save_triggered()
{
if(fileName.isEmpty())
{
fileName = QFileDialog::getSaveFileName(this,tr("保存 文件"),".",tr("Files (*.txt);;"));
if(fileName.isEmpty())
{
return;
}
}
qDebug() << "fileName:" << fileName;
QFile file(fileName); //创建一个文件对象
if(!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate))
{
return;
} //以指定方式打开文件
file.write(ui->textEdit->toPlainText().toUtf8()); //将文本编辑器的内容写入到打开的文件中
file.close(); //关闭文件
saveflag = false; //textedit已保存
this->setWindowTitle(QFileInfo(fileName).fileName() + tr(" - 记事本")); //保存完成后更改窗口名
}
这里我们实现的是保存功能,通过获取到文件路径名,然后文件操作的类来操作文件即可实现文件的保存。
cpp
oid MainWindow::on_action_open_triggered()
{
if(saveflag) //在打开之前textedit有改变,没有保存,要先弹窗判断选择是否保存
{
QMessageBox msgBox;
msgBox.setText("记事本");
msgBox.setInformativeText("Do you want to save your changes?");
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
qDebug() << "ret:" <<ret;
switch (ret) {
case QMessageBox::Save:
// Save was clicked
//保存textedit
on_action_save_triggered(); //这里的保存直接调用保存的槽函数即可
break;
case QMessageBox::Discard:
// Don't Save was clicked
//清空textedit
break;
case QMessageBox::Cancel:
// Cancel was clicked
//不做处理
return;
break;
default:
// should never be reached
break;
}
}
fileName = QFileDialog::getOpenFileName(this,tr("打开 文件"),".",tr("Files (*.txt);;")); //获取打开文件路径名
qDebug() << "fileName:" << fileName;
QFile file(fileName);
if(!file.open(QIODevice::ReadWrite | QIODevice::Text))
{
return ;
}
QByteArray data = file.readAll(); //读出打开文件中内容,带编码格式
ui->textEdit->setText(QString(data));
file.close();
this->setWindowTitle(QFileInfo(fileName).fileName() + tr(" - 记事本"));
saveflag = false;
}
这里我们要实现的是打开文件功能,当然如果在打开新的文本文件时我们原来的文本里面有内容没有被保存,我们就会弹出一个提示窗来提示你是否保存,防止原来编辑的文本丢失。我们打开文件的实现也时通过获取到文件路径名,然后通过QFile类来对文件进行操作,因为原来我们打开文件的文本会有这自己的格式,所以我们要采用格式化打开文本,不能将原来文本的格式修改了。所以我们使用了QByteArray来读出里面带编码格式的内容。
cpp
void MainWindow::on_action_saveas_triggered()
{
fileName = QFileDialog::getSaveFileName(this,tr("保存 文件"),".",tr("Files (*.txt);;"));
if(fileName.isEmpty())
{
return;
}
qDebug() << "fileName:" << fileName;
QFile file(fileName); //创建一个文件对象
if(!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate))
{
return;
} //以指定方式打开文件
file.write(ui->textEdit->toPlainText().toUtf8()); //将文本编辑器的内容写入到打开的文件中
file.close(); //关闭文件
saveflag = false; //textedit已保存
this->setWindowTitle(QFileInfo(fileName).fileName() + tr(" - 记事本")); //保存完成后更改窗口名
}
接下来在该函数中我们实现另存为的功能,在另存为中以为以另存所以我们不必判断这个文件是否为空都需要在点击了给控件之后就要实现文件的保存,所以只需要将原来保存文件控件的功能中的判断文件是否为空给去掉即可实现另存为的功能了。
cpp
void MainWindow::on_action_print_triggered()
{
QPrinter printer; //打印机对象
QPrintDialog printDialog(&printer , this);
if (printDialog.exec() == QDialog::Accepted) {
// print ...
ui->textEdit->print(&printer); //将textedit内容输出到打印机中
}
}
这里我们实现打印的功能通过,QPrinter类和QPrintDialog类来实现,具体的实现我们也可以参考官方例程如下:

cpp
void MainWindow::on_action_quit_triggered()
{
this->close(); //关闭窗体
}
接着我们实现退出的控件功能,对于退出来说我们只需要使用close将窗口关闭即可,但是我们要考虑到的是如果我们的记事本中有文本的话,我们就不能直接进行关闭了所以我们要使用qt中的事件来实现关闭之前有内容如何处理的功能程序如下:
cpp
void MainWindow::closeEvent(QCloseEvent *event)
{
if(saveflag)
{
QMessageBox msgBox;
msgBox.setText("记事本");
msgBox.setInformativeText("Do you want to save your changes?");
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
qDebug() << "ret:" <<ret;
switch (ret) {
case QMessageBox::Save:
// Save was clicked
//保存textedit
on_action_save_triggered(); //这里的保存直接调用保存的槽函数即可
event->accept(); //传递事件
break;
case QMessageBox::Discard:
// Don't Save was clicked
//清空textedit
event->accept();
break;
case QMessageBox::Cancel:
// Cancel was clicked
//不做处理
event->ignore(); //忽视事件
break;
default:
// should never be reached
break;
}
}
}
以为该事件函数是继承自父类的,所以我们要在mainwindow中声明出该函数并且重写其功能。这里实现的功能就是在关闭时判断文本内容是否保存,弹出提示窗供我们选择,当我们选择保存时调用前面写的保存槽函数即可,当我们选择不保存时,直接关闭记事本即可。当我们选择取消时我们就要通过ignore来忽视该事件,停止关闭该窗口的事件。
至此我们记事本第一个选项的功能都实现完成了,我们来看看我们记事本中的第二个功能要实现的是什么呢,如图:

接下来我们继续实现第二个选项中的这些功能。
cpp
void MainWindow::on_action_copy_triggered()
{
ui->textEdit->copy(); //复制textedit选中文本
}
void MainWindow::on_action_cut_triggered()
{
ui->textEdit->cut(); //剪切textedit选中文本
}
void MainWindow::on_action_paste_triggered()
{
ui->textEdit->paste(); //粘贴粘贴板中的文本
}
void MainWindow::on_action_redo_triggered()
{
ui->textEdit->redo(); //恢复操作
}
void MainWindow::on_action_undo_triggered()
{
ui->textEdit->undo(); //撤销操作
}
可见对于第二个选项的功能实现我们只需要调用qt给我们提供的函数即可实现。第二选项的实现还是比较简单的,下面我们来实现第三选项:

首先对于字体的设置我们通过查看官方例程即可实现如:

cpp
void MainWindow::on_action_font_triggered()
{
bool ok;
QFont font = QFontDialog::getFont(&ok, QFont("微软雅黑", 10), this);
if (ok) {
// the user clicked OK and font is set to the font the user selected
} else {
// the user canceled the dialog; font is set to the initial
// value, in this case Helvetica [Cronyx], 10
}
qDebug() << "font:" <<font;
ui->textEdit->setFont(font); //设置字体
}
然后我们看粗体斜体和下划线的实现。
cpp
void MainWindow::on_action_blod_triggered(bool checked)
{
qDebug() << "checked:" << checked;
if(checked)
{
ui->textEdit->setFontWeight(QFont::Bold); //设置粗体
}
else
{
ui->textEdit->setFontWeight(QFont::Normal); //设置正常字体
}
}
void MainWindow::on_action_itlic_triggered(bool checked)
{
if(checked)
{
ui->textEdit->setFontItalic(true); //设置斜体
}
else
{
ui->textEdit->setFontItalic(false); //取消斜体
}
}
void MainWindow::on_action_underline_triggered(bool checked)
{
if(checked)
{
ui->textEdit->setFontUnderline(true); //设置下划线
}
else
{
ui->textEdit->setFontUnderline(false); //取消下划线
}
}
我们通过调用qt给出的相关函数也是可以实现出来的。然后就是第四个选项帮助的实现了。我们看里首先看图:

这里我们通过点击帮助可以提供一些关于记事本的版本实现,和Qt的简介,程序如下:
cpp
void MainWindow::on_action_notepad_triggered()
{
QMessageBox::about(this,tr("关于记事本"),tr("我的记事本,基于QT5.15.2 "));
}
void MainWindow::on_action_qt_triggered()
{
QMessageBox::aboutQt(this);
}
最后就是实现我们第一个选项中还没有实习的中英转化的功能了,对于这个功能的实现可以去参考一些定时计数器的中英文转化的实现基本一样,程序如下:
cpp
void MainWindow::on_action_English_triggered(bool checked)
{
QTranslator translator;
qDebug() << "checked:" <<checked;
if(checked)
{
translator.load("translations/en_US.qm"); //将语言转化编译文件装载
QApplication::installTranslator(&translator); //安装一个翻译对象,参数是翻译对象的地址该地址下的文件已经被编译成.qm文件了,将用tr和对象编辑中可以进行语言转化的文字进行转化
ui->retranslateUi(this); //重新初始化ui界面
}
else
{
QApplication::installTranslator(nullptr); //安装一个空的翻译对象,即不翻译,重新初始化后即可显示中文
ui->retranslateUi(this); //重新初始化ui界面
}
}
最后将工程编译打包即可。