目录
开发环境:Qt Creator 3.3.0 Based on Qt 5.4.0
一、界面设计
创建步骤:
新建一个桌面Qt应用的项目文件,项目名称为“TextEdit”,基类选择“QMainWindow”类:
添加资源文件:
说明:由于Qt版本较低,不支持.png文件,所以在此使用的图标文件为.ico文件。
双击 mainwindow.ui 进入设计模式,添加textEdit组件:
在mainwindow.cpp文件中编写添加菜单选项以及工具图标的代码,并与相应槽函数进行连接:
// 菜单栏
QMenu *FileMenu = ui->menuBar->addMenu("文件");
QAction *NewFile = new QAction(QIcon(":/new/prefix1/icon/NewFile.ico"),"新建文件",this); // 创建动作对象
FileMenu->addAction(NewFile); // 将动作添加到菜单中
NewFile->setShortcut(Qt::CTRL|Qt::Key_N); // 添加快捷键
connect(NewFile,SIGNAL(triggered(bool)),this,SLOT(OnNewFile())); // 与槽函数连接
QAction *OpenFile = FileMenu->addAction(QIcon(":/new/prefix1/icon/OpenFile.ico"),"打开文件");
OpenFile->setShortcut(QKeySequence("Ctrl+O"));
connect(OpenFile,SIGNAL(triggered(bool)),this,SLOT(OnOpenFile()));
QAction *Save = FileMenu->addAction(QIcon(":/new/prefix1/icon/SaveFile.ico"),"保存");
Save->setShortcut(tr("Ctrl+S"));
connect(Save,SIGNAL(triggered(bool)),this,SLOT(OnSaveFile()));
QAction *SaveAs = FileMenu->addAction(QIcon(":/new/prefix1/icon/SaveAs.ico"),"另存为");
SaveAs->setShortcut(tr("Ctrl+Shift+S"));
connect(SaveAs,SIGNAL(triggered(bool)),this,SLOT(OnSaveAsFile()));
FileMenu->addSeparator(); // 添加分隔符
QAction *Quit = FileMenu->addAction("退出");
connect(Quit,SIGNAL(triggered(bool)),this,SLOT(OnQuit()));
QMenu *EditMenu = ui->menuBar->addMenu("编辑");
QAction *Undo = EditMenu->addAction(QIcon(""),"撤销");
Undo->setShortcut(tr("Ctrl+Z"));
connect(Undo,SIGNAL(triggered(bool)),this,SLOT(OnUndo()));
EditMenu->addSeparator(); // 添加分隔符
QAction *Cut = EditMenu->addAction(QIcon(":/new/prefix1/icon/Cut.ico"),"剪切");
Cut->setShortcut(tr("Ctrl+X"));
connect(Cut,SIGNAL(triggered(bool)),this,SLOT(OnCut()));
QAction *Copy = EditMenu->addAction(QIcon(":/new/prefix1/icon/Copy.ico"),"复制");
Copy->setShortcut(tr("Ctrl+C"));
connect(Copy,SIGNAL(triggered(bool)),this,SLOT(OnCopy()));
QAction *Paste = EditMenu->addAction(QIcon(":/new/prefix1/icon/Paste.ico"),tr("粘贴"));
Paste->setShortcut(tr("Ctrl+V"));
connect(Paste,SIGNAL(triggered(bool)),this,SLOT(OnPaste()));
EditMenu->addSeparator();
QAction *SelectAll = EditMenu->addAction("全选");
SelectAll->setShortcut(tr("Ctrl+A"));
connect(SelectAll,SIGNAL(triggered(bool)),this,SLOT(OnSelectAll()));
QMenu *ViewMenu = ui->menuBar->addMenu("查看");
QAction *StatusBar = ViewMenu->addAction("状态栏");
StatusBar->setCheckable(true); // 可选状态
StatusBar->setChecked(true); // 初始状态为选中
connect(StatusBar,SIGNAL(triggered(bool)),this,SLOT(OnStatusBar(bool)));
QAction *WordWrap = ViewMenu->addAction("自动换行");
WordWrap->setCheckable(true);
WordWrap->setChecked(false);
connect(WordWrap,SIGNAL(triggered(bool)),this,SLOT(OnWordWrap(bool)));
QAction *ToolBar = ViewMenu->addAction("工具栏");
ToolBar->setCheckable(true);
ToolBar->setChecked(true);
connect(ToolBar,SIGNAL(triggered(bool)),this,SLOT(OnToolBar(bool)));
// 工具栏
ui->mainToolBar->addAction(NewFile);
ui->mainToolBar->addAction(OpenFile);
ui->mainToolBar->addAction(Save);
ui->mainToolBar->addAction(SaveAs);
ui->mainToolBar->addSeparator(); // 添加分隔符
ui->mainToolBar->addAction(Cut);
ui->mainToolBar->addAction(Copy);
ui->mainToolBar->addAction(Paste);
ui->mainToolBar->addSeparator(); // 添加分隔符
槽函数:
private slots:
void OnNewFile(); // 新建文件
void OnOpenFile(); // 打开文件
bool OnSaveFile(); // 保存文件
bool OnSaveAsFile(); // 另存为文件
void OnQuit(); // 退出
void OnUndo(); // 撤销
void OnCut(); // 剪切
void OnCopy(); // 复制
void OnPaste(); // 粘贴
void OnSelectAll(); // 全选
void OnToolBar(bool); // 工具栏
void OnStatusBar(bool); // 状态栏
void OnWordWrap(bool); // 是否自动换行
界面展示:
主界面及工具栏:
文件菜单:
编辑菜单:
查看菜单:
二、功能设计
功能函数:
判断文件是否保存函数:
bool MainWindow::MaybeSave()
{
if(!ui->textEdit->document()->isModified())
return true;
// 创建一个警告对话框对象,返回值为点击的按钮。
const QMessageBox::StandardButton btn = QMessageBox::warning(this,qApp->applicationName(),"是否保存当前文件到"+cur_file+"?", QMessageBox::Save|QMessageBox::Discard|QMessageBox::Cancel);
// 判断用户点击的按钮
switch (btn) {
case QMessageBox::Save:
return OnSaveFile();
break;
case QMessageBox::Cancel:
return false;
default:
break;
}
return true;
}
加载函数:
void MainWindow::LoadFile(const QString &path)
{
QFile file(path);
// 判断文件是否打开成功
if(!file.open(QFile::ReadOnly|QFile::Text))
{
QMessageBox::warning(this,qApp->applicationName(),"无法打开文件!");
return;
}
// 将文件内容加载到输入框中
QTextStream in(&file);
ui->textEdit->setPlainText(in.readAll());
// 保存当前文件地址
cur_file = path;
ui->textEdit->document()->setModified(false);
statusBar()->showMessage("文件打开成功!",2000);
}
保存函数:
bool MainWindow::SaveFile(const QString &path)
{
QSaveFile file(path);
// 以只写与文本方式打开文件
if(file.open(QFile::WriteOnly|QFile::Text))
{
QTextStream out(&file);
out<<ui->textEdit->toPlainText();
if(!file.commit())
{
QMessageBox::warning(this,qApp->applicationName(),"文件保存失败!");
return false;
}
}
else
return false;
// 保存文件路径
cur_file = path;
ui->textEdit->document()->setModified(false);
statusBar()->showMessage("文件保存成功!",2000);
return true;
}
槽函数:
新建文件:
void MainWindow::OnNewFile()
{
if(MaybeSave())
{
ui->textEdit->clear();
cur_file = QString();
ui->textEdit->document()->setModified(false);
statusBar()->showMessage("新建文件成功!",2000);
}
}
打开文件:
void MainWindow::OnOpenFile()
{
// 判断文件是否已经保存
if(MaybeSave())
{
QString fileName = QFileDialog::getOpenFileName(this);
if(!fileName.isEmpty())
LoadFile(fileName);
setWindowTitle(cur_file);
}
}
保存文件:
bool MainWindow::OnSaveFile()
{
// 判断当前文件保存路径是否为空
if(cur_file.isEmpty())
return OnSaveAsFile();
else
return SaveFile(cur_file);
}
文件另存为:
bool MainWindow::OnSaveAsFile()
{
QFileDialog dialog(this);
dialog.setWindowModality(Qt::WindowModal); // 窗口模式
dialog.setAcceptMode(QFileDialog::AcceptSave); // 窗口类型
dialog.setNameFilter("text(*.txt);;所有文件(*.*)"); // 文件类型筛选器
if(dialog.exec() != QDialog::Accepted)
return false;
return SaveFile(dialog.selectedFiles().first());
}
退出:
void MainWindow::OnQuit()
{
// 判断文件是否已经保存
if(MaybeSave())
{
this->close();
}
else
{
// 判断当前文件路径是否为空
if(cur_file.isEmpty())
OnSaveAsFile();
else
SaveFile(cur_file);
this->close();
}
}
撤销:
void MainWindow::OnUndo()
{
// 判断文件是否有可以撤销的操作
if(ui->textEdit->isUndoRedoEnabled())
{
ui->textEdit->undo();
statusBar()->showMessage("撤销成功!",2000);
}
}
剪切:
void MainWindow::OnCut()
{
ui->textEdit->cut();
statusBar()->showMessage("剪切成功!",2000);
}
复制:
void MainWindow::OnCopy()
{
ui->textEdit->copy();
statusBar()->showMessage("复制成功!",2000);
}
粘贴:
void MainWindow::OnPaste()
{
ui->textEdit->paste();
statusBar()->showMessage("粘贴成功!",2000);
}
全选:
void MainWindow::OnSelectAll()
{
ui->textEdit->selectAll();
}
状态栏:
void MainWindow::OnStatusBar(bool flag)
{
// 是否显示状态栏
if(flag)
statusBar()->show();
else
statusBar()->hide();
}
工具栏:
void MainWindow::OnToolBar(bool flag)
{
// 是否打开工具栏
if(flag)
ui->mainToolBar->show();
else
ui->mainToolBar->hide();
}
换行模式:
void MainWindow::OnWordWrap(bool flag)
{
// 是否自动换行
if(flag)
ui->textEdit->setWordWrapMode(QTextOption::WordWrap);
else
ui->textEdit->setWordWrapMode(QTextOption::NoWrap);
}
三、程序打包
1、设置图标
设计或下载一个图标文件,新建C++资源文件,文件配置名称以.rc为后缀:
双击.rc文件,进入编辑模式,添加下面一段代码:
IDI_ICON1 ICON DISCARDABLE "icon/Text.ico"
进入项目的.pro文件,添加下面一段代码:
RC_FILE += icon_config.rc
编译并运行项目,检查图标是否设置成功
2、动态链接库
选择Release版本进行编译:
创建一个新文件夹,将刚编译好的TextEdit.exe文件放入新建的文件夹中:
启动Qt终端,并跳转到.exe文件路径下:
执行下面的命令:
windeployqt TextEdit.exe
此时该程序打包完成,双击.exe文件可以正常执行,但.exe文件必须在该文件夹中。
3、打包
下载、安装并打开软件:
下载链接:https://pan.baidu.com/s/1d2TPSFcVyQKO2DL8bvRssA
提取码:hqyj
--来自百度网盘超级会员V6的分享
整个安装一直下一步即可。
创建一个新脚本:
设置名称版本号、发布者、官网:
配置开始菜单:
直接点击Next:
选择安装包的向导语言:
安装包配置:
直接点击Next:
完成后桌面上出现一个安装包软件,打包完成:
四、完整代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QString cur_file; // 当前文件路径
bool MaybeSave(); // 判断当前文件是否已保存
void LoadFile(const QString &path);
bool SaveFile(const QString &path);
private slots:
void OnNewFile(); // 新建文件
void OnOpenFile(); // 打开文件
bool OnSaveFile(); // 保存文件
bool OnSaveAsFile(); // 另存为文件
void OnQuit(); // 退出
void OnUndo(); // 撤销
void OnCut(); // 剪切
void OnCopy(); // 复制
void OnPaste(); // 粘贴
void OnSelectAll(); // 全选
void OnToolBar(bool); // 工具栏
void OnStatusBar(bool); // 状态栏
void OnWordWrap(bool); // 是否自动换行
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
//#include <QMetaEnum>
#include <QMenu>
#include <QFile>
#include <QToolBar>
#include <QFileDialog>
#include <QMessageBox>
#include <QTextStream>
#include <QSaveFile>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 菜单栏
QMenu *FileMenu = ui->menuBar->addMenu("文件");
QAction *NewFile = new QAction(QIcon(":/new/prefix1/icon/NewFile.ico"),"新建文件",this);
FileMenu->addAction(NewFile);
NewFile->setShortcut(Qt::CTRL|Qt::Key_N);
connect(NewFile,SIGNAL(triggered(bool)),this,SLOT(OnNewFile()));
QAction *OpenFile = FileMenu->addAction(QIcon(":/new/prefix1/icon/OpenFile.ico"),"打开文件");
OpenFile->setShortcut(QKeySequence("Ctrl+O"));
connect(OpenFile,SIGNAL(triggered(bool)),this,SLOT(OnOpenFile()));
QAction *Save = FileMenu->addAction(QIcon(":/new/prefix1/icon/SaveFile.ico"),"保存");
Save->setShortcut(tr("Ctrl+S"));
connect(Save,SIGNAL(triggered(bool)),this,SLOT(OnSaveFile()));
QAction *SaveAs = FileMenu->addAction(QIcon(":/new/prefix1/icon/SaveAs.ico"),"另存为");
SaveAs->setShortcut(tr("Ctrl+Shift+S"));
connect(SaveAs,SIGNAL(triggered(bool)),this,SLOT(OnSaveAsFile()));
FileMenu->addSeparator();
QAction *Quit = FileMenu->addAction("退出");
connect(Quit,SIGNAL(triggered(bool)),this,SLOT(OnQuit()));
QMenu *EditMenu = ui->menuBar->addMenu("编辑");
QAction *Undo = EditMenu->addAction(QIcon(""),"撤销");
Undo->setShortcut(tr("Ctrl+Z"));
connect(Undo,SIGNAL(triggered(bool)),this,SLOT(OnUndo()));
EditMenu->addSeparator();
QAction *Cut = EditMenu->addAction(QIcon(":/new/prefix1/icon/Cut.ico"),"剪切");
Cut->setShortcut(tr("Ctrl+X"));
connect(Cut,SIGNAL(triggered(bool)),this,SLOT(OnCut()));
QAction *Copy = EditMenu->addAction(QIcon(":/new/prefix1/icon/Copy.ico"),"复制");
Copy->setShortcut(tr("Ctrl+C"));
connect(Copy,SIGNAL(triggered(bool)),this,SLOT(OnCopy()));
QAction *Paste = EditMenu->addAction(QIcon(":/new/prefix1/icon/Paste.ico"),tr("粘贴"));
Paste->setShortcut(tr("Ctrl+V"));
connect(Paste,SIGNAL(triggered(bool)),this,SLOT(OnPaste()));
EditMenu->addSeparator();
QAction *SelectAll = EditMenu->addAction("全选");
SelectAll->setShortcut(tr("Ctrl+A"));
connect(SelectAll,SIGNAL(triggered(bool)),this,SLOT(OnSelectAll()));
QMenu *ViewMenu = ui->menuBar->addMenu("查看");
QAction *StatusBar = ViewMenu->addAction("状态栏");
StatusBar->setCheckable(true);
StatusBar->setChecked(true);
connect(StatusBar,SIGNAL(triggered(bool)),this,SLOT(OnStatusBar(bool)));
QAction *WordWrap = ViewMenu->addAction("自动换行");
WordWrap->setCheckable(true);
WordWrap->setChecked(false);
connect(WordWrap,SIGNAL(triggered(bool)),this,SLOT(OnWordWrap(bool)));
QAction *ToolBar = ViewMenu->addAction("工具栏");
ToolBar->setCheckable(true);
ToolBar->setChecked(true);
connect(ToolBar,SIGNAL(triggered(bool)),this,SLOT(OnToolBar(bool)));
// 工具栏
ui->mainToolBar->addAction(NewFile);
ui->mainToolBar->addAction(OpenFile);
ui->mainToolBar->addAction(Save);
ui->mainToolBar->addAction(SaveAs);
ui->mainToolBar->addSeparator(); // 添加分隔符
ui->mainToolBar->addAction(Cut);
ui->mainToolBar->addAction(Copy);
ui->mainToolBar->addAction(Paste);
ui->mainToolBar->addSeparator(); // 添加分隔符
}
void MainWindow::OnNewFile()
{
if(MaybeSave())
{
ui->textEdit->clear();
cur_file = QString();
ui->textEdit->document()->setModified(false);
statusBar()->showMessage("新建文件成功!",2000);
}
}
void MainWindow::OnOpenFile()
{
if(MaybeSave())
{
QString fileName = QFileDialog::getOpenFileName(this);
if(!fileName.isEmpty())
LoadFile(fileName);
setWindowTitle(cur_file);
}
}
bool MainWindow::OnSaveFile()
{
if(cur_file.isEmpty())
return OnSaveAsFile();
else
return SaveFile(cur_file);
}
bool MainWindow::OnSaveAsFile()
{
QFileDialog dialog(this);
dialog.setWindowModality(Qt::WindowModal); // 窗口模式
dialog.setAcceptMode(QFileDialog::AcceptSave); // 窗口类型
dialog.setNameFilter("text(*.txt);;所有文件(*.*)"); // 文件类型筛选器
if(dialog.exec() != QDialog::Accepted)
return false;
return SaveFile(dialog.selectedFiles().first());
}
void MainWindow::OnUndo()
{
if(ui->textEdit->isUndoRedoEnabled())
{
ui->textEdit->undo();
statusBar()->showMessage("撤销成功!",2000);
}
}
void MainWindow::OnQuit()
{
if(MaybeSave())
{
this->close();
}
else
{
if(cur_file.isEmpty())
OnSaveAsFile();
else
SaveFile(cur_file);
this->close();
}
}
void MainWindow::OnCut()
{
ui->textEdit->cut();
statusBar()->showMessage("剪切成功!",2000);
}
void MainWindow::OnCopy()
{
ui->textEdit->copy();
statusBar()->showMessage("复制成功!",2000);
}
void MainWindow::OnPaste()
{
ui->textEdit->paste();
statusBar()->showMessage("粘贴成功!",2000);
}
void MainWindow::OnSelectAll()
{
ui->textEdit->selectAll();
}
void MainWindow::OnStatusBar(bool flag)
{
// 是否显示状态栏
if(flag)
statusBar()->show();
else
statusBar()->hide();
}
void MainWindow::OnWordWrap(bool flag)
{
// 是否自动换行
if(flag)
ui->textEdit->setWordWrapMode(QTextOption::WordWrap);
else
ui->textEdit->setWordWrapMode(QTextOption::NoWrap);
}
void MainWindow::OnToolBar(bool flag)
{
if(flag)
ui->mainToolBar->show();
else
ui->mainToolBar->hide();
}
bool MainWindow::SaveFile(const QString &path)
{
QSaveFile file(path);
if(file.open(QFile::WriteOnly|QFile::Text))
{
QTextStream out(&file);
out<<ui->textEdit->toPlainText();
if(!file.commit())
{
QMessageBox::warning(this,qApp->applicationName(),"文件保存失败!");
return false;
}
}
else
return false;
cur_file = path;
ui->textEdit->document()->setModified(false);
statusBar()->showMessage("文件保存成功!",2000);
return true;
}
bool MainWindow::MaybeSave()
{
if(!ui->textEdit->document()->isModified())
return true;
const QMessageBox::StandardButton btn = QMessageBox::warning(this,qApp->applicationName(),"是否保存当前文件到"+cur_file+"?",
QMessageBox::Save|QMessageBox::Discard|QMessageBox::Cancel);
switch (btn) {
case QMessageBox::Save:
return OnSaveFile();
break;
case QMessageBox::Cancel:
return false;
default:
break;
}
return true;
}
void MainWindow::LoadFile(const QString &path)
{
QFile file(path);
if(!file.open(QFile::ReadOnly|QFile::Text))
{
QMessageBox::warning(this,qApp->applicationName(),"无法打开文件!");
return;
}
QTextStream in(&file);
ui->textEdit->setPlainText(in.readAll());
cur_file = path;
ui->textEdit->document()->setModified(false);
statusBar()->showMessage("文件打开成功!",2000);
}
MainWindow::~MainWindow()
{
delete ui;
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
五、可扩展部分
1. 可以实现多窗口
2. 菜单更加智能:刚开始打开文件时使所有菜单选项不可用,对文本进行编辑后才可进行菜单操作
3. 可以实现窗口设置保存
4. 可以添加自定义右键菜单
5. 在状态栏中显示编辑器中光标所在的行号和列号
六、总结
该项目是一个非常好的Qt入门项目,整体难度不大,主要在于菜单栏与工具栏的槽函数编写,是个非常不错的基础入门项目。还可以在此基础上扩展更多的功能,从而实现一个更加个性化的文本编辑器,满足更多的需求。