Qt基础项目篇——Qt版Word字处理软件

一、核心功能

本软件为多文档型程序,界面是标准的 Windows 主从窗口

拥有:主菜单、工具栏、文档显示区 和 状态栏。

所要实现的东西,均在下图了。

开发该软件,主要分为下面三个阶段

1)界面设计开发

  • 多窗口 MDI 程序框架的建立
  • 菜单设计
  • 工具栏设计
  • 工具按钮
  • 状态栏的帮助提示文本
  • 多个文档子窗口的管理和控制

2)文本编辑功能实现

  • 建立、打开和保存
  • 剪切、复制和粘贴
  • 撤销和恢复

3)排版美化功能实现

  • 字体选择
  • 字形
  • 字号
  • 文字颜色
  • 文档段落标号和标号的添加
  • 段落对齐方式

二、界面设计与开发

新建项目,MyselfWord。

1. 建立 MDI 程序框架

1.1 多文档区域的创建

在头文件 “myword.h” 中添加 QMdiArea 类的声明和定义变量:

#ifndef MYWORD_H
#define MYWORD_H#include <QMainWindow>//申明
class QMdiArea;class MyWord : public QMainWindow
{Q_OBJECTpublic:MyWord(QWidget *parent = nullptr);~MyWord();private://定义变量QMdiArea *mdiArea;
};
#endif // MYWORD_H

在 “myword.cpp” 的构造函数编写如下:

#include "myword.h"
#include <QtWidgets>MyWord::MyWord(QWidget *parent): QMainWindow(parent)
{mdiArea = new QMdiArea; // 创建一个新的QMdiArea实例mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); // 设置水平滚动条策略为根据需要显示mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); // 设置垂直滚动条策略为根据需要显示setCentralWidget(mdiArea); // 将QMdiArea设置为窗口的中心部件move(200,150);resize(800,500);setWindowTitle(tr("Myself Word"));
}MyWord::~MyWord()
{
}

1.2 子窗口类的创建

        为了实现多文档操作和管理,需要向 QMdiArea 中添加子窗口。为了可以更好地操作子窗口,则必须实例化子窗口的中心部件。而子窗口的中心部件使用了 QTextEdit 类,所以要实现自己的类,它必须继承自 QTextEdit 类。

        添加新的类,具体如下:

在 “mychild.h” 中添加:

#ifndef MYCHILD_H
#define MYCHILD_H#include <QWidget>
#include <QTextEdit>class MyChild : public QTextEdit
{Q_OBJECT
public:MyChild();void newFile(); //新建操作QString userFriendlyCurrentFile();  //提取文件名QString currentFile() { return curFile; }   //返回当前文件路径
protected:void closeEvent(QCloseEvent *event);    //关闭事件
private slots:void documentWasModified(); //文档被更改时,窗口显示更改状态标识
private:QString strippedName(const QString &fullFileName);  //获取较短的绝对路径QString curFile;    //保存当前文件路径bool isUntitled;    //作为当前文件是否被保存到硬盘上的标识
};#endif // MYCHILD_H

声明了许多函数和定义了几个变量。其实可以一边实现功能,一边添加需要的函数。现在先实现新建功能,首先声明函数 newFile()。

1.3 新建文件操作

(1)newFile() 设计思路

  • 设置窗口编号
  • 设置文件未被保存过 “isUntitiled = true;”
  • 保存文件路径,为 curFile 赋初值,用 strippedName 函数修改为绝对路径
  • 设置子窗口标题
  • 关联文档内容改变信号 contentsChanged() 到显示文档更改状态标志槽documentWasModified()。

(2)newFile() 实现

子窗口的初始化

在“mychild.cpp”文件中添加:

#include "mychild.h"
#include <QtWidgets>MyChild::MyChild()
{setAttribute(Qt::WA_DeleteOnClose); //设置在子窗口关闭时销毁这个类的对象isUntitled = true;  //初始 isUntitled 为 true
}

newFile() 的实现


void MyChild::newFile()
{//设置窗口编号,因为编号会一直保存,所以需要使用静态变量static int sequenceNumber = 1;//新建的文档默认为命名isUntitled = true;//将当前文件命名为"文档+编号"的形式,编号先使用再1curFile = tr("文档 %1").arg(sequenceNumber++);//设置窗口标题,使用[*]可以在文档被更改后在文件名称后显示"*"号setWindowTitle(curFile + "[*]" + tr(" - Myself Word"));//文档更改时发送 contentsChanged()信号,执行 documentWasModified() 曹函数connect(document(),SIGNAL(contentsChanged()),this,SLOT(documentWasModified()));
}

这里在设置窗口标题时添加了“[*]”字符,它可以保证编辑器内容被更改后,在文档标题中显示“*”号。

(3)文件更改标记

下面是 documentWasModified() 槽函数的定义:

void MyChild::documentWasModified()
{   //根据文档的 isModified() 函数的返回值,判断编辑器内容是否被更改setWindowModified(document()->isModified());
}

编辑器内容是否被更改,可以使用 QTextDocument 类的 isModified() 函数得知。

设置文档子窗口标题

QString MyChild::userFriendlyCurrentFile()
{return strippedName(curFile);
}

strippedName 函数用于修改文件名为较短的绝对路径。接收一个完整的文件名(包括路径)作为参数(类型为 QString),然后返回这个文件名中的基本文件名部分(即去除路径后的文件名)。

QString MyChild::strippedName(const QString &fullFileName)
{return QFileInfo(fullFileName).fileName();
}

先不考虑关闭文档时的保存逻辑,在 closeEvent() 中无条件地接收关闭事件。

void MyChild::closeEvent(QCloseEvent *event)
{event->accept();
}

2. 菜单系统设计

MyselfWord 的菜单系统包括主菜单、菜单栏和子菜单三级。

在 “myword.h” 中声明以及系统动作和菜单的实现:

#ifndef MYWORD_H
#define MYWORD_H#include <QMainWindow>class QMdiArea;
class QAction;//
class QMenu;//class MyWord : public QMainWindow
{Q_OBJECTpublic:MyWord(QWidget *parent = nullptr);~MyWord();private:QMdiArea *mdiArea;void createActions();//void createMenus();//
};
#endif // MYWORD_H

2.1 文件 主菜单

需要包括:新建N,打开O,保存S,另存为A,打印P,打印预览,退出X。

在“myword.h”文件中,定义“文件”菜单指针,定义“文件”主菜单下各个功能项的 QAction

private:void createActions();void createMenus();QMdiArea *mdiArea;//菜单QMenu *fileMenu;//动作(Action)QAction *newAct;            //【文件】主菜单QAction *openAct;QAction *saveAct;QAction *saveAsAct;QAction *printAct;QAction *printPreviewAct;QAction *exitAct;

在“myword.cpp”文件中编写函数 createActions() 的代码

记得在 images目录下搞点菜单图标。

const QString rsrcPath = ":/images";
void MyWord::createActions()
{/*【文件】菜单动作集*///&N 表示这个菜单项可以使用快捷键 Alt+N 来访问newAct = new QAction(QIcon(rsrcPath + "/filenew.png"), tr("新建(&N)"), this);newAct->setShortcuts(QKeySequence::New);        //设置了快捷键newAct->setToolTip("新建");                   //设置工具栏按钮的提示文本newAct->setStatusTip(tr("创建一个新文档"));     //设置状态栏提示文本//connect(newAct, SIGNAL(triggered()), this, SLOT(fileNew()));openAct = new QAction(QIcon(rsrcPath + "/fileopen.png"), tr("打开(&O)..."), this);openAct->setShortcuts(QKeySequence::Open);openAct->setToolTip("打开");openAct->setStatusTip(tr("打开已存在的文档"));//connect(openAct, SIGNAL(triggered()), this, SLOT(fileOpen()));saveAct = new QAction(QIcon(rsrcPath + "/filesave.png"), tr("保存(&S)"), this);saveAct->setShortcuts(QKeySequence::Save);saveAct->setToolTip("保存");saveAct->setStatusTip(tr("将当前文档存盘"));//connect(saveAct, SIGNAL(triggered()), this, SLOT(fileSave()));saveAsAct = new QAction(tr("另存为(&A)..."), this);saveAsAct->setShortcuts(QKeySequence::SaveAs);saveAsAct->setStatusTip(tr("以一个新名字保存文档"));//connect(saveAsAct, SIGNAL(triggered()), this, SLOT(fileSaveAs()));printAct = new QAction(QIcon(rsrcPath + "/fileprint.png"), tr("打印(&P)..."), this);printAct->setShortcuts(QKeySequence::Print);printAct->setToolTip("打印");printAct->setStatusTip(tr("打印文档"));//connect(printAct, SIGNAL(triggered()), this, SLOT(filePrint()));printPreviewAct = new QAction(tr("打印预览..."), this);printPreviewAct->setStatusTip(tr("预览打印效果"));//connect(printPreviewAct, SIGNAL(triggered()), this, SLOT(filePrintPreview()));exitAct = new QAction(tr("退出(&X)"), this);exitAct->setShortcuts(QKeySequence::Quit);exitAct->setStatusTip(tr("退出应用程序"));//connect(exitAct, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
}

上面所写的槽函数,后面会一一实现。

然后再编写函数 createMenus() 的代码

void MyWord::createMenus()
{//【文件】主菜单fileMenu = menuBar()->addMenu(tr("文件(&F)"));fileMenu->addAction(newAct);fileMenu->addAction(openAct);fileMenu->addSeparator();   //分隔线fileMenu->addAction(saveAct);fileMenu->addAction(saveAsAct);fileMenu->addSeparator();   //分隔线fileMenu->addAction(printAct);fileMenu->addAction(printPreviewAct);fileMenu->addSeparator();   //分隔线fileMenu->addAction(exitAct);
}

记得别忘记在“myword.cpp”的构造函数中添加这里两个函数

    createActions();createMenus();

“文件”主菜单的运行显示效果如下:

2.2 编辑 主菜单

“编辑” 主菜单功能项应包含:撤销U、重做R、剪切T、复制C、粘贴P

在 “myword.h”文件中,定义“编辑”主菜单指针:

    QMenu *editMenu;QAction *undoAct;           //【编辑】主菜单QAction *redoAct;QAction *cutAct;QAction *copyAct;QAction *pasteAct;

在“myword.cpp”文件,函数 createActions() 的代码中添加:

/*【编辑】菜单动作集*/undoAct = new QAction(QIcon(rsrcPath + "/editundo.png"),tr("撤销(&U)"), this);undoAct->setShortcut(QKeySequence::Undo);undoAct->setToolTip("撤销");undoAct->setStatusTip(tr("撤销当前操作"));connect(undoAct, SIGNAL(triggered()), this, SLOT(undo()));      //不用子窗口类去实现redoAct = new QAction(QIcon(rsrcPath + "/editredo.png"),tr("重做(&R)"), this);redoAct->setShortcut(QKeySequence::Redo);redoAct->setToolTip("重做");redoAct->setStatusTip(tr("恢复之前操作"));connect(redoAct, SIGNAL(triggered()), this, SLOT(redo()));      //不用子窗口类去实现cutAct = new QAction(QIcon(rsrcPath + "/editcut.png"),tr("剪切(&T)"), this);cutAct->setShortcuts(QKeySequence::Cut);cutAct->setToolTip("剪切");cutAct->setStatusTip(tr("从文档中裁剪所选内容,并将其放入剪贴板"));connect(cutAct, SIGNAL(triggered()), this, SLOT(cut()));        //不用子窗口类去实现copyAct = new QAction(QIcon(rsrcPath + "/editcopy.png"),tr("复制(&C)"), this);copyAct->setShortcuts(QKeySequence::Copy);copyAct->setToolTip("复制");copyAct->setStatusTip(tr("拷贝所选内容,并将其放入剪贴板"));connect(copyAct, SIGNAL(triggered()), this, SLOT(copy()));      //不用子窗口类去实现pasteAct = new QAction(QIcon(rsrcPath + "/editpaste.png"),tr("粘贴(&P)"), this);pasteAct->setShortcuts(QKeySequence::Paste);pasteAct->setToolTip("粘贴");pasteAct->setStatusTip(tr("将剪贴板的内容粘贴到文档"));connect(pasteAct, SIGNAL(triggered()), this, SLOT(paste()));    //不用子窗口类去实现

在“myword.cpp”文件,函数 createMenus() 的代码中添加:

//【编辑】主菜单editMenu = menuBar()->addMenu(tr("编辑(&E)"));editMenu->addAction(undoAct);editMenu->addAction(redoAct);editMenu->addSeparator();   //分隔线editMenu->addAction(cutAct);editMenu->addAction(copyAct);editMenu->addAction(pasteAct);

“编辑” 主菜单的运行效果:

2.3 格式 主菜单

“格式”主菜单功能项应包含:

  • 字体D
    • 加粗B、倾斜I、下画线U
  • 段落
    • 左对齐L、居中E、右对齐R、两端对齐J
  • 颜色C

这是多级菜单了,在“myword.h”中,定义“格式”主菜单及其自菜单的指针:

    QMenu *formatMenu;QMenu *fontMenu;            //子菜单QMenu *alignMenu;           //子菜单QAction *boldAct;           //【格式】主菜单QAction *italicAct;QAction *underlineAct;QAction *leftAlignAct;QAction *centerAct;QAction *rightAlignAct;QAction *justifyAct;QAction *colorAct;

在“myword.cpp”文件,函数 createActions() 的代码中添加:

    /*【格式】菜单动作集*/boldAct = new QAction(QIcon(rsrcPath + "/textbold.png"),tr("加粗(&B)"), this);boldAct->setCheckable(true);boldAct->setShortcut(Qt::CTRL + Qt::Key_B);boldAct->setToolTip("加粗");boldAct->setStatusTip(tr("将所选文字加粗"));QFont bold;bold.setBold(true);boldAct->setFont(bold);connect(boldAct, SIGNAL(triggered()), this, SLOT(textBold()));italicAct = new QAction(QIcon(rsrcPath + "/textitalic.png"),tr("倾斜(&I)"), this);italicAct->setCheckable(true);italicAct->setShortcut(Qt::CTRL + Qt::Key_I);italicAct->setToolTip("倾斜");italicAct->setStatusTip(tr("将所选文字用斜体显示"));QFont italic;italic.setItalic(true);italicAct->setFont(italic);connect(italicAct, SIGNAL(triggered()), this, SLOT(textItalic()));underlineAct = new QAction(QIcon(rsrcPath + "/textunder.png"),tr("下划线(&U)"), this);underlineAct->setCheckable(true);underlineAct->setShortcut(Qt::CTRL + Qt::Key_U);underlineAct->setToolTip("下划线");underlineAct->setStatusTip(tr("给所选文字加下划线"));QFont underline;underline.setUnderline(true);underlineAct->setFont(underline);connect(underlineAct, SIGNAL(triggered()), this, SLOT(textUnderline()));//【格式】→【段落】子菜单下的各项为同一个菜单项组,只能选中其中一项QActionGroup *grp = new QActionGroup(this);connect(grp, SIGNAL(triggered(QAction*)), this, SLOT(textAlign(QAction*)));if (QApplication::isLeftToRight()) {leftAlignAct = new QAction(QIcon(rsrcPath + "/textleft.png"),tr("左对齐(&L)"), grp);centerAct = new QAction(QIcon(rsrcPath + "/textcenter.png"),tr("居中(&E)"), grp);rightAlignAct = new QAction(QIcon(rsrcPath + "/textright.png"),tr("右对齐(&R)"), grp);} else {rightAlignAct = new QAction(QIcon(rsrcPath + "/textright.png"),tr("右对齐(&R)"), grp);centerAct = new QAction(QIcon(rsrcPath + "/textcenter.png"),tr("居中(&E)"), grp);leftAlignAct = new QAction(QIcon(rsrcPath + "/textleft.png"),tr("左对齐(&L)"), grp);}justifyAct = new QAction(QIcon(rsrcPath + "/textjustify.png"),tr("两端对齐(&J)"), grp);leftAlignAct->setShortcut(Qt::CTRL + Qt::Key_L);leftAlignAct->setCheckable(true);leftAlignAct->setToolTip("左对齐");leftAlignAct->setStatusTip(tr("将文字左对齐"));centerAct->setShortcut(Qt::CTRL + Qt::Key_E);centerAct->setCheckable(true);centerAct->setToolTip("居中");centerAct->setStatusTip(tr("将文字居中对齐"));rightAlignAct->setShortcut(Qt::CTRL + Qt::Key_R);rightAlignAct->setCheckable(true);rightAlignAct->setToolTip("右对齐");rightAlignAct->setStatusTip(tr("将文字右对齐"));justifyAct->setShortcut(Qt::CTRL + Qt::Key_J);justifyAct->setCheckable(true);justifyAct->setToolTip("两端对齐");justifyAct->setStatusTip(tr("将文字左右两端同时对齐,并根据需要增加字间距"));QPixmap pix(16, 16);pix.fill(Qt::red);colorAct = new QAction(pix, tr("颜色(&C)..."), this);colorAct->setToolTip("颜色");colorAct->setStatusTip(tr("设置文字颜色"));connect(colorAct, SIGNAL(triggered()), this, SLOT(textColor()));

这里用到了 QActionGroup 类,它将菜单动作分组。

在上面的代码创建了一个 Action 组 grp。由于 Action 组默认是互斥的,所以同一时刻只有一个会被选中。

在“myword.h”文件中,添加 textAlign() 声明,以及对应cpp文件,添加定义:

//myword.h
private slots:void textAlign(QAction *a);//myword.cpp
void MyWord::textAlign(QAction *a)
{}

暂时不写其中的代码,只是定义函数体。

在“myword.cpp”文件,函数 createMenus() 的代码中添加:

    //【格式】主菜单formatMenu = menuBar()->addMenu(tr("格式(&O)"));fontMenu = formatMenu->addMenu(tr("字体(&D)"));   //【字体】子菜单fontMenu->addAction(boldAct);fontMenu->addAction(italicAct);fontMenu->addAction(underlineAct);alignMenu = formatMenu->addMenu(tr("段落"));      //【段落】子菜单alignMenu->addAction(leftAlignAct);alignMenu->addAction(centerAct);alignMenu->addAction(rightAlignAct);alignMenu->addAction(justifyAct);

运行效果如下:

2.4 窗口 和 帮助 主菜单

“窗口”主菜单功能项应包含:关闭O,关闭所有A,平铺T,层叠C,下一个X,前一个V。

在“myword.h”头文件中,定义“窗口”主菜单指针,以及各个功能项的动作:

    QMenu *windowMenu;QAction *closeAct;          //【窗口】主菜单QAction *closeAllAct;QAction *tileAct;QAction *cascadeAct;QAction *nextAct;QAction *previousAct;QAction *separatorAct;QAction *aboutAct;          //【帮助】主菜单QAction *aboutQtAct;

在“myword.cpp”文件,函数 createActions() 的代码中添加:

    /*【窗口】菜单动作集*/closeAct = new QAction(tr("关闭(&O)"), this);closeAct->setStatusTip(tr("关闭活动文档子窗口"));//connect(closeAct, SIGNAL(triggered()),mdiArea, SLOT(closeActiveSubWindow()));           //不用自己实现closeAllAct = new QAction(tr("关闭所有(&A)"), this);closeAllAct->setStatusTip(tr("关闭所有子窗口"));//connect(closeAllAct, SIGNAL(triggered()),mdiArea, SLOT(closeAllSubWindows()));          //不用自己实现tileAct = new QAction(tr("平铺(&T)"), this);tileAct->setStatusTip(tr("平铺子窗口"));//connect(tileAct, SIGNAL(triggered()), mdiArea, SLOT(tileSubWindows()));                 //不用自己实现cascadeAct = new QAction(tr("层叠(&C)"), this);cascadeAct->setStatusTip(tr("层叠子窗口"));//connect(cascadeAct, SIGNAL(triggered()), mdiArea, SLOT(cascadeSubWindows()));           //不用自己实现nextAct = new QAction(tr("下一个(&X)"), this);nextAct->setShortcuts(QKeySequence::NextChild);nextAct->setStatusTip(tr("移动焦点到下一个子窗口"));//connect(nextAct, SIGNAL(triggered()),mdiArea, SLOT(activateNextSubWindow()));           //不用自己实现previousAct = new QAction(tr("前一个(&V)"), this);previousAct->setShortcuts(QKeySequence::PreviousChild);previousAct->setStatusTip(tr("移动焦点到前一个子窗口"));//connect(previousAct, SIGNAL(triggered()),mdiArea, SLOT(activatePreviousSubWindow()));   //不用自己实现separatorAct = new QAction(this);separatorAct->setSeparator(true);/*【帮助】菜单动作集*/aboutAct = new QAction(tr("关于(&A)"), this);aboutAct->setStatusTip(tr("关于 Myself Word"));//connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));aboutQtAct = new QAction(tr("关于 Qt(&Q)"), this);aboutQtAct->setStatusTip(tr("关于 Qt 库"));//connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); 

在“myword.cpp”文件,函数 createMenus() 的代码中添加:

    //【窗口】主菜单windowMenu = menuBar()->addMenu(tr("窗口(&W)"));//updateWindowMenu();//connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu()));menuBar()->addSeparator();

2.5 图标问题

把图标的问题解决下,主要是路径的问题。

这段改成绝对路径即可。当然,这里可以先不改,后面会创建 qrc 文件来管理资源。

const QString rsrcPath = "D:/qt_project/MyselfWord/images";

3. 工具栏设计

工具栏共有四个工具条,其中三个分别对应 “文件”、“编辑” 和:“格式” 菜单的功能。最后一个为组合选择栏,它提供一组选择框控件。

3.1 工具条开发

在“myword.h”头文件中声明:

class QComboBox;
class QFontComboBox;private:void createToolBars();//工具栏QToolBar *fileToolBar;      //文件 工具条QToolBar *editToolBar;      //编辑 工具条QToolBar *formatToolBar;    //格式 工具条QToolBar *comboToolBar;     //组合选择框QComboBox *comboStyle;      //子控件   标号与编号类型选择框QFontComboBox *comboFont;   //子控件   字体选择框QComboBox *comboSize;       //子控件   字号选择框

在“myword.cpp”实现 createToolBars() 函数,别忘记构造函数添加成员函数:

void MyWord::createToolBars()
{//"文件"工具栏fileToolBar = addToolBar(tr("文件"));fileToolBar->addAction(newAct);fileToolBar->addAction(openAct);fileToolBar->addAction(saveAct);fileToolBar->addSeparator();        //分隔条fileToolBar->addAction(printAct);//"编辑"工具栏editToolBar = addToolBar(tr("编辑"));editToolBar->addAction(undoAct);editToolBar->addAction(redoAct);editToolBar->addSeparator();        //分隔条editToolBar->addAction(cutAct);editToolBar->addAction(copyAct);editToolBar->addAction(pasteAct);//"格式"工具栏formatToolBar = addToolBar(tr("格式"));formatToolBar->addAction(boldAct);formatToolBar->addAction(italicAct);formatToolBar->addAction(underlineAct);formatToolBar->addSeparator();      //分隔条formatToolBar->addAction(leftAlignAct);formatToolBar->addAction(centerAct);formatToolBar->addAction(rightAlignAct);formatToolBar->addAction(justifyAct);formatToolBar->addSeparator();      //分隔条formatToolBar->addAction(colorAct);//组合工具栏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())));
}

3.2 导入图标资源

图片资源存放在 D:\qt_project\MyselfWord 下。

给工程项目添加 Qt Resource File,也就是 qrc 后缀的文件。

添加以下内容:

<RCC><qresource prefix="/"><file>images/editcopy.png</file><file>images/editcut.png</file><file>images/editpaste.png</file><file>images/editredo.png</file><file>images/editundo.png</file><file>images/filenew.png</file><file>images/fileopen.png</file><file>images/fileprint.png</file><file>images/filesave.png</file><file>images/textbold.png</file><file>images/textcenter.png</file><file>images/textitalic.png</file><file>images/textjustify.png</file><file>images/textleft.png</file><file>images/textright.png</file><file>images/textunder.png</file></qresource>
</RCC>

在 “myword.cpp”文件开头添加资源路径:

const QString rsrcPath = ":/images";

然后,运行效果如下:

4. 子窗口管理

4.1 新建子窗口

前面已经建立了子窗口的中心部件 MyChild 类,它继承自 QTextEDit 类。

下面便可以使用这个类来创建文档子窗口。

“myword.h”

class MyChild;private slots:void fileNew();MyChild *createMyChild();

“myword.cpp” 

#include "mychild.h"
MyChild *MyWord::createMyChild()
{MyChild *child = new MyChild;mdiArea->addSubWindow(child);connect(child, SIGNAL(copyAvailable(bool)),cutAct, SLOT(setEnabled(bool)));connect(child, SIGNAL(copyAvailable(bool)),copyAct, SLOT(setEnabled(bool)));return child;
}

 函数 createActions() 中,去掉注释。

connect(newAct, SIGNAL(triggered()), this, SLOT(fileNew()));
void MyWord::fileNew()
{MyChild *child = createMyChild();child->newFile();child->show();enabledText();              //使得字体设置菜单可用
}

 “myword.h”

private:void enabledText();         //使得【格式】下的各个子菜单项可用

 “myword.cpp” 

void MyWord::enabledText()
{boldAct->setEnabled(true);italicAct->setEnabled(true);underlineAct->setEnabled(true);leftAlignAct->setEnabled(true);centerAct->setEnabled(true);rightAlignAct->setEnabled(true);justifyAct->setEnabled(true);colorAct->setEnabled(true);
}

文件 → 新建,出现 “文档1” 子窗口。

4.2 更新菜单状态

在“myword.h” 

class QMdiSubWindow;private slots:void updateMenus();    //更新菜单private:MyChild *activeMyChild();   //活动窗口

在“myword.cpp”

connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)),this, SLOT(updateMenus()));
updateMenus();

 updateMenus() 函数


void MyWord::updateMenus()
{//至少有一个子文档打开着的情况bool hasMyChild = (activeMyChild()!=0);saveAct->setEnabled(hasMyChild);saveAsAct->setEnabled(hasMyChild);printAct->setEnabled(hasMyChild);printPreviewAct->setEnabled(hasMyChild);pasteAct->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 = (activeMyChild() && activeMyChild()->textCursor().hasSelection());cutAct->setEnabled(hasSelection);copyAct->setEnabled(hasSelection);boldAct->setEnabled(hasSelection);italicAct->setEnabled(hasSelection);underlineAct->setEnabled(hasSelection);leftAlignAct->setEnabled(hasSelection);centerAct->setEnabled(hasSelection);rightAlignAct->setEnabled(hasSelection);justifyAct->setEnabled(hasSelection);colorAct->setEnabled(hasSelection);
}

activeMyChild() 函数

MyChild *MyWord::activeMyChild()
{if (QMdiSubWindow *activeSubWindow = mdiArea->activeSubWindow())return qobject_cast<MyChild *>(activeSubWindow->widget());return 0;
}

4.3 添加子窗口列表

“myword.h”

class QSignalMapper;private:QSignalMapper *windowMapper;private slots:void updateWindowMenu();

“myword.cpp”

windowMapper = new QSignalMapper(this);
connect(windowMapper, SIGNAL(mapped(QWidget*)),this, SLOT(setActiveSubWindow(QWidget*)));
updateWindowMenu();
connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu()));

void MyWord::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) {MyChild *child = qobject_cast<MyChild *>(windows.at(i)->widget());QString text;if (i < 9) {text = tr("&%1 %2").arg(i + 1).arg(child->userFriendlyCurrentFile());} else {text = tr("%1 %2").arg(i + 1).arg(child->userFriendlyCurrentFile());}QAction *action  = windowMenu->addAction(text);action->setCheckable(true);action ->setChecked(child == activeMyChild());connect(action, SIGNAL(triggered()), windowMapper, SLOT(map()));windowMapper->setMapping(action, windows.at(i));}enabledText();          //使得字体设置菜单可用
}

4.4 窗口关闭

protected:void closeEvent(QCloseEvent *event);
void MyWord::closeEvent(QCloseEvent *event)
{mdiArea->closeAllSubWindows();if (mdiArea->currentSubWindow()) {event->ignore();} else {event->accept();}
}

新建四个文档,然后窗口菜单的显示效果。

然后,点击“关闭”就会把当前活动的文档关闭,点击 “关闭所有”,就会把全部的4个文档关闭。

5. 界面生成试运行

private:void createStatusBar();
void MyWord::createStatusBar()
{statusBar()->showMessage(tr("就绪"));
}

三、基本编辑功能实现

开发好软件界面后,就可以向系统中添加各种各样的功能。

首先实现的基本编辑功能包括:打开、保存、另存为、剪切、复制、粘贴、撤销和回复。

1. 打开文件

实现打开文件功能需要在子窗口类 MyChild 中定义加载文件操作。

1.1 加载文件操作步骤

1)打开指定的文件,并读取文件内容到编辑器。

2)设置当前文件的 setCurrentFile() ,该函数可以获取文件路径,完成文件和窗口状态的设置。

3)关联文档内容改变信号到显示文档更改状态槽 documentWasModified() 。

加载文件操作采用 loadFile() 函数实现。

1.2 加载文件操作实现

//mychild.h
public:bool loadFile(const QString &fileName);
private:void setCurrentFile(const QString &fileName);//mychild.cpp
bool MyChild::loadFile(const QString &fileName)
{if (fileName.isEmpty())return false;QFile file(fileName);if (!file.exists()) {qWarning() << "File does not exist:" << fileName;return false;}if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {qWarning() << "Failed to open file for reading:" << fileName;return false;}// 假设文件是以 UTF-8 编码的,这是 HTML 文件的常见情况QTextStream in(&file);QString content = in.readAll();// 不再需要 QTextCodec,因为我们已经读取了 UTF-8 编码的字符串// 检查内容是否为富文本(这里简单假设 HTML 就是富文本)if (content.contains("<html>") || content.contains("<HTML>")) { // 简单的检查,可能不够准确this->setHtml(content);} else {// 如果不是明显的 HTML,我们可以尝试将其视为纯文本// 注意:这里我们不再转换编码,因为 content 已经是 QString 了this->setPlainText(content);}setCurrentFile(fileName);// 连接信号和槽以监控文档更改(这部分看起来没问题)connect(document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));return true;
}
void MyChild::setCurrentFile(const QString &fileName)
{curFile = QFileInfo(fileName).canonicalFilePath();isUntitled = false;document()->setModified(false);setWindowModified(false);setWindowTitle(userFriendlyCurrentFile() + "[*]");
}

1.3 加载文件操作的调用

//myword.h
private slots:void fileOpen();
privete:QMdiSubWindow *findMyChild(const QString &fileName);//myword.cpp
void MyWord::createActions()
{connect(newAct, SIGNAL(triggered()), this, SLOT(fileNew()));
}void MyWord::fileOpen()
{QString fileName = QFileDialog::getOpenFileName(this, tr("打开"),QString(), tr("HTML 文档 (*.htm *.html);;所有文件 (*.*)"));if (!fileName.isEmpty()) {QMdiSubWindow *existing = findMyChild(fileName);if (existing) {mdiArea->setActiveSubWindow(existing);return;}MyChild *child = createMyChild();if (child->loadFile(fileName)) {statusBar()->showMessage(tr("文件已载入"), 2000);child->show();enabledText();      //使得字体设置菜单可用} else {child->close();}}    
}
//打开文件用
QMdiSubWindow *MyWord::findMyChild(const QString &fileName)
{QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();foreach (QMdiSubWindow *window, mdiArea->subWindowList()) {MyChild *myChild = qobject_cast<MyChild *>(window->widget());if (myChild->currentFile() == canonicalFilePath)return window;}return 0;
}

提取准备一个1.html在bulid的Debug目录下。

2. 保存文件操作实现

保存文件功能分为“保存”和“另存为”两种操作,这两种操作都需要在子窗口 MyChild 中定义。

2.1 保存文件操作步骤

保存 save() 的逻辑

1)如果文件没有被保存过(用 isUntitled 判断),则执行 “另存为” 操作 saveAs()。

2)否则直接 “保存” 文件 saveFile(),改函数首先打开指定文件,然后将编辑器的内容写入该文件,最后设置当前文件 setCurrentFile()。

另存为 saveAs() 的逻辑

1)从“文件”对话框获取文件路径。

2)如果路径不为空,则保存文件 saveFile()。

2.2 保存文件操作实现

//mychild.h
public:bool save();bool saveAs();bool saveFile(QString fileName);//mychild.cpp
bool MyChild::save()
{if (isUntitled) {return saveAs();} else {return saveFile(curFile);}
}bool MyChild::saveAs()
{QString fileName = QFileDialog::getSaveFileName(this, tr("另存为"),curFile,tr("HTML 文档 (*.htm *.html);;所有文件 (*.*)"));if (fileName.isEmpty())return false;return saveFile(fileName);
}bool MyChild::saveFile(QString fileName)
{if (!(fileName.endsWith(".htm", Qt::CaseInsensitive) || fileName.endsWith(".html", Qt::CaseInsensitive))) {fileName += ".html"; // 默认保存为 HTML 文档}QTextDocumentWriter writer(fileName);bool success = writer.write(this->document());if (success)setCurrentFile(fileName);return success;
}

2.3 保存文件操作调用

void MyWord::createActions()
{connect(saveAct, SIGNAL(triggered()), this, SLOT(fileSave()));connect(saveAsAct, SIGNAL(triggered()), this, SLOT(fileSaveAs()));
}
//myword.h
private slots:void fileSave();void fileSaveAs();//myword.cpp
void MyWord::fileSave()
{if (activeMyChild() && activeMyChild()->save())statusBar()->showMessage(tr("保存成功"), 2000);
}void MyWord::fileSaveAs()
{if (activeMyChild() && activeMyChild()->saveAs())statusBar()->showMessage(tr("保存成功"), 2000);
}

2.4 提醒保存文件

//mychild.h
private:bool maybeSave();
protected:void closeEvent(QCloseEvent *event);//mychild.cpp
bool MyChild::maybeSave()
{if (!document()->isModified())return true;QMessageBox::StandardButton ret;ret = QMessageBox::warning(this, tr("Myself Qt Word"),tr("文档'%1'已被修改,保存吗?").arg(userFriendlyCurrentFile()),QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);if (ret == QMessageBox::Save)return save();else if (ret == QMessageBox::Cancel)return false;return true;
}void MyChild::closeEvent(QCloseEvent *event)
{if (maybeSave()) {event->accept();} else {event->ignore();}
}

3. 文本操作

最基本的文本操作包括:撤销、重做、剪切、复制和粘贴。又QTextEdit 类提供。

3.1 撤销与重做

编辑菜单动作集

connect(undoAct, SIGNAL(triggered()), this, SLOT(undo()));      //不用子窗口类去实现
connect(redoAct, SIGNAL(triggered()), this, SLOT(redo()));      //不用子窗口类去实现

3.2 剪切、复制和粘贴

connect(cutAct, SIGNAL(triggered()), this, SLOT(cut())); 
connect(copyAct, SIGNAL(triggered()), this, SLOT(copy())); 
connect(pasteAct, SIGNAL(triggered()), this, SLOT(paste()));    //不用子窗口类去实现
//myword.h
private slots:void undo();void redo();void cut();void copy();void paste();//myword.cpp
void MyWord::undo()
{if(activeMyChild())activeMyChild()->undo();
}void MyWord::redo()
{if(activeMyChild())activeMyChild()->redo();
}void MyWord::cut()
{if (activeMyChild())activeMyChild()->cut();
}void MyWord::copy()
{if (activeMyChild())activeMyChild()->copy();
}void MyWord::paste()
{if (activeMyChild())activeMyChild()->paste();
}

到此,功能完成的差不多了。

四、文档排版美化功能实现

1. 字体格式设置

基本设置包括:加粗、倾斜和加下划线。

1.1 子窗口的操作

//mychild.h
pubilc:void mergeFormatOnWordOrSelection(const QTextCharFormat &format);   //格式字体设置//mychild.cpp
//格式设置
void MyChild::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
{QTextCursor cursor = this->textCursor();if (!cursor.hasSelection())cursor.select(QTextCursor::WordUnderCursor);cursor.mergeCharFormat(format);this->mergeCurrentCharFormat(format);
}

1.2 主窗口调用格式函数

connect(boldAct, SIGNAL(triggered()), this, SLOT(textBold()));
connect(italicAct, SIGNAL(triggered()), this, SLOT(textItalic()));
connect(underlineAct, SIGNAL(triggered()), this, SLOT(textUnderline()));
//myword.h
private slots:void textBold();void textItalic();void textUnderline();//myword.cpp
void MyWord::textBold()
{QTextCharFormat fmt;fmt.setFontWeight(boldAct->isChecked() ? QFont::Bold : QFont::Normal);if(activeMyChild())activeMyChild()->mergeFormatOnWordOrSelection(fmt);
}void MyWord::textItalic()
{QTextCharFormat fmt;fmt.setFontItalic(italicAct->isChecked());if(activeMyChild())activeMyChild()->mergeFormatOnWordOrSelection(fmt);
}void MyWord::textUnderline()
{QTextCharFormat fmt;fmt.setFontUnderline(underlineAct->isChecked());if(activeMyChild())activeMyChild()->mergeFormatOnWordOrSelection(fmt);
}

1.3 字体、字号选择框

void MyWord::createToolBars(){connect(comboFont, SIGNAL(activated(QString)), this, SLOT(textFamily(QString)));connect(comboSize, SIGNAL(activated(QString)), this, SLOT(textSize(QString)));comboSize->setCurrentIndex(comboSize->findText(QString::number(QApplication::font().pointSize())));
}
//myword.h
private slots:void textFamily(const QString &f);void textSize(const QString &p);//myword.cpp
void MyWord::textFamily(const QString &f)
{QTextCharFormat fmt;fmt.setFontFamily(f);if(activeMyChild())activeMyChild()->mergeFormatOnWordOrSelection(fmt);
}void MyWord::textSize(const QString &p)
{qreal pointSize = p.toFloat();if (p.toFloat() > 0) {QTextCharFormat fmt;fmt.setFontPointSize(pointSize);if(activeMyChild())activeMyChild()->mergeFormatOnWordOrSelection(fmt);}
}

这边5代和6代Qt,有一定的不同。

2. 段落对齐设置

//mychild.h
public:void setAlign(int align);//mychild.cpp
//段落对齐设置
void MyChild::setAlign(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);
}
//myword.cpp
void MyWord::textAlign(QAction *a)
{if(activeMyChild()){if (a == leftAlignAct)activeMyChild()->setAlign(1);else if (a == centerAct)activeMyChild()->setAlign(2);else if (a == rightAlignAct)activeMyChild()->setAlign(3);else if (a == justifyAct)activeMyChild()->setAlign(4);}
}

3. 颜色设置

//Action
connect(colorAct, SIGNAL(triggered()), this, SLOT(textColor()));
//myword.h
private:void colorChanged(const QColor &c);private slots:void textColor();//myword.cpp
void MyWord::textColor()
{if(activeMyChild()){QColor col = QColorDialog::getColor(activeMyChild()->textColor(), this);if (!col.isValid())return;QTextCharFormat fmt;fmt.setForeground(col);activeMyChild()->mergeFormatOnWordOrSelection(fmt);colorChanged(col);}
}void MyWord::colorChanged(const QColor &c)
{QPixmap pix(16, 16);pix.fill(c);colorAct->setIcon(pix);
}

4. 段落标号、编号

4.1 子窗口设置段落标号、编号操作

//mychild.h
public:void setStyle(int style);//mychild.cpp
//段落标号、编号
void MyChild::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);}
}

4.2 实现段落标号、编号选择框

//createToolBars()
//组合工具栏
connect(comboStyle, SIGNAL(activated(int)), this, SLOT(textStyle(int)));

4.3 主窗口调用

//myword.h
private slots:void textStyle(int styleIndex);//myword.cpp
void MyWord::textStyle(int styleIndex)
{if(activeMyChild()){activeMyChild()->setStyle(styleIndex);}
}

5. 文档打印与预览

5.1 添加打印模块支持

在 MyselfWord.pro 中添加支持:

//6代QT
QT += printsupport//5代QT
qtHaveModule(printsupport): QT += printsupport

5.2 实现打印及预览功能 

//Action
connect(printAct, SIGNAL(triggered()), this, SLOT(filePrint()));connect(printPreviewAct, SIGNAL(triggered()), this, SLOT(filePrintPreview()));
//myword.h
private slots:void filePrint();void filePrintPreview();void printPreview(QPrinter *);//myword.cpp
void MyWord::filePrint()
{QPrinter printer(QPrinter::HighResolution);QPrintDialog *dlg = new QPrintDialog(&printer, this);if (activeMyChild()->textCursor().hasSelection())//6代QT//dlg->setOption(QAbstractPrintDialog::PrintSelection);dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection);dlg->setWindowTitle(tr("打印文档"));if (dlg->exec() == QDialog::Accepted)activeMyChild()->print(&printer);delete dlg;
}void MyWord::filePrintPreview()
{QPrinter printer(QPrinter::HighResolution);QPrintPreviewDialog preview(&printer, this);connect(&preview, SIGNAL(paintRequested(QPrinter*)), SLOT(printPreview(QPrinter*)));preview.exec();
}void MyWord::printPreview(QPrinter *printer)
{activeMyChild()->print(printer);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/5127.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【物联网】keil仿真环境设置 keilV5可以适用ARM7

文章目录 一、ARM指令模拟器环境搭建1. keil软件2. Legacy Support 二、Keil仿真环境设置1. 创建一个项目2. 编译器介绍(1)arm-none-eabi-gcc(2)arm-none-linux-gnueabi-gcc(3)arm-eabi-gcc(4)grmcc(5)aarch64-linux-gnu-gcc 3. 安装编译器(1)设置调试 一、ARM指令模拟器环境搭…

StackOrQueueOJ3:用栈实现队列

目录 题目描述思路分析开辟队列入队列出队列 代码展示 题目描述 原题&#xff1a;232. 用栈实现队列 思路分析 有了前面的用队列实现栈的基础我们不难想到这题的基本思路&#xff0c;也就是用两个栈来实现队列&#xff0c;&#xff08;栈的实现具体参考&#xff1a;栈及其接口…

二叉树--堆排序

我们之前学过冒泡排序算法&#xff0c;还有其他的排序算法之类的&#xff0c;我们今天来讲堆排序算法&#xff1b; 假设我们现在有一个数组&#xff0c;我们想要对其进行排序&#xff0c;我们可以使用冒泡排序来进行排序&#xff1b;我们也可以使用堆排序来进行排序&#xff1b…

简述mysql 主从复制原理及其工作过程,配置一主两从并验证

第一种基于binlog的主从同步 首先对主库进行配置&#xff1a; [rootopenEuler-1 ~]# vim /etc/my.cnf 启动服务 [rootopenEuler-1 ~]# systemctl enable --now mysqld 主库的配置 从库的配置 第一个从库 [rootopenEuler-1 ~]# vim /etc/my.cnf [rootopenEuler-1 ~]# sys…

【技术总结类】2024,一场关于海量数据治理以及合理建模的系列写作

目录 1.今年的创作路线 2.先说第一条线 2.1.由日志引出的海量文本数据存储和分析问题 2.2.监控以及监控的可视化 2.3.数据量级再往上走牵扯出了大数据 2.4.由大数据牵扯出的JAVA线程高级内容 3.第二条线&#xff0c;也是2025要继续的主线 1.今年的创作路线 今年的写作内…

用于牙科的多任务视频增强

Multi-task Video Enhancement for Dental Interventions 2022 miccai Abstract 微型照相机牢牢地固定在牙科手机上&#xff0c;这样牙医就可以持续地监测保守牙科手术的进展情况。但视频辅助牙科干预中的视频增强减轻了低光、噪音、模糊和相机握手等降低视觉舒适度的问题。…

Hnu电子电路实验2

目录 【说明】 与本次实验相关的代码及报告等文件见以下链接&#xff1a; 一、实验目的 二、实验内容 三&#xff1a;实验原理 1.指令译码器 2.AU 算术单元 四&#xff1a;实验过程 1.指令译码器 A&#xff09;创建工程&#xff08;选择的芯片为 familyCyclone II&am…

C语言之图像文件的属性

&#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 图像文件属性提取系统设计与实现 目录 设计题目设计内容系统分析总体设计详细设计程序实现…

AI 新动态:技术突破与应用拓展

目录 一.大语言模型的持续进化 二.AI 在医疗领域的深度应用 疾病诊断 药物研发 三.AI 与自动驾驶的新进展 四.AI 助力环境保护 应对气候变化 能源管理 后记 在当下科技迅猛发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;无疑是最具影响力的领域之一。AI 技…

ElasticSearch DSL查询之排序和分页

一、排序功能 1. 默认排序 在 Elasticsearch 中&#xff0c;默认情况下&#xff0c;查询结果是根据 相关度 评分&#xff08;score&#xff09;进行排序的。我们之前已经了解过&#xff0c;相关度评分是通过 Elasticsearch 根据查询条件与文档内容的匹配程度自动计算得出的。…

【NLP基础】Word2Vec 中 CBOW 指什么?

【NLP基础】Word2Vec 中 CBOW 指什么&#xff1f; 重要性&#xff1a;★★ CBOW 模型是根据上下文预测目标词的神经网络&#xff08;“目标词”是指中间的单词&#xff0c;它周围的单词是“上下文”&#xff09;。通过训练这个 CBOW 模型&#xff0c;使其能尽可能地进行正确的…

资料03:【TODOS案例】微信小程序开发bilibili

样式 抽象数据类型 页面数据绑定 事件传参

vim文本编辑器

vim命令的使用&#xff1a; [rootxxx ~]# touch aa.txt #首先创建一个文件 [rootxxx ~]# vim aa.txt #vim进入文件aa.txt进行编辑 vim是vi的升级版&#xff0c;具有以下三种基本模式&#xff1a; 输入模式(编辑模式) 点击i进入编辑模式 &#xff08;说明…

(undone) 并行计算学习 (Day2: 什么是 “伪共享” ?)

伪共享是什么&#xff1f; TODO: 这里补点文档&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 缓存一致性、同步的代价&#xff01;&#xff01;&#xff01; 也就是&#xff0c;当不同线程所访问的内存元素恰好在同一个 cache line 上时&#xf…

基于python的博客系统设计与实现

摘要&#xff1a;目前&#xff0c;对于信息的获取是十分的重要&#xff0c;我们要做到的不是裹足不前&#xff0c;而是应该主动获取和共享给所有人。博客系统就能够实现信息获取与分享的功能&#xff0c;博主在发表文章后&#xff0c;互联网上的其他用户便可以看到&#xff0c;…

使用插件SlideVerify实现滑块验证

作者gitee地址&#xff1a;https://gitee.com/monoplasty/vue-monoplasty-slide-verify 使用步骤&#xff1a; 1、安装插件 npm install --save vue-monoplasty-slide-verify 2、在main.js中进行配置 import SlideVerify from vue-monoplasty-slide-verify; Vue.use(SlideV…

【深度学习项目】语义分割-FCN网络(原理、网络架构、基于Pytorch实现FCN网络)

文章目录 介绍深度学习语义分割的关键特点主要架构和技术数据集和评价指标总结 FCN网络FCN 的特点FCN 的工作原理FCN 的变体和发展FCN 的网络结构FCN 的实现&#xff08;基于Pytorch&#xff09;1. 环境配置2. 文件结构3. 预训练权重下载地址4. 数据集&#xff0c;本例程使用的…

2024年博客之星主题创作|从零到一:我的技术成长与创作之路

2024年博客之星主题创作&#xff5c;从零到一&#xff1a;我的技术成长与创作之路 个人简介个人主页个人成就热门专栏 历程回顾初来CSDN&#xff1a;怀揣憧憬&#xff0c;开启创作之旅成长之路&#xff1a;从平凡到榜一的蜕变持续分享&#xff1a;打卡基地与成长复盘四年历程&a…

【整体介绍】

ODO&#xff1a;汽车总行驶里程 Chime: 例如安全带没系的报警声音 多屏交互就是中控屏的信息会同步到主驾驶的仪表盘上 面试问题&#xff1a;蓝牙电话协议HFP 音乐协议A2DP 三方通话测试的逻辑

PyTorch使用教程(13)-一文搞定模型的可视化和训练过程监控

一、简介 在现代深度学习的研究和开发中&#xff0c;模型的可视化和监控是不可或缺的一部分。PyTorch&#xff0c;作为一个流行的深度学习框架&#xff0c;通过其丰富的生态系统提供了多种工具来满足这一需求。其中&#xff0c;torch.utils.tensorboard 是一个强大的接口&…