项目功能演示:
放心食用!最后有完整代码.
超级详细,期待您的一个点赞❥(^_-)
一览全局:
WPS项目目录
- 一.创建项目
- 二.导入资源
- 三.ui设计
- 四.字号选择框初始化
- 五.滚动条初始化
- 六.添加自定义文本类
- 七.初始化action状态
- 八.新建文档
- 九.打开文件
- 十.保存与另存为
- 十一.打印/打印预览
- 十二.撤销重做剪切复制粘贴
- 十三.关闭事件/退出
- 十四.窗体菜单实现
- 十五.动态添加action/信号映射器
- 十六.字体颜色加粗斜体下划线
- 十七.文本对齐
- 十八.段落符号
- 十九.字体字号
- 二十.打包
- 二十一.发布
- 二十二.完整代码
- 二十三.最后
一.创建项目
用的是QMainWindow类,这个包含菜单,工具栏,状态栏.
能运行出来,就说明环境搭好了.
二.导入资源
三.ui设计
应用图标的添加.
四.字号选择框初始化
获取系统可支持的字号添加到选择框中,再设置当前系统字号
五.滚动条初始化
滚动条就是这个,这是用的后面做完的来演示的.
六.添加自定义文本类
记得添加宏Q_OBJECT
,还有初始化父类
七.初始化action状态
八.新建文档
九.打开文件
十.保存与另存为
十一.打印/打印预览
十二.撤销重做剪切复制粘贴
十三.关闭事件/退出
十四.窗体菜单实现
十五.动态添加action/信号映射器
十六.字体颜色加粗斜体下划线
十七.文本对齐
十八.段落符号
void MainWindow::on_comboBoxStandard_activated(int index)
{TextEdit*edit=activateWindow();if(edit){if(index==0){QTextCursor cursor=edit->textCursor();cursor.beginEditBlock();QTextList*list=cursor.currentList();if(list){list->remove(cursor.block());QTextBlockFormat blockFormat=cursor.blockFormat();blockFormat.setIndent(0);cursor.setBlockFormat(blockFormat);}cursor.endEditBlock();return;}QTextListFormat::Style style;//描述装饰列表项符号的枚举switch (index){case 1:style=QTextListFormat::ListDisc;break;case 2:style=QTextListFormat::ListCircle;break;case 3:style=QTextListFormat::ListSquare;break;case 4:style=QTextListFormat::ListDecimal;break;case 5:style=QTextListFormat::ListLowerAlpha;break;case 6:style=QTextListFormat::ListUpperAlpha;break;case 7:style=QTextListFormat::ListLowerRoman;break;case 8:style=QTextListFormat::ListUpperRoman;break;default:style=QTextListFormat::ListStyleUndefined;//0break;}QTextCursor cursor=edit->textCursor();cursor.beginEditBlock();QTextBlockFormat blockFormat=cursor.blockFormat();QTextListFormat listFormat;QTextList*list=cursor.currentList();if(list){listFormat=list->format();list->remove(cursor.block());blockFormat.setIndent(0);cursor.setBlockFormat(blockFormat);}listFormat.setStyle(style);cursor.createList(listFormat);cursor.endEditBlock();}
}
十九.字体字号
二十.打包
二十一.发布
二十二.完整代码
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.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "textedit.h"
#include <QMdiSubWindow>
#include <QPrinter>
#include <QActionGroup>
#include <QSignalMapper>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_NewAction_triggered();void setActionStatus(bool b);void on_OpenAction_triggered();void on_saveAction_triggered();void on_saveAsAction_triggered();void on_printAction_triggered();void on_printViewAction_triggered();void printPreview(QPrinter*printer);void on_undoAction_triggered();void on_redoAction_triggered();void on_cutAction_triggered();void on_copyAction_triggered();void on_pasteAction_triggered();void on_exitAction_triggered();void on_closeAction_triggered();void on_closeAllAction_triggered();void on_tileAction_triggered();void on_cascadeAction_triggered();void on_nextAction_triggered();void on_previousAction_triggered();void addSubWindowAction();void setActiveSubWindow(QWidget*widget);void on_colorAction_triggered();void on_blodAction_triggered();void on_italicAction_triggered();void on_underLineAction_triggered();void on_leftAlignAction_triggered();void on_centerAction_triggered();void on_rightAlignAction_triggered();void on_justifyAction_triggered();void on_comboBoxStandard_activated(int index);void on_fontComboBox_activated(const QString &arg1);void on_comboBoxFontSize_activated(const QString &arg1);protected:void closeEvent(QCloseEvent *event)override;//重写关闭事件private:Ui::MainWindow *ui;void init();//初始化函数void initFontSize();//初始化字号void initScrollBar();//初始化滚动条void initWindowAction();//初始化窗体相关的actionvoid initDocAction();//初始化文本相关的actionTextEdit* activateWindow();//获取当前活动窗口QMdiSubWindow * findSubWindow(const QString&docName);//获取相应文档的子窗体QActionGroup*actionGroup;QSignalMapper*mapper;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFontDatabase>
#include <QMdiSubWindow>
#include <QFileDialog>
#include <QFileInfo>
#include <QPrinter>
#include <QPrintDialog>
#include <QPrintPreviewDialog>
#include <QCloseEvent>
#include <QColorDialog>
#include <QTextCharFormat>
#include <QTextList>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this); init();
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::init()
{ui->mdiArea->setBackground(QBrush(Qt::white));//用画刷设置mdi背景颜色initFontSize();initScrollBar();initWindowAction();//当窗口关闭时发送一次信号,重新设置窗口action. initWindowActionconnect(ui->mdiArea,&QMdiArea::subWindowActivated,this,&MainWindow::initWindowAction);connect(ui->mdiArea,&QMdiArea::subWindowActivated,this,&MainWindow::initDocAction);initDocAction();actionGroup=new QActionGroup(this);actionGroup->setExclusive(true);//排他选择mapper=new QSignalMapper(this);connect(ui->menu_W,&QMenu::aboutToShow,this,&MainWindow::addSubWindowAction);connect(mapper,SIGNAL(mapped(QWidget*)),this,SLOT(setActiveSubWindow(QWidget*)));
}void MainWindow::initFontSize()
{ui->comboBoxFontSize->clear();//QFontDatabase提供系统可用字体的相关信息for(int fontSize:QFontDatabase::standardSizes())//返回标准字体大小的列表{ui->comboBoxFontSize->addItem(QString::number(fontSize));//插入到字体选择框中}QFont appFont=QApplication::font();//当前系统默认字体int fontSize=appFont.pointSize(); //获取字体号int sizeIndex=ui->comboBoxFontSize->findText(QString::number(fontSize));ui->comboBoxFontSize->setCurrentIndex(sizeIndex);
}void MainWindow::initScrollBar()
{//设置mdi的水平和垂直滚动条当需要的时候ui->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);ui->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
}void MainWindow::initWindowAction()
{bool hasActWindow=(activateWindow()!=nullptr);ui->saveAction->setEnabled(hasActWindow);ui->saveAsAction->setEnabled(hasActWindow);ui->printAction->setEnabled(hasActWindow);ui->printViewAction->setEnabled(hasActWindow);ui->undoAction->setEnabled(hasActWindow);ui->redoAction->setEnabled(hasActWindow);ui->pasteAction->setEnabled(hasActWindow);ui->closeAction->setEnabled(hasActWindow);ui->closeAllAction->setEnabled(hasActWindow);ui->tileAction->setEnabled(hasActWindow);ui->cascadeAction->setEnabled(hasActWindow);ui->nextAction->setEnabled(hasActWindow);ui->previousAction->setEnabled(hasActWindow);
}void MainWindow::initDocAction()
{ui->cutAction->setEnabled(false);ui->copyAction->setEnabled(false);ui->colorAction->setEnabled(false);ui->blodAction->setEnabled(false);ui->italicAction->setEnabled(false);ui->underLineAction->setEnabled(false);ui->leftAlignAction->setEnabled(false);ui->centerAction->setEnabled(false);ui->rightAlignAction->setEnabled(false);ui->justifyAction->setEnabled(false);
}TextEdit *MainWindow::activateWindow()
{QMdiSubWindow*window=ui->mdiArea->activeSubWindow();if(window){return qobject_cast<TextEdit*>(window->widget());}return nullptr;
}QMdiSubWindow *MainWindow::findSubWindow(const QString &docName)
{QString filepath=QFileInfo(docName).canonicalFilePath();//返回文件的绝对路径for(QMdiSubWindow*sub:ui->mdiArea->subWindowList()){TextEdit* edit=qobject_cast<TextEdit*>(sub->widget());if(edit->getDocFilePath()==filepath){return sub;}}return nullptr;
}void MainWindow::on_NewAction_triggered()
{TextEdit*edit=new TextEdit;ui->mdiArea->addSubWindow(edit);//edit父对象将是QMdiArea的viewport小部件//当文本编辑器选中或者取消选中会发出copyAvailable信号.connect(edit,&TextEdit::copyAvailable,this,&MainWindow::setActionStatus);edit->initNewDoc();edit->show();
}void MainWindow::setActionStatus(bool b)
{ui->cutAction->setEnabled(b);ui->copyAction->setEnabled(b);ui->colorAction->setEnabled(b);ui->blodAction->setEnabled(b);ui->italicAction->setEnabled(b);ui->underLineAction->setEnabled(b);ui->leftAlignAction->setEnabled(b);ui->centerAction->setEnabled(b);ui->rightAlignAction->setEnabled(b);ui->justifyAction->setEnabled(b);
}void MainWindow::on_OpenAction_triggered()
{QString docName=QFileDialog::getOpenFileName(this,"打开文档","./","所以文件(*.*)");if(!docName.isEmpty()){QMdiSubWindow*sub=findSubWindow(docName);if(sub){ui->mdiArea->setActiveSubWindow(sub);return;}TextEdit*edit=new TextEdit;ui->mdiArea->addSubWindow(edit);connect(edit,&TextEdit::copyAvailable,this,&MainWindow::setActionStatus);if(edit->loadDoc(docName)){statusBar()->showMessage("文档已打开",3000);//3秒显示在状态栏edit->show();}else{edit->close();}}
}void MainWindow::on_saveAction_triggered()
{TextEdit* edit=activateWindow();if(edit){if(edit->saveDoc()){statusBar()->showMessage("文档已保存",3000);}}
}void MainWindow::on_saveAsAction_triggered()
{TextEdit* edit=activateWindow();if(edit){if(edit->saveAsDoc()){statusBar()->showMessage("文档已保存",3000);}}
}void MainWindow::on_printAction_triggered()
{TextEdit* edit=activateWindow();if(!edit) return;//QPrinter::HighResolution将printer分辨率设置为正在使用的打印机分辨率QPrinter printer(QPrinter::HighResolution);QPrintDialog dialog(&printer,this);if(dialog.exec()==QDialog::Accepted){edit->print(&printer);}
}void MainWindow::on_printViewAction_triggered()
{TextEdit* edit=activateWindow();if(!edit) return;QPrinter printer;QPrintPreviewDialog preview(&printer,this);connect(&preview,&QPrintPreviewDialog::paintRequested,this,&MainWindow::printPreview);if(preview.exec()==QPrintPreviewDialog::Accepted){edit->print(&printer);}
}void MainWindow::printPreview(QPrinter*printer)
{TextEdit* edit=activateWindow();if(edit){edit->print(printer);}
}void MainWindow::on_undoAction_triggered()
{TextEdit*edit=activateWindow();if(edit){edit->undo();}
}void MainWindow::on_redoAction_triggered()
{TextEdit*edit=activateWindow();if(edit){edit->redo();}
}void MainWindow::on_cutAction_triggered()
{TextEdit*edit=activateWindow();if(edit){edit->cut();}
}void MainWindow::on_copyAction_triggered()
{TextEdit*edit=activateWindow();if(edit){edit->copy();}
}void MainWindow::on_pasteAction_triggered()
{TextEdit*edit=activateWindow();if(edit){edit->paste();}
}void MainWindow::closeEvent(QCloseEvent *event)
{ui->mdiArea->closeAllSubWindows();if(ui->mdiArea->currentSubWindow()){event->ignore();}else{event->accept();}
}void MainWindow::on_exitAction_triggered()
{close();
}void MainWindow::on_closeAction_triggered()
{ui->mdiArea->closeActiveSubWindow();
}void MainWindow::on_closeAllAction_triggered()
{ui->mdiArea->closeAllSubWindows();
}void MainWindow::on_tileAction_triggered()
{ui->mdiArea->tileSubWindows();
}void MainWindow::on_cascadeAction_triggered()
{ui->mdiArea->cascadeSubWindows();
}void MainWindow::on_nextAction_triggered()
{ui->mdiArea->activateNextSubWindow();
}void MainWindow::on_previousAction_triggered()
{ui->mdiArea->activatePreviousSubWindow();
}void MainWindow::addSubWindowAction()
{QList<QAction*> actionList=actionGroup->actions();if(!actionList.isEmpty()){for(QAction*action:actionList){delete action;}}QList<QMdiSubWindow*>subWindowList=ui->mdiArea->subWindowList();//获取子窗体列表if(!subWindowList.isEmpty())ui->menu_W->addSeparator();//添加一个分隔符for(int i=0;i<subWindowList.count();i++){QMdiSubWindow*subWindow=subWindowList[i];TextEdit*edit=qobject_cast<TextEdit*>(subWindow->widget());QString action_text=QString("%1 %2").arg(i+1).arg(edit->getDocWindowTitle());QAction* action=ui->menu_W->addAction(action_text);actionGroup->addAction(action);action->setCheckable(true);if(edit==activateWindow())action->setChecked(true);//设置选中connect(action,SIGNAL(triggered(bool)),mapper,SLOT(map()));mapper->setMapping(action,subWindow);}}void MainWindow::setActiveSubWindow(QWidget *widget)
{if(widget)ui->mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow*>(widget));
}void MainWindow::on_colorAction_triggered()
{TextEdit*edit=activateWindow();if(edit){QColor color;color=QColorDialog::getColor();if(!color.isValid())return ;QTextCharFormat format;format.setForeground(color);edit->mergeCurrentCharFormat(format);QPixmap pixmap(24,24);pixmap.fill(color);ui->colorAction->setIcon(pixmap);}
}void MainWindow::on_blodAction_triggered()
{TextEdit*edit=activateWindow();if(edit){bool ischecked=ui->blodAction->isChecked();QTextCharFormat format;format.setFontWeight(ischecked?QFont::Bold:QFont::Normal);edit->mergeCurrentCharFormat(format);}
}void MainWindow::on_italicAction_triggered()
{TextEdit*edit=activateWindow();if(edit){QTextCharFormat format;format.setFontItalic(ui->italicAction->isChecked());edit->mergeCurrentCharFormat(format);}
}void MainWindow::on_underLineAction_triggered()
{TextEdit*edit=activateWindow();if(edit){QTextCharFormat format;format.setFontUnderline(ui->underLineAction->isChecked());edit->mergeCurrentCharFormat(format);}
}void MainWindow::on_leftAlignAction_triggered()
{TextEdit*edit=activateWindow();if(edit){edit->setAlignment(Qt::AlignLeft);}
}void MainWindow::on_centerAction_triggered()
{TextEdit*edit=activateWindow();if(edit){edit->setAlignment(Qt::AlignCenter);}
}void MainWindow::on_rightAlignAction_triggered()
{TextEdit*edit=activateWindow();if(edit){edit->setAlignment(Qt::AlignRight);}
}void MainWindow::on_justifyAction_triggered()
{TextEdit*edit=activateWindow();if(edit){edit->setAlignment(Qt::AlignJustify);}
}void MainWindow::on_comboBoxStandard_activated(int index)
{TextEdit*edit=activateWindow();if(edit){if(index==0){QTextCursor cursor=edit->textCursor();cursor.beginEditBlock();QTextList*list=cursor.currentList();if(list){list->remove(cursor.block());QTextBlockFormat blockFormat=cursor.blockFormat();blockFormat.setIndent(0);cursor.setBlockFormat(blockFormat);}cursor.endEditBlock();return;}QTextListFormat::Style style;//描述装饰列表项符号的枚举switch (index){case 1:style=QTextListFormat::ListDisc;break;case 2:style=QTextListFormat::ListCircle;break;case 3:style=QTextListFormat::ListSquare;break;case 4:style=QTextListFormat::ListDecimal;break;case 5:style=QTextListFormat::ListLowerAlpha;break;case 6:style=QTextListFormat::ListUpperAlpha;break;case 7:style=QTextListFormat::ListLowerRoman;break;case 8:style=QTextListFormat::ListUpperRoman;break;default:style=QTextListFormat::ListStyleUndefined;//0break;}QTextCursor cursor=edit->textCursor();cursor.beginEditBlock();QTextBlockFormat blockFormat=cursor.blockFormat();QTextListFormat listFormat;QTextList*list=cursor.currentList();if(list){listFormat=list->format();list->remove(cursor.block());blockFormat.setIndent(0);cursor.setBlockFormat(blockFormat);}listFormat.setStyle(style);cursor.createList(listFormat);cursor.endEditBlock();}
}void MainWindow::on_fontComboBox_activated(const QString &arg1)
{TextEdit* edit=activateWindow();if(edit){QTextCharFormat format;format.setFontFamily(arg1);edit->mergeCurrentCharFormat(format);}
}void MainWindow::on_comboBoxFontSize_activated(const QString &arg1)
{TextEdit* edit=activateWindow();if(edit){QTextCharFormat format;format.setFontPointSize(arg1.toInt());edit->mergeCurrentCharFormat(format);}
}
textedit.h
#ifndef TEXTEDIT_H
#define TEXTEDIT_H
#include <QTextEdit>class TextEdit : public QTextEdit
{Q_OBJECT
public:TextEdit(QWidget*parent=nullptr);~TextEdit();void initNewDoc(); //初始化新建文档QString getDocFilePath()const;//获取文件路径bool loadDoc(const QString&docName);//读取文件内容bool saveDoc();//保存文档bool saveAsDoc();//另存为QString getDocWindowTitle()const;protected:void closeEvent(QCloseEvent *event)override;//重写关闭事件private:QString getDocName()const;void initOpenDoc(const QString&docName);//初始化打开的文档bool writeToDoc(const QString&docName);//写文件bool promptSave();//提示是否保存private slots:void setWindowModality();//设置WindowModality属性private:QString docWindowTitle; //文档标题static int docNo;//文档编号QString docFilePath;//文档路径
};#endif // TEXTEDIT_H
textedit.cpp
#include "textedit.h"
#include <QFile>
#include <QFileInfo>
#include <QFileDialog>
#include <QTextDocumentWriter>
#include <QCloseEvent>
#include <QMessageBox>int TextEdit::docNo=1;TextEdit::TextEdit(QWidget *parent):QTextEdit(parent)
{setAttribute(Qt::WA_DeleteOnClose);//关闭窗口时,释放资源docWindowTitle="";docFilePath="";//路径初始化为空可以区分是否是打开的文档
}TextEdit::~TextEdit()
{}void TextEdit::initNewDoc()
{docWindowTitle=QString("文档 %1").arg(docNo++);//使用windowModified机制,添加[*]占位符//当窗口显示的文档未保存时,*就显示出来setWindowTitle(docWindowTitle + "[*]");//当文档内容发生改变,发出contentsChanged信号//document() 返回当前TextEdit文档connect(document(),&QTextDocument::contentsChanged,this,&TextEdit::setWindowModality);
}QString TextEdit::getDocFilePath() const
{return this->docFilePath;
}QString TextEdit::getDocName() const
{return QFileInfo(this->docFilePath).fileName();//获取文件名称
}bool TextEdit::loadDoc(const QString &docName)
{if(!docName.isEmpty()){QFile file(docName);if(!file.exists())return false;//文件不存在if(!file.open(QFile::ReadOnly))return false;//打开文件失败QByteArray text=file.readAll();//读取文件内容if(Qt::mightBeRichText(text))//如果是富文件{setHtml(text);//富文本显示}else{setPlainText(text);//纯文本显示}initOpenDoc(docName);}return true;
}bool TextEdit::saveDoc()
{if(document()->isModified())//文档是否被修改{if(!docFilePath.isEmpty())//路径是否为空{return writeToDoc(docFilePath);//写文件}else{return saveAsDoc();//另存为}}return false;
}bool TextEdit::saveAsDoc()
{QString docName=QFileDialog::getSaveFileName(this,"另存为","./","HTML文档(*.html);;文本文件(*.txt)");if(docName.isEmpty())return false;return writeToDoc(docName);
}QString TextEdit::getDocWindowTitle() const
{return this->docWindowTitle;
}bool TextEdit::promptSave()
{if(!document()->isModified()){return true;}QMessageBox::StandardButton res;res=QMessageBox::warning(this,"提示",QString("%1已修改,是否保存?").arg(docWindowTitle),QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel);if(res==QMessageBox::Yes){return saveDoc();}else if(res==QMessageBox::No){return true;}else if(res==QMessageBox::Cancel){return false;}}void TextEdit::closeEvent(QCloseEvent *event)
{if(promptSave()){event->accept();}else{event->ignore();}
}void TextEdit::initOpenDoc(const QString &docName)
{docFilePath=QFileInfo(docName).canonicalFilePath();docWindowTitle=getDocName()+" "+QString::number(docNo++);setWindowTitle(docWindowTitle + "[*]");connect(document(),&QTextDocument::contentsChanged,this,&TextEdit::setWindowModality);
}bool TextEdit::writeToDoc(const QString &docName)
{//QTextDocumentWriter将QTextDocument写入文件QTextDocumentWriter docWriter(docName);if(docWriter.write(document())){docFilePath=QFileInfo(docName).canonicalFilePath();document()->setModified(false);//文档未改动setWindowModified(false);//不显示占位符标识}return true;
}void TextEdit::setWindowModality()
{setWindowModified(document()->isModified());//根据是否改动来设置是否显示*
}
二十三.最后
现在是2024年9月20日15:57:22,让时间见证这一切吧,继续前进!