大家好,这里是国中之林!
❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看←
项目功能演示:
放心食用!最后有完整代码.
超级详细,期待您的一个点赞❥(^_-)
一览全局:
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;//0 break; } 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_NAMESPACEnamespace 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();//初始化窗体相关的action void initDocAction();//初始化文本相关的action TextEdit* 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. initWindowAction connect(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;//0 break; } 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_OBJECTpublic: 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,让时间见证这一切吧,继续前进!