微软公司的Office Word软件是一个通用的功能强大的字处理软件,本项目采用Qt5参照Word开发一个类似的文字处理软件,并添加了如多窗口同时处理等功能。
计划本软件的开发分为下几个阶段进行。
(1)界面设计开发。
包括主窗口程序框架的建立,菜单设计,工具栏设计,工具按钮和状态栏的帮助提示文本,多个文档子窗口的管理和控制等。
(2)文本编辑功能实现。
主要包括文件的建立、打开和保存,文本的剪切、复制和粘贴,操作撤销和恢复等这些最基本的文档编辑功能。
(3)排版美化功能实现。
包括字体选择,字形、字号和文字颜色的设置,文档段落标号和编号的添加,段落对齐方式设置等功能实现。
(4)其他功能的添加
如子窗口背景可显示图片,在进行文字编辑是可自动播放舒缓的音乐等趣味功能。
(5)后期的维护与修饰
- 界面设计开发
菜单系统包括主菜单、菜单项和子菜单三级。部分采用在.ui文件中设计,部分通过代码手动设计(格式与窗口)。
效果图:
菜单运行显示效果示例:
菜单功能项图标:
2.文本编辑功能实现
代码包含第一阶段界面开发:
关于ui文件的使用:
效果图:
3.排版美化功能实现。
在实现功能的基础上我们增加了背景界面背景美化
效果图:
4.其他功能的添加
在帮助菜单栏中添加了一个音乐播放的按钮
效果图:
代码如下
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include"newwindow.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class QMdiArea;
class EditWindow;
class sound;
class QComboBox;
class QFrontComboBox;
class QFontComboBox;
class QMdiSubWindow;
class QSignalMapper;
class FontSize;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
void createActionsandMenus();//创建一级菜单
void createActions(); //创建二级菜单
void createToolBars();//创建工具栏
void paintEvent(QPaintEvent *);
QMdiSubWindow *isAlreadyOpen(const QString &fileName);//与fileOPen()配合 判断文件是否已经打开
~MainWindow();
private:
Ui::MainWindow *ui;
QMdiArea*mdiArea;//为了创建多窗体应用程序框架
QMenu *formatMenu,*fontMenu,*alignMenu; //字体菜单指针
QMenu *windowMenu; //窗口菜单指针
QAction *helpAct;
QAction *bold,*italic,*underline,*color; //字体二级菜单指针
QAction *leftAlign,*center,*rightAlign,*justify;//段落二级菜单指针
QAction *closeAct,*closeAllAct,*tileAct ,*cascadeAct ,*nextAct ,*previousAct,*separatorAct;//窗口二级菜单指针
QToolBar *fileToolBar,*editToolBar,*formatToolBar,*comboToolBar;
QComboBox*comboStyle,*comboSize;
QFrontComboBox *comboFront;
QFontComboBox *comboFont;
EditWindow *activeEditwindow();//用来寻找活动窗口
QSignalMapper *windowMapper;
newWindow *win;
FontSize * mycombo;
protected:
void closeEvent(QCloseEvent *event);
private slots:
void setFunctionState();
void fileNew();
void fileOpen();
void fileSave();
void fileSaveAs();
void filePrint();
void undo();
void redo();
void cut();
void copy();
void paste();
void Bold();
void Italic();
void Underline();
void Align(QAction *a);
void textStyle(int styleIndex);
void textFamily(const QString &f);
void textSize(const QString &p);
void Color();
void enableText();
void createStatusBar();
void setActiveSubWindow(QWidget *window);
void openNewWindow();
void updateWindowMenu();
// void colorChanged(const QColor &c);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include<QString>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QtWidgets>
#include"editwindow.h"
#include<QFileDialog>
#include<QPainter>
#include<QPrintDialog>
#include"fontsize.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//主窗口基础配置
setWindowIcon(QIcon(":/images/logo.jpg"));
move(200,150);
resize(800,500);
setWindowTitle(QString("QT Version Word"));
//创建多窗体应用程序框架
mdiArea=new QMdiArea;
mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);//设置子窗口过多时主窗口出现滚动条
mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
setCentralWidget(mdiArea);//将子窗口设置为中心窗口部件
connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)),this, SLOT(setFunctionState()));
createActionsandMenus();
createToolBars();//创建工具栏
statusBar()->showMessage(tr("就绪"));
setFunctionState();//初始按钮不可用
windowMapper=new QSignalMapper(this);//为窗口->子窗口列表 设置信号映射
connect(windowMapper, SIGNAL(mapped(QWidget*)),this, SLOT(setActiveSubWindow(QWidget*)));//mapped函数执行
}
void MainWindow::createActionsandMenus(){
//文件 一级菜单栏已通过设计师界面设置
//编辑 一级菜单栏已通过设计师界面设置
//文件 二级菜单栏已通过设计师界面设置
connect(ui->actionnew, SIGNAL(triggered()), this, SLOT(fileNew()));//点击新建创建窗口
ui->actionnew->setShortcuts(QKeySequence::New);
connect(ui->actionopen, SIGNAL(triggered()), this, SLOT(fileOpen()));//点击打开 打开文件
ui->actionopen->setShortcuts(QKeySequence::Open);
connect(ui->actionsave, SIGNAL(triggered()), this, SLOT(fileSave()));//点击保存保存文件
ui->actionsave->setShortcuts(QKeySequence::Save);
connect(ui->actionsaveAs, SIGNAL(triggered()), this, SLOT(fileSaveAs()));//
ui->actionsaveAs->setShortcuts(QKeySequence::SaveAs);
connect(ui->actionprint, SIGNAL(triggered()), this, SLOT(filePrint()));//
ui->actionprint->setShortcuts(QKeySequence::Print);
connect(ui->actionexit, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));//QApplication自带函数
//编辑 二级菜单栏已通过设计师界面设置
connect(ui->actionundo, SIGNAL(triggered()), this, SLOT(undo()));//撤回
ui->actionundo->setShortcut(QKeySequence::Undo);
connect(ui->actionredo, SIGNAL(triggered()), this, SLOT(redo()));//重做
ui->actionredo->setShortcut(QKeySequence::Redo);
connect(ui->actioncut, SIGNAL(triggered()), this, SLOT(cut()));// 剪切
ui->actioncut->setShortcuts(QKeySequence::Cut);
connect(ui->actioncopy, SIGNAL(triggered()), this, SLOT(copy()));//复制
ui->actioncopy->setShortcuts(QKeySequence::Copy);
connect(ui->actionpaste, SIGNAL(triggered()), this, SLOT(paste()));//粘贴
ui->actionpaste->setShortcuts(QKeySequence::Paste);
//格式 二级菜单栏设置
formatMenu = ui->menubar->addMenu("格式");
fontMenu = formatMenu->addMenu(QString("字体")); //字体 子菜单
alignMenu = formatMenu->addMenu(QString("段落")); //段落 子菜单
bold = new QAction(QIcon(":/images/textbold.png"),QString("加粗"), this);
bold->setCheckable(true);
bold->setShortcut(Qt::CTRL + Qt::Key_B);
bold->setToolTip("加粗");
bold->setStatusTip(QString("将所选文字加粗"));
QFont boldfront;
boldfront.setBold(true);
bold->setFont(boldfront);
fontMenu->addAction(bold);
connect(bold, SIGNAL(triggered()), this, SLOT(Bold()));
italic = new QAction(QIcon( ":/images/textitalic.png"),QString("倾斜"), this);
italic->setCheckable(true);
italic->setShortcut(Qt::CTRL + Qt::Key_I);
italic->setToolTip("倾斜");
italic->setStatusTip(QString("将所选文字用斜体显示"));
QFont italicfront;
italicfront.setItalic(true);
italic->setFont(italicfront);
fontMenu->addAction(italic);
connect(italic, SIGNAL(triggered()), this, SLOT(Italic()));
underline = new QAction(QIcon( ":/images/textunder.png"),QString("下划线"), this);
underline->setCheckable(true);
underline->setShortcut(Qt::CTRL + Qt::Key_U);
underline->setToolTip("下划线");
underline->setStatusTip(QString("给所选文字加下划线"));
QFont underlinefront;
underlinefront.setUnderline(true);
underline->setFont(underlinefront);
fontMenu->addAction(underline);
connect(underline, SIGNAL(triggered()), this, SLOT(Underline()));
//利用动作组使得格式->段落下的动作只能选择一个
QActionGroup *grp = new QActionGroup(this);
connect(grp, SIGNAL(triggered(QAction*)), this, SLOT(Align(QAction*)));
leftAlign = new QAction(QIcon(":/images/textleft.png"),QString("左对齐"), grp);
leftAlign->setShortcut(Qt::CTRL + Qt::Key_L);
leftAlign->setCheckable(true);
leftAlign->setToolTip("左对齐");
leftAlign->setStatusTip(QString("将文字左对齐"));
alignMenu->addAction(leftAlign);
center = new QAction(QIcon( ":/images/textcenter.png"),QString("居中"), grp);
center->setShortcut(Qt::CTRL + Qt::Key_E);
center->setCheckable(true);
center->setToolTip("居中");
center->setStatusTip(QString("将文字居中对齐"));
alignMenu->addAction(center);
rightAlign = new QAction(QIcon(":/images/textright.png"),QString("右对齐"), grp);
rightAlign->setShortcut(Qt::CTRL + Qt::Key_R);
rightAlign->setCheckable(true);
rightAlign->setToolTip("右对齐");
rightAlign->setStatusTip(QString("将文字右对齐"));
alignMenu->addAction(rightAlign);
justify = new QAction(QIcon( ":/images/textjustify.png"),QString("两端对齐"), grp);
justify->setShortcut(Qt::CTRL + Qt::Key_J);
justify->setCheckable(true);
justify->setToolTip("两端对齐");
justify->setStatusTip(QString("将文字左右两端同时对齐,在文档有多行时才会起作用"));
alignMenu->addAction(justify);
QPixmap pix(16, 16);
pix.fill(Qt::red);
color = new QAction(QIcon( ":/images/color.jpg"),QString("颜色..."), this);
color->setToolTip("颜色");
color->setStatusTip(QString("设置文字颜色"));
formatMenu->addAction(color);
connect(color, SIGNAL(triggered()), this, SLOT(Color()));
//窗口 二级菜单栏设置
//窗口 一级菜单栏设置
windowMenu = ui->menubar->addMenu("窗口");
closeAct = new QAction(tr("关闭(&O)"), this);
closeAct->setStatusTip("关闭当前子窗口");
connect(closeAct, SIGNAL(triggered()),mdiArea, SLOT(closeActiveSubWindow()));
closeAllAct =new QAction(tr("关闭所有(&A)"), this);
closeAllAct->setStatusTip("关闭所有子窗口");
connect(closeAllAct, SIGNAL(triggered()),mdiArea, SLOT(closeAllSubWindows()));
windowMenu->addSeparator();
tileAct = new QAction(tr("平铺(&T)"), this);
tileAct->setStatusTip("平铺子窗口");
connect(tileAct, SIGNAL(triggered()), mdiArea, SLOT(tileSubWindows()));
cascadeAct = new QAction(tr("层叠(&C)"), this);
cascadeAct->setStatusTip("层叠子窗口");
connect(cascadeAct, SIGNAL(triggered()), mdiArea, SLOT(cascadeSubWindows()));
windowMenu->addSeparator();
nextAct = new QAction(tr("下一个(&X)"), this);
nextAct->setShortcuts(QKeySequence::NextChild);
nextAct->setStatusTip("切换到下一个子窗口");
connect(nextAct, SIGNAL(triggered()),mdiArea, SLOT(activateNextSubWindow()));
previousAct =new QAction(tr("前一个(&V)"), this);
previousAct->setShortcuts(QKeySequence::PreviousChild);
previousAct->setStatusTip("切换到上一个子窗口");
connect(previousAct, SIGNAL(triggered()),mdiArea, SLOT(activatePreviousSubWindow()));
separatorAct = new QAction(this);
separatorAct->setSeparator(true);
updateWindowMenu();
connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu()));
menuBar()->addSeparator();
helpAct = ui->menubar->addAction("帮助");
connect(helpAct,SIGNAL(triggered()),this,SLOT(openNewWindow()));
}
void MainWindow::createToolBars(){// 创建工具栏
fileToolBar=addToolBar(QString("文件"));
fileToolBar->addAction(ui->actionnew);
fileToolBar->addAction(ui->actionopen);
fileToolBar->addAction(ui->actionsave);
fileToolBar->addSeparator();
fileToolBar->addAction(ui->actionprint);
editToolBar=addToolBar(QString("编辑"));
editToolBar->addAction(ui->actionundo);
editToolBar->addAction(ui->actionredo);
editToolBar->addSeparator();
editToolBar->addAction(ui->actioncut);
editToolBar->addAction(ui->actioncopy);
editToolBar->addAction(ui->actionpaste);
formatToolBar = addToolBar(tr("格式"));
formatToolBar->addAction(bold);
formatToolBar->addAction(italic);
formatToolBar->addAction(underline);
formatToolBar->addSeparator();
formatToolBar->addAction(leftAlign);
formatToolBar->addAction(center);
formatToolBar->addAction(rightAlign);
formatToolBar->addAction(justify);
formatToolBar->addSeparator();
formatToolBar->addAction(color);
addToolBarBreak(Qt::TopToolBarArea); //使这个工具条在界面上另起一行显示
comboToolBar = addToolBar(tr("组合选择"));
comboStyle = new QComboBox();
comboToolBar->addWidget(comboStyle);
// comboStyle->addItem("标准");
comboStyle->addItem("项目符号 (●)");
comboStyle->addItem("项目符号 (○)");
comboStyle->addItem("项目符号 (■)");
comboStyle->addItem("编号 (⒈⒉⒊)");
comboStyle->addItem("编号 ( a.b.c.)");
comboStyle->addItem("编号 ( A.B.C.)");
comboStyle->addItem("编号 (ⅰ.ⅱ.ⅲ.)");
comboStyle->addItem("编号 (Ⅰ.Ⅱ.Ⅲ.)");
comboStyle->setStatusTip("段落加标号或编号");
connect(comboStyle, SIGNAL(activated(int)), this, SLOT(textStyle(int)));
comboFont = new QFontComboBox();
comboToolBar->addWidget(comboFont);
comboFont->setStatusTip("更改字体");
connect(comboFont, SIGNAL(activated(QString)), this, SLOT(textFamily(QString)));
comboSize = new QComboBox();
comboToolBar->addWidget(comboSize);
comboSize->setEditable(true);
comboSize->setStatusTip("更改字号");
QFontDatabase db;
foreach(int size, db.standardSizes())
comboSize->addItem(QString::number(size));
connect(comboSize, SIGNAL(activated(QString)), this, SLOT(textSize(QString)));
comboSize->setCurrentIndex(comboSize->findText(QString::number(QApplication::font().pointSize())));
//自定义控件
mycombo = new FontSize;
comboToolBar->addWidget(mycombo);
connect(mycombo->comboBox, SIGNAL(activated(QString)), this, SLOT(textSize(QString)));
mycombo->comboBox->setCurrentIndex(comboSize->findText(QString::number(QApplication::font().pointSize())));
mycombo->comboBox->setCurrentIndex(comboSize->currentIndex());
}
void MainWindow::createStatusBar()
{
statusBar()->showMessage(tr("就绪"));
}
void MainWindow::setFunctionState(){//根据文档状态调整动作是否可用
//至少有一个子文档打开着的情况
bool hasMyChild = (activeEditwindow()!=0);
ui->actionsave->setEnabled(hasMyChild);
ui->actionsaveAs->setEnabled(hasMyChild);
ui->actionprint->setEnabled(hasMyChild);
ui->actionpaste->setEnabled(hasMyChild);
closeAct->setEnabled(hasMyChild);
closeAllAct->setEnabled(hasMyChild);
tileAct->setEnabled(hasMyChild);
cascadeAct->setEnabled(hasMyChild);
nextAct->setEnabled(hasMyChild);
previousAct->setEnabled(hasMyChild);
// separatorAct->setVisible(hasMyChild);
//文档打开着并且其中有内容被选中的情况
// bool hasSelection = (activeEditwindow() && activeEditwindow()->textCursor().hasSelection());
ui->actioncut->setEnabled(hasMyChild);
ui->actioncopy->setEnabled(hasMyChild);
bold->setEnabled(hasMyChild);
italic->setEnabled(hasMyChild);
underline->setEnabled(hasMyChild);
leftAlign->setEnabled(hasMyChild);
center->setEnabled(hasMyChild);
rightAlign->setEnabled(hasMyChild);
justify->setEnabled(hasMyChild);
color->setEnabled(hasMyChild);
}
void MainWindow::fileNew(){//新建文件的槽函数
//后期进行封装
EditWindow *child = new EditWindow;
mdiArea->addSubWindow(child);
connect(child, SIGNAL(copyAvailable(bool)),ui->actioncut, SLOT(setEnabled(bool)));
connect(child, SIGNAL(copyAvailable(bool)),ui->actioncopy, SLOT(setEnabled(bool)));
if(child ->newFile()){
child->show();
statusBar()->showMessage(QString("新建成功"), 2000);
enableText();
}
}
QMdiSubWindow *MainWindow::isAlreadyOpen(const QString &fileName){//寻找文件是否已在窗口中打开 是则返回此窗口的指针
QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();//获取文件的规范路径
//遍历编辑窗口
foreach (QMdiSubWindow *window, mdiArea->subWindowList()) {
EditWindow *myChild = qobject_cast<EditWindow *>(window->widget());
if (myChild->curFileName == canonicalFilePath)
return window;
}
return 0;
}
void MainWindow::fileOpen(){//打开磁盘中文件的槽函数
QString fileName=QFileDialog::getOpenFileName(this,QString("打开现有文件"),QString(), tr("HTML 文档 (*.htm *.html);;所有文件 (*.*)"));
if(!fileName.isEmpty()){//如果路径非空
//先判断是否已经打开
QMdiSubWindow * isExis = isAlreadyOpen(fileName);
//已打开则将其设置为活动窗口
if (isExis) {
mdiArea->setActiveSubWindow(isExis);
return;
}
//未打开则打开
EditWindow *child = new EditWindow;
mdiArea->addSubWindow(child);
connect(child, SIGNAL(copyAvailable(bool)),ui->actioncut, SLOT(setEnabled(bool)));
connect(child, SIGNAL(copyAvailable(bool)),ui->actioncopy, SLOT(setEnabled(bool)));
if (child->openFile(fileName)) {
statusBar()->showMessage(tr("文件已载入"), 2000);
child->show();
enableText();
} else {
child->close();
}
}
}
void MainWindow::fileSave(){ //保存文档
if (activeEditwindow() && activeEditwindow()->save())
statusBar()->showMessage(QString("保存成功"), 2000);
}
void MainWindow::fileSaveAs(){ //另存为
if (activeEditwindow() && activeEditwindow()->saveAs())
statusBar()->showMessage(QString("保存成功"), 2000);
}
void MainWindow::filePrint(){//打印
QPrinter printer(QPrinter::HighResolution);
QPrintDialog *printdialog = new QPrintDialog(&printer, this);
printdialog->setWindowTitle(tr("打印文档"));
if (printdialog->exec() == QDialog::Accepted)
activeEditwindow()->print(&printer);
delete printdialog;
}
void MainWindow::paintEvent(QPaintEvent *){
QPixmap pix;
pix.load(":/images/mountain.jpg");
QPainter painter(this);
painter.drawPixmap(0, 0, this->width(), this->height(), pix);
}
EditWindow *MainWindow::activeEditwindow()//找到当前活动的(被选中的)窗口
{
if (QMdiSubWindow *activeSubWindow = mdiArea->activeSubWindow())
return qobject_cast<EditWindow *>(activeSubWindow->widget());//类型转换
return 0;
}
void MainWindow::undo()//撤销操作的槽函数
{
if(activeEditwindow())
activeEditwindow()->undo();
}
void MainWindow::redo()//重做的槽函数
{
if(activeEditwindow())
activeEditwindow()->redo();
}
void MainWindow::cut()//剪切的槽函数
{
if (activeEditwindow())
activeEditwindow()->cut();
}
void MainWindow::copy()//复制的槽函数
{
if (activeEditwindow())
activeEditwindow()->copy();
}
void MainWindow::paste()//粘贴的槽函数
{
if (activeEditwindow())
activeEditwindow()->paste();
}
void MainWindow::Bold()//字体加粗的槽函数
{
QTextCharFormat bo;
bo.setFontWeight(bold->isChecked() ? QFont::Bold : QFont::Normal);
if(activeEditwindow())
activeEditwindow()->WordFormat(bo);
}
void MainWindow::Italic()//字体倾斜的槽函数
{
QTextCharFormat il;
il.setFontItalic(italic->isChecked());
if(activeEditwindow())
activeEditwindow()->WordFormat(il);
}
void MainWindow::Underline()//字体下划线的槽函数
{
QTextCharFormat ul;
ul.setFontUnderline(underline->isChecked());
if(activeEditwindow())
activeEditwindow()->WordFormat(ul);
}
void MainWindow::Align(QAction *a)//字体对齐的槽函数
{
if(activeEditwindow())
{
if (a == leftAlign)
activeEditwindow()->Align(1);
else if (a == center)
activeEditwindow()->Align(2);
else if (a == rightAlign)
activeEditwindow()->Align(3);
else if (a == justify)
activeEditwindow()->Align(4);
}
}
void MainWindow::textFamily(const QString &f)//字体选择的槽函数
{
QTextCharFormat tf;
tf.setFontFamily(f);
if(activeEditwindow())
activeEditwindow()->WordFormat(tf);
}
void MainWindow::textSize(const QString &p)//字号选择的槽函数
{
qreal pointSize = p.toFloat();
if (p.toFloat() > 0) {
QTextCharFormat fs;
fs.setFontPointSize(pointSize);
if(activeEditwindow())
activeEditwindow()->WordFormat(fs);
mycombo->comboBox->setCurrentIndex(comboSize->currentIndex());
comboSize->setCurrentIndex(mycombo->comboBox->currentIndex());
}
}
void MainWindow::Color()//设置字体颜色的槽函数
{
if(activeEditwindow())
{
QColor clr = QColorDialog::getColor(activeEditwindow()->textColor(), this);
if (!clr.isValid())
return;
QTextCharFormat co;
co.setForeground(clr);
activeEditwindow()->WordFormat(co);
QPixmap pix(16, 16);//更改设置字体颜色的按钮的图标
pix.fill(clr);
color->setIcon(pix);
}
}
void MainWindow::textStyle(int styleIndex)//实现为段落增加标号和编号的功能
{
if(activeEditwindow())
{
activeEditwindow()->setStyle(styleIndex);
}
}
void MainWindow::enableText()
{
bold->setEnabled(true);
italic->setEnabled(true);
underline->setEnabled(true);
leftAlign->setEnabled(true);
center->setEnabled(true);
rightAlign->setEnabled(true);
justify->setEnabled(true);
color->setEnabled(true);
}
void MainWindow::closeEvent(QCloseEvent *event)//重写关闭的函数
{
mdiArea->closeAllSubWindows();
if (mdiArea->currentSubWindow()) {
event->ignore();
} else {
event->accept();
}
}
void MainWindow::setActiveSubWindow(QWidget *window)
{
if (!window)
return;
mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(window));
}
void MainWindow::updateWindowMenu()
{
windowMenu->clear();//初始化清除
windowMenu->addAction(closeAct);
windowMenu->addAction(closeAllAct);
windowMenu->addSeparator();
windowMenu->addAction(tileAct);
windowMenu->addAction(cascadeAct);
windowMenu->addSeparator();
windowMenu->addAction(nextAct);
windowMenu->addAction(previousAct);
windowMenu->addAction(separatorAct);
QList<QMdiSubWindow *> windows = mdiArea->subWindowList();
//当有窗口打开时显示分隔符
separatorAct->setVisible(!windows.isEmpty());
//显示当前打开着的文档子窗口项
for (int i = 0; i < windows.size(); i++) {
EditWindow *child = qobject_cast<EditWindow *>(windows.at(i)->widget());
QString text;
if (i < 9) {
text = tr("&%1 %2").arg(i + 1).arg(child->easyCurrentFile());
} else {
text = tr("%1 %2").arg(i + 1).arg(child->easyCurrentFile());
}
//添加动作到菜单 设置动作可选
QAction *action = windowMenu->addAction(text);
action->setCheckable(true);
//设置当前活动窗口被选中
action ->setChecked(child == activeEditwindow());
//触发时执行map函数发送mapped信号
connect(action, SIGNAL(triggered()), windowMapper, SLOT(map()));
windowMapper->setMapping(action, windows.at(i));
}
enableText(); //使得字体设置菜单可用
}
void MainWindow::openNewWindow()
{
win = new newWindow();
win->show();
}
MainWindow::~MainWindow()
{
delete ui;
}
editwindow.h:
#ifndef EDITWINDOW_H
#define EDITWINDOW_H
#include <QTextEdit>
#include <QWidget>
#include<QString>
#include <QPrinter>
class EditWindow : public QTextEdit
{
Q_OBJECT
public:
EditWindow();
QString curFileName;//当前窗口文件的名称
void setCurrentFile(const QString &fileName);
bool newFile();
bool openFile(const QString &filePath);
bool saveFile(QString fileName);
bool saveAs();
bool save();
QString easyCurrentFile();
QString currentFile() { return curFileName; }
void WordFormat(const QTextCharFormat &format);
void Align(int align);
void setStyle(int style);
protected:
void closeEvent(QCloseEvent *event);
private:
QString strippedName(const QString &fullFileName);
bool maybeSave();
bool isUntitled;
private slots:
void documentWasModified();
};
#endif // EDITWINDOW_H
editwindow.cpp:
#include "editwindow.h"
#include<QtWidgets>
#include<QString>
#include<QTextEdit>
EditWindow::EditWindow()
{
setAttribute(Qt::WA_DeleteOnClose);//设置关闭时自动删除这个类
isUntitled = true;//默认未命名
}
QString EditWindow::strippedName(const QString &fullFileName)
{
return QFileInfo(fullFileName).fileName();
}
QString EditWindow::easyCurrentFile()//提取简易文件名
{
return strippedName(curFileName);
}
void EditWindow::setCurrentFile(const QString &fileName){
curFileName = QFileInfo(fileName).canonicalFilePath();
isUntitled = false;//设置文档为已保存状态
document()->setModified(false);//文档设为未被修改状态
setWindowModified(false);//窗口设为未被修改状态
setWindowTitle(easyCurrentFile() + "[*]");
}
void EditWindow::documentWasModified()
{
setWindowModified(document()->isModified());
}
bool EditWindow::newFile(){
static int num=1;//窗口编号 设为全局变量
curFileName=QString("文档"+QString::number(num++));
setWindowTitle(curFileName+"[*]");
connect(document(),SIGNAL(contentsChanged()),this,SLOT(documentWasModified()));
return true;
}
bool EditWindow::openFile(const QString &filePath){//从filePath读取文件
if (!filePath.isEmpty())
{
if (!QFile::exists(filePath))
return false;
QFile file(filePath);
if (!file.open(QFile::ReadOnly))
return false;
QByteArray data = file.readAll();
QTextCodec *codec = Qt::codecForHtml(data);
QString str = codec->toUnicode(data);
if (Qt::mightBeRichText(str)) {
this->setHtml(str);
} else {
str = QString::fromLocal8Bit(data);
this->setPlainText(str);
}
setCurrentFile(filePath);//设置文档及窗口
connect(document(),SIGNAL(contentsChanged()),this,SLOT(documentWasModified()));
return true;
}
return 0;
}
void EditWindow::closeEvent(QCloseEvent *event)
{
if (maybeSave()) {
event->accept();
} else {
event->ignore();
}
}
bool EditWindow::maybeSave()
{
if (!document()->isModified())
return true;
QMessageBox::StandardButton ret;
ret = QMessageBox::warning(this, tr("My Qt-Version Word"),tr("文档'%1'已被修改,保存吗?").arg(easyCurrentFile()),QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
if (ret == QMessageBox::Save)
return save();
else if (ret == QMessageBox::Cancel)
return false;
return true;
}
bool EditWindow::save()
{
if (isUntitled) {
return saveAs();
} else {
return saveFile(curFileName);
}
}
bool EditWindow::saveFile(QString curFileName){
if (isUntitled) {
return saveAs();
} else {
if (!(curFileName.endsWith(".htm", Qt::CaseInsensitive) || curFileName.endsWith(".html", Qt::CaseInsensitive))) {
curFileName += ".html"; // 默认保存为 HTML 文档
}
QTextDocumentWriter writer(curFileName);
bool isok = writer.write(this->document());
if (isok)
setCurrentFile(curFileName);
return isok;
}
}
bool EditWindow::saveAs(){
QString fileName = QFileDialog::getSaveFileName(this, tr("另存为"),curFileName,QString("HTML 文档 (*.htm *.html);;所有文件 (*.*)"));
if (fileName.isEmpty())
return false;
else{
if (!(fileName.endsWith(".htm", Qt::CaseInsensitive) || fileName.endsWith(".html", Qt::CaseInsensitive))) {
fileName += ".html"; // 默认保存为 HTML 文档
}
QTextDocumentWriter writer(fileName);
bool isok = writer.write(this->document());
if (isok)
setCurrentFile(fileName);
return isok;
}
}
void EditWindow::Align(int align)//段落文字对齐方式
{
if (align == 1)
this->setAlignment(Qt::AlignLeft | Qt::AlignAbsolute);
else if (align == 2)
this->setAlignment(Qt::AlignHCenter);
else if (align == 3)
this->setAlignment(Qt::AlignRight | Qt::AlignAbsolute);
else if (align == 4)
this->setAlignment(Qt::AlignJustify);
}
void EditWindow::WordFormat(const QTextCharFormat &format)//设置字体格式 颜色
{
QTextCursor cursor = this->textCursor();
if (!cursor.hasSelection())
cursor.select(QTextCursor::WordUnderCursor);
cursor.mergeCharFormat(format);
this->mergeCurrentCharFormat(format);
}
void EditWindow::setStyle(int style)//设置文本标号
{
QTextCursor cursor = this->textCursor();
if (style != 0) {
QTextListFormat::Style stylename = QTextListFormat::ListDisc;
switch (style) {
default:
case 1:
stylename = QTextListFormat::ListDisc;
break;
case 2:
stylename = QTextListFormat::ListCircle;
break;
case 3:
stylename = QTextListFormat::ListSquare;
break;
case 4:
stylename = QTextListFormat::ListDecimal;
break;
case 5:
stylename = QTextListFormat::ListLowerAlpha;
break;
case 6:
stylename = QTextListFormat::ListUpperAlpha;
break;
case 7:
stylename = QTextListFormat::ListLowerRoman;
break;
case 8:
stylename = QTextListFormat::ListUpperRoman;
break;
}
cursor.beginEditBlock();
QTextBlockFormat blockFmt = cursor.blockFormat();
QTextListFormat listFmt;
if (cursor.currentList()) {
listFmt = cursor.currentList()->format();
} else {
listFmt.setIndent(blockFmt.indent() + 1);
blockFmt.setIndent(0);
cursor.setBlockFormat(blockFmt);
}
listFmt.setStyle(stylename);
cursor.createList(listFmt);
cursor.endEditBlock();
} else {
QTextBlockFormat bfmt;
bfmt.setObjectIndex(-1);
cursor.mergeBlockFormat(bfmt);
}
}