前言
此文本编辑器开发环境为QT5.12.8,使用QT Creator,这个程序是跟着教程一步步做的,感觉QT将各种函数封装得特别全面,使得可以通过简洁的代码实现复杂的功能,在WindowsAPI上实现与QT同样的功能可能需要额外多出近千行的代码
程序运行结果
从左至右依次有撤回,撤销撤回,新建文件,打开文件,保存,另存为;复制,剪贴,粘贴;加粗,斜体,下划线,选择字体;打印,关于;退出等功能
在本文本编辑器中编辑的文本保存之后用系统自带的记事本查看会是html格式,使文本阅读困难,只有使用本编辑器打开时才会显示正常的文本,并且可以自定义后缀,仅使用此程序打开
项目所有文件
C++QT项目的组成主要是配置文件.pro、头文件.h、源文件.cpp和界面文件.ui,其中源文件由main与窗口组成,若我们后续加入其他窗口也会生成其他的源文件
代码实现
mianwindow.h
这段代码仅提供必要的头文件以及函数在窗口类中的定义
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QFileDialog>
#include <QMessageBox>
#include <QFontDialog>
#if defined(QT_PRINTSUPPORT_LIB)
#include <QtPrintSupport/qtprintsupportglobal.h>
#if QT_CONFIG(printer)
#if QT_CONFIG(printdialog)
#include <QPrintDialog>
#endif
#include <QPrinter>
#endif
#endif
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_Add_new_triggered();
void on_open_file_triggered();
void on_save_file_triggered();
void on_save_as_triggered();
void on_paste_triggered();
void on_cut_triggered();
void on_copy_triggered();
void on_font_triggered();
void on_about_triggered();
void on_undo_triggered();
void on_redo_triggered();
void on_exit_triggered();
void on_print_triggered();
void on_bolder_triggered(bool checked);
void on_italc_triggered(bool checked);
void on_actionunderline_triggered(bool checked);
private:
Ui::MainWindow *ui;
QString currentFile;
};
#endif // MAINWINDOW_H
main.cpp
此段代码仅用作输出窗口
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
各控件主要功能在此段代码中实现,这也是最重要的一段代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setCentralWidget(ui->textEdit);
}
#if !QT_CONFIG(printer)
ui->print->setEnabled(false);
#endif
MainWindow::~MainWindow()
{
delete ui;
}
//新建文件
void MainWindow::on_Add_new_triggered()
{
qDebug() << "start Create New File ... ";
currentFile.clear();
ui->textEdit->setText("");
}
//打开文件
void MainWindow::on_open_file_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this,"打开文件");
QFile file(fileName);
if(!file.open(QIODevice::ReadOnly|QFile::Text)){
QMessageBox::warning(this,"警告","无法打开此文件:"+file.errorString());
return;
}
currentFile = fileName;
setWindowTitle(fileName);
QTextStream in(&file);
QString text = in.readAll();
ui->textEdit->setText(text);
file.close();
}
//保存文件
void MainWindow::on_save_file_triggered()
{
QString fileName;
if(currentFile.isEmpty()){
fileName = QFileDialog::getSaveFileName(this,"保存文件");
currentFile = fileName;
}
else {
fileName = currentFile;
}
QFile file(fileName);
if(!file.open(QIODevice::WriteOnly|QFile::Text)){
QMessageBox::warning(this,"警告","无法保存文件:"+file.errorString());
return;
}
setWindowTitle(fileName);
QTextStream out(&file);
QString text = ui->textEdit->toPlainText();
out << text;
file.close();
}
void MainWindow::on_save_as_triggered()
{
QString fileName = QFileDialog::getSaveFileName(this,"另存文件");
QFile file(fileName);
if(!file.open(QIODevice::WriteOnly|QFile::Text)){
QMessageBox::warning(this,"警告","无法保存文件:"+file.errorString());
return;
}
currentFile = fileName;
setWindowTitle(fileName);
QTextStream out(&file);
QString text = ui->textEdit->toPlainText();
out << text;
file.close();
}
//粘贴
void MainWindow::on_paste_triggered()
{
ui->textEdit->paste();
}
//剪贴
void MainWindow::on_cut_triggered()
{
ui->textEdit->cut();
}
//复制
void MainWindow::on_copy_triggered()
{
ui->textEdit->copy();
}
void MainWindow::on_font_triggered()
{
bool fontSelected;
QFont font = QFontDialog::getFont(&fontSelected,this);
if(fontSelected){
ui->textEdit->setFont(font);
}
}
void MainWindow::on_about_triggered()
{
QMessageBox::about(this,"Xm's Notepad!","Welcome to C++QT!");
}
//撤销
void MainWindow::on_undo_triggered()
{
ui->textEdit->undo();
}
//取消撤销
void MainWindow::on_redo_triggered()
{
ui->textEdit->redo();
}
void MainWindow::on_exit_triggered()
{
exit(1);
}
void MainWindow::on_print_triggered()
{
#if defined (QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
QPrinter printDev;
#if QT_CONFIG(printdialog)
QPrintDialog dialog(&printDev,this);
if(dialog.exec()==QDialog::Rejected)
return;
#endif
ui->textEdit->print(&printDev);
#endif
}
//加粗
void MainWindow::on_bolder_triggered(bool checked)
{
ui->textEdit->setFontWeight(checked?QFont::Bold:QFont::Normal);
}
//斜体
void MainWindow::on_italc_triggered(bool checked)
{
ui->textEdit->setFontItalic(checked);
}
//下划线
void MainWindow::on_actionunderline_triggered(bool checked)
{
ui->textEdit->setFontUnderline(checked);
}
mainwindow.ui
下图是ui的设计界面
此段代码是ui界面的具体实现,事实上,我们在ui的设计界面增减控件时会同步到这个ui文件当中,避免了我们手敲代码
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Notepad</string>
</property>
<property name="windowIcon">
<iconset resource="images.qrc">
<normaloff>:/images/images/pencil.png</normaloff>:/images/images/pencil.png</iconset>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QTextEdit" name="textEdit">
<property name="geometry">
<rect>
<x>20</x>
<y>10</y>
<width>104</width>
<height>71</height>
</rect>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menu">
<property name="title">
<string>文件</string>
</property>
<addaction name="Add_new"/>
<addaction name="open_file"/>
<addaction name="separator"/>
<addaction name="save_file"/>
<addaction name="save_as"/>
<addaction name="separator"/>
<addaction name="print"/>
<addaction name="exit"/>
</widget>
<widget class="QMenu" name="menu_2">
<property name="title">
<string>编辑</string>
</property>
<addaction name="copy"/>
<addaction name="paste"/>
<addaction name="cut"/>
<addaction name="separator"/>
<addaction name="bolder"/>
<addaction name="italc"/>
<addaction name="actionunderline"/>
<addaction name="font"/>
</widget>
<widget class="QMenu" name="menu_3">
<property name="title">
<string>关于</string>
</property>
<addaction name="about"/>
</widget>
<addaction name="menu"/>
<addaction name="menu_2"/>
<addaction name="menu_3"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="undo"/>
<addaction name="redo"/>
<addaction name="Add_new"/>
<addaction name="open_file"/>
<addaction name="save_file"/>
<addaction name="save_as"/>
</widget>
<widget class="QToolBar" name="toolBar_2">
<property name="windowTitle">
<string>toolBar_2</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="paste"/>
<addaction name="cut"/>
<addaction name="copy"/>
</widget>
<widget class="QToolBar" name="toolBar_3">
<property name="windowTitle">
<string>toolBar_3</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="bolder"/>
<addaction name="italc"/>
<addaction name="actionunderline"/>
<addaction name="font"/>
</widget>
<widget class="QToolBar" name="toolBar_4">
<property name="windowTitle">
<string>toolBar_4</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="print"/>
<addaction name="about"/>
</widget>
<widget class="QToolBar" name="toolBar_5">
<property name="windowTitle">
<string>toolBar_5</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="exit"/>
</widget>
<action name="Add_new">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/new.png</normaloff>:/images/images/new.png</iconset>
</property>
<property name="text">
<string>新建文件</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
</property>
</action>
<action name="open_file">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/open.png</normaloff>:/images/images/open.png</iconset>
</property>
<property name="text">
<string>打开文件</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="save_file">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/save.png</normaloff>:/images/images/save.png</iconset>
</property>
<property name="text">
<string>保存文件</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="save_as">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/save_as.png</normaloff>:/images/images/save_as.png</iconset>
</property>
<property name="text">
<string>另存为</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+S</string>
</property>
</action>
<action name="paste">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/paste.png</normaloff>:/images/images/paste.png</iconset>
</property>
<property name="text">
<string>粘贴</string>
</property>
<property name="shortcut">
<string>Ctrl+V</string>
</property>
</action>
<action name="cut">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/cut.png</normaloff>:/images/images/cut.png</iconset>
</property>
<property name="text">
<string>剪贴</string>
</property>
<property name="shortcut">
<string>Ctrl+X</string>
</property>
</action>
<action name="copy">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/copy.png</normaloff>:/images/images/copy.png</iconset>
</property>
<property name="text">
<string>复制</string>
</property>
<property name="shortcut">
<string>Ctrl+C</string>
</property>
</action>
<action name="bolder">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/bold.png</normaloff>:/images/images/bold.png</iconset>
</property>
<property name="text">
<string>加粗</string>
</property>
<property name="shortcut">
<string>Ctrl+B</string>
</property>
</action>
<action name="italc">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/italic.png</normaloff>:/images/images/italic.png</iconset>
</property>
<property name="text">
<string>斜体</string>
</property>
<property name="shortcut">
<string>Ctrl+I</string>
</property>
</action>
<action name="actionunderline">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/underline.png</normaloff>:/images/images/underline.png</iconset>
</property>
<property name="text">
<string>下划线</string>
</property>
<property name="shortcut">
<string>Ctrl+U</string>
</property>
</action>
<action name="font">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/font.png</normaloff>:/images/images/font.png</iconset>
</property>
<property name="text">
<string>字体</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+F</string>
</property>
</action>
<action name="about">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/info.png</normaloff>:/images/images/info.png</iconset>
</property>
<property name="text">
<string>关于</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+I</string>
</property>
</action>
<action name="undo">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/edit_undo.png</normaloff>:/images/images/edit_undo.png</iconset>
</property>
<property name="text">
<string>撤回</string>
</property>
<property name="shortcut">
<string>Ctrl+Z</string>
</property>
</action>
<action name="redo">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/edit_redo.png</normaloff>:/images/images/edit_redo.png</iconset>
</property>
<property name="text">
<string>取消撤回</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+Z</string>
</property>
</action>
<action name="exit">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/exit.png</normaloff>:/images/images/exit.png</iconset>
</property>
<property name="text">
<string>退出</string>
</property>
<property name="toolTip">
<string>退出</string>
</property>
<property name="shortcut">
<string>Esc</string>
</property>
</action>
<action name="print">
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/images/images/print.png</normaloff>:/images/images/print.png</iconset>
</property>
<property name="text">
<string>打印</string>
</property>
<property name="shortcut">
<string>Ctrl+P</string>
</property>
</action>
</widget>
<resources>
<include location="images.qrc"/>
</resources>
<connections/>
</ui>
images.prc
其中时是我导入的一些图标文件
项目构建
在完成上述代码之后,我们就可以开始构建项目了,在此之前我通过QT的功能修改了程序的桌面图标
但是作为应用程序,我们应当使用release版本,基于此构建项目之后可以在文件夹的release目录看见.exe,但是只是这样的话,exe只是一个100多kb的文件,当我们将其拎到没有QT环境的计算机上时就无法运行程序了。不过好在QT有自己的打包程序,我们可以直接windeployqt notepad.exe
对其完成打包,这样会在其文件夹中生成对应的配置文件以便于在没有开发环境的计算机上运行
在完成这一步之后其实就差不多了,可以将这些文件压缩之后发给别人,但好像一次性打包这么多文件又很麻烦,于是我又找了安装包程序
安装包程序会将所有的项目文件打包成为一个可执行文件,同时我还设置了安装包桌面图标,在双击安装包之后就会出现如下界面,我们点击下一步就可以跟着它的提示去一步步安装。其中包括用户协议,自定义安装路径等等
结语
至此一个较为完整的Windows桌面项目就算是完成了,唯一美中不足的就是应用程序的功能稍显欠缺
我也跟着教程搞了一个,好玩嘿嘿嘿