从零开始:用Qt开发一个功能强大的文本编辑器——WPS项目全解析
文章目录
- 引言
- 项目功能介绍
- 1. **文件操作**
- 2. **文本编辑功能**
- 3. **撤销与重做**
- 4. **剪切、复制与粘贴**
- 5. **文本查找与替换**
- 6. **打印功能**
- 7. **打印预览**
- 8. **设置字体颜色**
- 9. **设置字号**
- 10. **设置字体**
- 11. **左对齐**
- 12. **右对齐**
- 13. **居中对齐**
- 14. **两侧对齐**
- 15. **加粗**
- 16. **斜体**
- 17. **下划线**
- 18. **设置项目符号**
- 代码解析(部分)
- 1. **剪切(`cut`)**
- 2. **复制(`copy`)**
- 3. **粘贴(`paste`)**
- 4. **撤销(`undo`)**
- 5. **重做(`redo`)**
- 6. **加粗(`setBold`)**
- 7. **斜体(`setItalic`)**
- 8. **下划线(`setUnderline`)**
- 9. **设置字体(`setFont`)**
- 10. **设置字号(`setSize`)**
- 11. **设置文本颜色(`setTextColor`)**
- 12. **设置背景颜色(`setBackgroundColor`)**
- 13. **设置左对齐(`setLeftAlignment`)**
- 14. **设置居中对齐(`setCenterAlignment`)**
- 15. **设置右对齐(`setRightAlignment`)**
- 源代码
- mainwindow.h
- textedit.h
- mainwindow.cpp
- textedit.cpp
- main.cpp
- 总结
- 1. **初始化与UI设置**
- 2. **文本操作功能**
- 3. **文本格式化功能**
- 4. **文本对齐功能**
- 5. **功能实现的信号与槽机制**
引言
文本编辑器是每个程序员日常工作中不可或缺的工具,而开发一个属于自己的文本编辑器则是许多开发者的梦想。作为一名开发者,我也一直渴望能够打造一个既简单高效,又能满足个性化需求的文本编辑器。经过一段时间的探索与实践,我终于完成了这个项目——WPS,一个基于Qt框架开发的文本编辑器。
在这篇博客中,我将详细介绍如何利用Qt开发一个具备文件操作、文本编辑、撤销重做等常用功能的文本编辑器。我会从项目的设计思路、功能实现、代码分析等方面进行详细讲解,并分享开发过程中遇到的挑战及解决方案。无论你是刚接触Qt的初学者,还是想要深入理解Qt应用开发的开发者,都可以从中获得一些启发与技巧。
项目功能介绍
在这个项目中,WPS文本编辑器 实现了一些常见且实用的文本编辑功能,旨在提供一个简单高效的写作和编辑体验。以下是本项目所具备的主要功能:
1. 文件操作
- 新建文件:用户可以创建一个新的空白文本文件,开始书写或编辑。
- 打开文件:用户可以从本地磁盘中选择一个现有文件并加载到编辑器中,支持标准的文本文件格式(如
.txt
)。 - 保存文件:支持将编辑器中的内容保存到指定的文件路径中。用户也可以选择“另存为”来保存为不同的文件名或路径。
- 文件另存为:提供了将当前编辑的文件另存为不同文件名或路径的功能,便于文件版本管理。
2. 文本编辑功能
- 文本输入与编辑:用户可以在编辑器中自由输入文本,支持文本的插入与删除。
- 文本格式化:提供基本的文本格式化功能,如字体、字号、颜色等调整,满足用户对文本样式的基本需求。
- 文本对齐与换行:支持文本的左对齐、右对齐、居中对齐等基本对齐操作,以及自动换行功能,保证文本编辑的灵活性与美观性。
3. 撤销与重做
- 撤销:允许用户在误操作或修改后,快速撤回到之前的状态,使得编辑过程更加安全和无忧。
- 重做:支持撤销操作的反向恢复,方便用户重新进行某些操作,提升编辑的灵活性。
4. 剪切、复制与粘贴
- 剪切:用户可以将选中的文本剪切,并保存在剪贴板中,方便移动文本内容。
- 复制:复制选中的文本,保留原内容不变,用户可以在其他地方粘贴。
- 粘贴:将剪贴板中的内容粘贴到当前文本光标位置。
5. 文本查找与替换
- 查找功能:允许用户在文本中进行关键字查找,定位到相应内容。
- 替换功能:提供查找到指定文本后,将其替换为新的文本内容,提升编辑效率。
6. 打印功能
打印功能允许用户将文本内容直接打印到纸张上。用户可以通过点击“打印”按钮来调用系统默认的打印对话框,选择打印机及其他打印设置,并将当前文档打印出来。
7. 打印预览
打印预览功能提供用户在实际打印前预览文档的打印效果。这可以帮助用户查看文本是否排版正确,是否需要调整格式,确保打印效果符合预期。用户通过点击“打印预览”按钮来进入此模式。
8. 设置字体颜色
用户可以通过此功能设置文本的字体颜色。点击“设置字体颜色”按钮后,会弹出颜色选择框,用户可以选择不同的颜色以改变文本的显示效果。这个功能帮助用户根据需要突出显示或装饰文本内容。
9. 设置字号
通过设置字号,用户可以调整文本的大小。点击“设置字号”按钮后,用户可以从下拉菜单中选择一个预设的字号,或者输入自定义的数字值,以改变文档中所有或选定部分文本的显示大小。
10. 设置字体
该功能允许用户选择文本的字体。通过点击“设置字体”按钮,用户可以从字体选择框中选择不同的字体样式,如“宋体”,“Arial”,或“Times New Roman”等,从而调整文档的整体风格。
11. 左对齐
左对齐功能将文本与页面的左边缘对齐。用户可以点击“左对齐”按钮,确保段落中的文本从左边缘开始显示,常用于大多数书面内容。
12. 右对齐
右对齐功能将文本与页面的右边缘对齐。点击“右对齐”按钮后,用户可以将段落中的文本从右边缘开始显示,这对于一些语言(如阿拉伯语)或特殊排版是非常重要的。
13. 居中对齐
居中对齐功能将文本居中显示在页面上。点击“居中对齐”按钮后,文中的所有文本会被自动居中,确保文本在页面上的位置对称且整齐。
14. 两侧对齐
两侧对齐(即“对齐两端”)功能使文本在左右两端同时对齐。这会通过调整单词之间的间距来实现文本两端对齐,通常用于报纸、杂志等印刷物的排版。
15. 加粗
加粗功能允许用户将文本设置为加粗格式。点击“加粗”按钮后,选中的文本将显示为加粗样式,常用于突出显示重要的内容或标题。
16. 斜体
斜体功能允许用户将文本设置为斜体样式。点击“斜体”按钮后,选中的文本将倾斜,通常用于强调、书名、外语词汇或引用内容。
17. 下划线
下划线功能为选定的文本添加下划线效果。点击“下划线”按钮后,文本下方会出现一条线,通常用于强调或标注链接文本。
18. 设置项目符号
设置项目符号功能允许用户在文本中插入项目符号(例如:圆点、方块等)并创建无序列表。用户可以通过点击“项目符号”按钮,快速将选中的段落转化为项目符号列表,帮助整理和清晰地展示信息。此功能适用于创建清单、步骤说明等。
代码解析(部分)
1. 剪切(cut
)
void TextEditor::cut()
{QTextCursor cursor = textEdit->textCursor(); // 获取当前光标位置if (cursor.hasSelection()) {textEdit->cut(); // 如果有选中的文本,执行剪切操作}
}
textEdit->textCursor()
获取当前QTextEdit
控件的文本光标 (QTextCursor
)。cursor.hasSelection()
检查当前光标位置是否有选中的文本。- 如果有选中的文本,调用
textEdit->cut()
执行剪切操作,将选中的文本从编辑器中删除,并复制到剪贴板。
2. 复制(copy
)
void TextEditor::copy()
{QTextCursor cursor = textEdit->textCursor(); // 获取当前光标位置if (cursor.hasSelection()) {textEdit->copy(); // 如果有选中的文本,执行复制操作}
}
textEdit->textCursor()
获取当前的文本光标。cursor.hasSelection()
检查是否选中了文本。- 如果选中了文本,调用
textEdit->copy()
将选中的文本复制到剪贴板。
3. 粘贴(paste
)
void TextEditor::paste()
{textEdit->paste(); // 将剪贴板的内容粘贴到光标当前位置
}
textEdit->paste()
会将剪贴板中的内容粘贴到当前光标的位置。如果剪贴板没有内容,则不会有任何变化。
4. 撤销(undo
)
void TextEditor::undo()
{textEdit->undo(); // 撤销上一步操作
}
textEdit->undo()
执行撤销操作,即撤回上一步在文本编辑器中做的更改。例如,撤回输入的文字或删除的内容。
5. 重做(redo
)
void TextEditor::redo()
{textEdit->redo(); // 重做上一步撤销的操作
}
textEdit->redo()
执行重做操作,即将撤销的操作恢复。如果没有撤销操作,则此操作无效。
6. 加粗(setBold
)
void TextEditor::setBold()
{QTextCharFormat format;format.setFontWeight(QFont::Bold); // 设置字体为加粗textEdit->mergeCurrentCharFormat(format); // 将格式应用到当前选中的文本
}
QTextCharFormat format
创建一个QTextCharFormat
对象,用来设置文本格式。format.setFontWeight(QFont::Bold)
设置字体加粗。textEdit->mergeCurrentCharFormat(format)
将新的字体格式应用到当前选中的文本。
7. 斜体(setItalic
)
void TextEditor::setItalic()
{QTextCharFormat format;format.setFontItalic(true); // 设置字体为斜体textEdit->mergeCurrentCharFormat(format); // 将格式应用到当前选中的文本
}
format.setFontItalic(true)
设置字体为斜体。textEdit->mergeCurrentCharFormat(format)
将斜体格式应用到当前选中的文本。
8. 下划线(setUnderline
)
void TextEditor::setUnderline()
{QTextCharFormat format;format.setFontUnderline(true); // 设置字体为下划线textEdit->mergeCurrentCharFormat(format); // 将格式应用到当前选中的文本
}
format.setFontUnderline(true)
设置字体加下划线。textEdit->mergeCurrentCharFormat(format)
将下划线格式应用到当前选中的文本。
9. 设置字体(setFont
)
void TextEditor::setFont()
{bool ok;QFont font = QFontDialog::getFont(&ok, textEdit->currentFont(), this); // 弹出字体选择对话框if (ok) {textEdit->setCurrentFont(font); // 设置当前文本编辑框的字体}
}
QFontDialog::getFont(&ok, textEdit->currentFont(), this)
弹出一个字体选择对话框,允许用户选择字体。如果用户点击确认,返回选择的字体。textEdit->setCurrentFont(font)
将用户选择的字体设置到文本编辑器中。
10. 设置字号(setSize
)
void TextEditor::setSize()
{bool ok;int size = QInputDialog::getInt(this, tr("选择字号"), tr("字号:"), textEdit->currentFont().pointSize(), 1, 72, 1, &ok); // 弹出字号输入框if (ok) {QFont font = textEdit->currentFont();font.setPointSize(size); // 设置字体大小textEdit->setCurrentFont(font); // 更新文本编辑器字体}
}
QInputDialog::getInt
弹出一个输入框,允许用户选择字号。font.setPointSize(size)
设置新的字体大小。textEdit->setCurrentFont(font)
更新文本编辑器中的字体。
11. 设置文本颜色(setTextColor
)
void TextEditor::setTextColor()
{QColor color = QColorDialog::getColor(textEdit->textColor(), this); // 弹出颜色选择对话框if (color.isValid()) {QTextCharFormat format;format.setForeground(color); // 设置前景色(文本颜色)textEdit->mergeCurrentCharFormat(format); // 应用颜色}
}
QColorDialog::getColor
弹出颜色选择对话框,允许用户选择文本颜色。format.setForeground(color)
设置选中的文本颜色。textEdit->mergeCurrentCharFormat(format)
将颜色应用到当前选中的文本。
12. 设置背景颜色(setBackgroundColor
)
void TextEditor::setBackgroundColor()
{QColor color = QColorDialog::getColor(textEdit->textBackgroundColor(), this); // 弹出颜色选择对话框if (color.isValid()) {QTextCharFormat format;format.setBackground(color); // 设置背景颜色textEdit->mergeCurrentCharFormat(format); // 应用背景颜色}
}
QColorDialog::getColor
弹出颜色选择对话框,允许用户选择背景颜色。format.setBackground(color)
设置选中文本的背景颜色。textEdit->mergeCurrentCharFormat(format)
将背景颜色应用到当前选中的文本。
13. 设置左对齐(setLeftAlignment
)
void TextEditor::setLeftAlignment()
{QTextBlockFormat format;format.setAlignment(Qt::AlignLeft); // 设置为左对齐textEdit->mergeCurrentBlockFormat(format); // 将对齐方式应用到当前选中的文本
}
format.setAlignment(Qt::AlignLeft)
设置对齐方式为左对齐。textEdit->mergeCurrentBlockFormat(format)
将左对齐的格式应用到当前选中的文本块。
14. 设置居中对齐(setCenterAlignment
)
void TextEditor::setCenterAlignment()
{QTextBlockFormat format;format.setAlignment(Qt::AlignCenter); // 设置为居中对齐textEdit->mergeCurrentBlockFormat(format); // 将对齐方式应用到当前选中的文本
}
format.setAlignment(Qt::AlignCenter)
设置对齐方式为居中对齐。textEdit->mergeCurrentBlockFormat(format)
将居中对齐的格式应用到当前选中的文本块。
15. 设置右对齐(setRightAlignment
)
void TextEditor::setRightAlignment()
{QTextBlockFormat format;format.setAlignment(Qt::AlignRight); // 设置为右对齐textEdit->mergeCurrentBlockFormat(format); // 将对齐方式应用到当前选中的文本
}
format.setAlignment(Qt::AlignRight)
设置对齐方式为右对齐。textEdit->mergeCurrentBlockFormat(format)
将右对齐的格式应用到当前选中的文本块。
源代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QTextEdit>
#include <QMdiSubWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass TextEdit;
class QPrinter;
class QActionGroup;
class QSignalMapper;
class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void initWindowAction(); //初始化窗体action状态void initTextAction(bool b); //初始化文本action状态void on_New_action_triggered();void on_Open_action_triggered();void on_Save_action_triggered();void on_Save_save_action_triggered();void on_Print_action_triggered();void on_Print_preview_action_triggered();void on_Undo_action_triggered();void on_Redo_action_triggered();void on_Cut_action_triggered();void on_Copy_action_triggered();void on_paste_action_triggered();void on_Bold_action_triggered();void on_Italic_action_triggered();void on_Under_action_triggered();void on_Fontcombosize_activated(const QString &arg1);void on_fontComboBox_activated(const QString &arg1);void on_Left_action_triggered();void on_Center_action_triggered();void on_Right_action_triggered();void on_Justfiy_action_triggered();void on_Colse_action_triggered();void on_Colse_all_action_triggered();void on_Tittle_action_triggered();void on_Cascade_action_triggered();void on_Next_action_triggered();void on_previous_action_triggered();void on_About_action_triggered();void on_Color_action_triggered();void on_standardcomboBox_activated(int index);void setActiveSubWindow(QWidget* widget);private:Ui::MainWindow *ui;void init(); //初始化void initMdiArea(); //初始化Mdi控件,初始化进度条void initFontSize(); //初始化字号TextEdit* activateWindow(); //获取Mdi中的活动窗体QMdiSubWindow* findSubWindow(const QString &docname); //判断MDI中是否有相同文件名的文件void printPreview(QPrinter *printer); //打印预览功能void Start_Past(); //根据系统粘贴板状态控制past粘贴功能void Select(); //判断文本格式,是否加粗,是否有下划线等void closeEvent(QCloseEvent *event); //重写关闭事件void addSubWindowAction(); //使用信号映射器实现标题栏窗口选择窗口功能public:QActionGroup* actionGroup;QSignalMapper* signalMapper;};
#endif // MAINWINDOW_H
textedit.h
#ifndef TEXTEDIT_H
#define TEXTEDIT_H
#include <QTextEdit>class TextEdit : public QTextEdit
{Q_OBJECT
public:TextEdit(QWidget *parent=nullptr);~TextEdit();public:void initNewDoc(); //初始化文档void initOpenDoc(const QString &docName); //初始化标题QString getDocFilePath() const; //返回绝对路径和文件名bool loadDoc(const QString &docName); //读取文本显示出来bool SaveDoc(); //保存文档bool Save_save_Doc(); //另存为bool writeToDoc(const QString &docName); //保存功能void closeEvent(QCloseEvent *event); //重写关闭事件bool promptSave();QString getDocFileName() const; //获取文档名称private slots:void setWindowModify(); //设置windowModified属性private:static int docNo; //静态数据,文档编号,静态数据成员存储在静态数据区,所有类共享副本//类存储在堆区,静态数据成员属于类,但是不在一块内存,所以要类内声明,类外定义QString docWindowTitle; //标题QString docFilePath_Name; //文档的绝对路径和名称QString docFileName; //文档的名称
};#endif // TEXTEDIT_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "textedit.h"
#include <QFontDatabase>
#include <QFont>
#include <QMdiArea>
#include <QFileDialog>
#include <QPrintDialog>
#include <QPainter>
#include <QPrinter>
#include <QPrintPreviewDialog>
#include <QApplication>
#include <QClipboard>
#include <QtDebug>
#include <QColorDialog>
#include <QCloseEvent>
#include <QMessageBox>
#include <QTextCursor>
#include <QTextList>
#include <QTextBlockFormat>
#include <QSignalMapper>
#include <QActionGroup>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);init(); //初始化
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::init()
{initMdiArea(); //初始化MdiinitFontSize(); //初始化字体框initWindowAction(); //初始化窗体action状态//initTextAction(false); //初始化文本action状态//当在mdi中添加活动窗体时会触发subWindowActivated信号,关闭窗口会返回0connect(ui->mdiArea,&QMdiArea::subWindowActivated,this,&MainWindow::initWindowAction);//获取系统剪贴板的指针,返回类型为,QClipboard *QClipboard *clip=QApplication::clipboard();//每当剪贴板的内容发生变化时都会触发这个信号connect(clip,&QClipboard::dataChanged,this,&MainWindow::Start_Past);signalMapper = new QSignalMapper(this);actionGroup = new QActionGroup(this);actionGroup->setExclusive(true); //排他性connect(ui->menu_T,&QMenu::aboutToShow,this,&MainWindow::addSubWindowAction);connect(signalMapper,SIGNAL(mapped(QWidget*)), this,SLOT(setActiveSubWindow(QWidget*)));
}void MainWindow::initMdiArea()
{//设置背景色ui->mdiArea->setBackground(QBrush(Qt::white));//设置滚动条ui->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);ui->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
}void MainWindow::initFontSize()
{ui->Fontcombosize->clear();//使用QFontDatabase数据库设置字号//standardSizes:QFontDatabase的静态函数,返回系统字号for(int fontsize : QFontDatabase::standardSizes()){ui->Fontcombosize->addItem(QString::number(fontsize));}QFont font=QApplication::font();int appfontsize=font.pointSize();//int sizeindex=ui->Fontcombosize->findText(QString::asprintf("%d",appfontsize));int sizeindex=ui->Fontcombosize->findText(QString::number(appfontsize));ui->Fontcombosize->setCurrentIndex(sizeindex);
}void MainWindow::initWindowAction()
{bool activate=(activateWindow()!=nullptr);if(!activate){initTextAction(false);}ui->paste_action->setEnabled(activate);ui->Save_action->setEnabled(activate);ui->Save_save_action->setEnabled(activate);ui->Print_action->setEnabled(activate);ui->Print_preview_action->setEnabled(activate);ui->Undo_action->setEnabled(activate);ui->Redo_action->setEnabled(activate);ui->Colse_action->setEnabled(activate);ui->Colse_all_action->setEnabled(activate);ui->Tittle_action->setEnabled(activate);ui->Cascade_action->setEnabled(activate);ui->previous_action->setEnabled(activate);ui->Next_action->setEnabled(activate);ui->standardcomboBox->setEnabled(activate);ui->Fontcombosize->setEnabled(activate);ui->fontComboBox->setEnabled(activate);
}TextEdit *MainWindow::activateWindow()
{//activeSubWindow用于返回当前活动的窗体有窗体返回QMdiSubWindow指针,没有返回0QMdiSubWindow* window=ui->mdiArea->activeSubWindow();if(window){//widget:返回 QMdiSubWindow 中实际显示的主控件return qobject_cast<TextEdit*>(window->widget());}return nullptr;
}void MainWindow::initTextAction(bool b)
{ui->Cut_action->setEnabled(b);ui->Copy_action->setEnabled(b);ui->Color_action->setEnabled(b);ui->Bold_action->setEnabled(b);ui->Italic_action->setEnabled(b);ui->Under_action->setEnabled(b);ui->Left_action->setEnabled(b);ui->Center_action->setEnabled(b);ui->Right_action->setEnabled(b);ui->Justfiy_action->setEnabled(b);ui->Justfiy_action->setEnabled(b);
}void MainWindow::on_New_action_triggered()
{TextEdit*Edit=new TextEdit;ui->mdiArea->addSubWindow(Edit);//会把Edit的父对象自动设置为mdi//copyAvailable选中文本或者取消选择时会触发信号connect(Edit,&TextEdit::copyAvailable,this,&MainWindow::initTextAction);//每次选中文本的时候都会触发connect(Edit,&TextEdit::copyAvailable,this,&MainWindow::Select);Edit->initNewDoc();Edit->show();statusBar()->showMessage("新建成功",3000);
}void MainWindow::on_Open_action_triggered()
{QString FileName=QFileDialog::getOpenFileName(this,"打开文件","../","所有文件(*.*);;文本文件(*.txt)",nullptr);if(!FileName.isEmpty()){QMdiSubWindow* sub=findSubWindow(FileName); //判断文件是否已经存在,如果存在就设置为活动窗口,不存在就新增if(sub){ui->mdiArea->setActiveSubWindow(sub);return;}TextEdit* Edit=new TextEdit;ui->mdiArea->addSubWindow(Edit);//copyAvailable选中文本或者取消选择时会触发信号connect(Edit,&TextEdit::copyAvailable,this,&MainWindow::initTextAction);//每次选中文本的时候都会触发connect(Edit,&TextEdit::copyAvailable,this,&MainWindow::Select);if(Edit->loadDoc(FileName)){ //初始化EditstatusBar()->showMessage("文档已打开",3000); //让状态栏显示三秒钟Edit->show();}else{Edit->close();}}return;
}QMdiSubWindow *MainWindow::findSubWindow(const QString &docname)
{QString filepath=QFileInfo(docname).canonicalFilePath(); //返回文件绝对路径for(QMdiSubWindow* sub:ui->mdiArea->subWindowList()){ //遍历MDI中的活动窗口TextEdit *edit=qobject_cast<TextEdit*>(sub->widget());//强转为TextEdit类型if(edit->getDocFilePath()==filepath){ //如果找到了一样的文件(绝对路径)就直接返回真否则返回空return sub;}}return nullptr;
}void MainWindow::on_Save_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->SaveDoc();}}void MainWindow::on_Save_save_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->Save_save_Doc();}
}void MainWindow::on_Print_action_triggered()
{QPrinter print;print.setResolution(QPrinter::HighResolution);//是 QPrinter 中的一个常量,它表示一个高分辨率的打印设置,通常是 600 DPI 或更高。//使用这个常量时,打印机将尽可能以更高的质量进行打印,适用于需要高质量输出的情况QPrintDialog printf_dialog(&print,this);//在打印对话框中启用了“打印选定内容”选项,允许用户选择打印文档中的一部分内容。printf_dialog.setOption(QAbstractPrintDialog::PrintSelection, true);//用户可以选择“打印选定内容”或者“打印整个文档”。printf_dialog.setOption(QAbstractPrintDialog::PrintSelection, true);TextEdit *text=activateWindow();if(printf_dialog.exec()==QDialog::Accepted){text->print(&print);}
}void MainWindow::on_Print_preview_action_triggered()
{// 获取当前活动的 TextEdit 控件(假设这是你编辑文档的地方)TextEdit* Edit = activateWindow();if (!Edit) return; // 如果没有活动的窗口,退出// 创建一个 QPrinter 对象,它是用来控制打印机的QPrinter print;// 创建一个打印预览对话框,传入 QPrinter 对象QPrintPreviewDialog preview(&print, this);// 连接打印预览对话框的 paintRequested 信号到 printPreview 槽函数connect(&preview, &QPrintPreviewDialog::paintRequested, this, &MainWindow::printPreview);// 弹出打印预览对话框,并且马上回触发信号与槽,打印到屏幕上// 如果用户点击了“打印”按钮(即接受了打印预览),则执行实际的打印if (preview.exec() == QDialog::Accepted) { //实际打印到打印机上// 如果打印预览对话框的返回值是“Accepted”,表示用户点击了打印按钮Edit->print(&print); // 调用 TextEdit 的 print 方法执行打印}
}void MainWindow::printPreview(QPrinter *printer) //打印到屏幕上
{// 获取当前活动的 TextEdit 控件(文档编辑器)TextEdit* Edit = activateWindow();// 如果有活动的 TextEdit 控件(即有一个正在编辑的文档)if (Edit) {// 使用传入的 QPrinter 对象执行打印Edit->print(printer);}
}void MainWindow::Start_Past()
{//获取系统剪贴板的指针,返回类为QClipboard *QClipboard *clip=QApplication::clipboard();QString pastText=clip->text(); //返回粘贴板中的文本if(!pastText.isEmpty()){ //判断是否存在文本ui->paste_action->setEnabled(true);}else{ui->paste_action->setEnabled(false);}
}void MainWindow::Select()
{TextEdit* Edit=activateWindow();if(Edit){QTextCharFormat format=Edit->currentCharFormat();//判断字体是否加粗bool isBold=(format.fontWeight()==QFont::Bold);if(isBold){ui->Bold_action->setChecked(true);}else{ui->Bold_action->setChecked(false);}//判断是否斜体bool isitalic=format.fontItalic();if(isitalic){ui->Italic_action->setChecked(true);}else{ui->Italic_action->setChecked(false);}//判断是否下划线bool isUnder=format.fontUnderline();if(isUnder){ui->Under_action->setChecked(true);}else{ui->Under_action->setChecked(false);}}}void MainWindow::closeEvent(QCloseEvent *event)
{ui->mdiArea->closeAllSubWindows();if(ui->mdiArea->currentSubWindow()){event->ignore();}else{event->accept();}
}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_T->addSeparator(); //添加分割线for(int i=0;i<subWindowList.count();i++){//获取内嵌部件QMdiSubWindow* subWindow=subWindowList.at(i);TextEdit* Edit=qobject_cast<TextEdit*>(subWindow->widget());if(Edit==nullptr){qDebug()<<"转换失败!";}//设置需要添加的Action名称QString ACtion_Name=QString("%1 %2").arg(i+1).arg(Edit->getDocFileName());QAction *addAction=ui->menu_T->addAction(ACtion_Name);actionGroup->addAction(addAction);addAction->setCheckable(true);if(Edit==activateWindow()) addAction->setChecked(true);connect(addAction, SIGNAL(triggered(bool)), signalMapper, SLOT(map()));connect(addAction, SIGNAL(triggered(bool)), this, SLOT(on_Center_action_triggered()));signalMapper->setMapping(addAction,subWindow);}
}void MainWindow::setActiveSubWindow(QWidget *widget)
{if(widget)ui->mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow*>(widget));
}void MainWindow::on_Undo_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->undo();}
}void MainWindow::on_Redo_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->redo();}
}void MainWindow::on_Cut_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->cut();}
}void MainWindow::on_Copy_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->copy();}
}void MainWindow::on_paste_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->paste();}
}void MainWindow::on_Bold_action_triggered()
{//使用QFont不能局部设置加粗,一加粗所有文本都加粗了,不能根据光标位置或者选中的文本单独进行加粗// TextEdit* Edit=activateWindow();// if(Edit){// QFont font=Edit->font();// font.setBold(true);// Edit->setFont(font);// }TextEdit* Edit=activateWindow();if(Edit){bool isChecked=ui->Bold_action->isChecked();//设置文本字符格式的类。例如字体、颜色、加粗、斜体、下划线等。QTextCharFormat format;format.setFontWeight(isChecked ? QFont::Bold : QFont::Normal);//使用mergeCurrentCharFormat可以局部进行单独的设置Edit->mergeCurrentCharFormat(format);}
}void MainWindow::on_Italic_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){QTextCharFormat format;bool isItalic=ui->Italic_action->isChecked();format.setFontItalic(isItalic);Edit->mergeCurrentCharFormat(format);}
}void MainWindow::on_Under_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){QTextCharFormat format;bool isUnder=ui->Under_action->isChecked();format.setFontUnderline(isUnder);Edit->mergeCurrentCharFormat(format);}
}void MainWindow::on_Fontcombosize_activated(const QString &arg1)
{TextEdit* Edit=activateWindow();if(Edit){QTextCharFormat format;format.setFontPointSize(arg1.toInt());Edit->mergeCurrentCharFormat(format);}
}void MainWindow::on_fontComboBox_activated(const QString &arg1)
{TextEdit* Edit=activateWindow();if(Edit){QTextCharFormat format;format.setFontFamily(arg1);format.setFontPointSize(ui->Fontcombosize->currentText().toInt());Edit->mergeCurrentCharFormat(format);}
}void MainWindow::on_Left_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->setAlignment(Qt::AlignLeft);}
}void MainWindow::on_Center_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->setAlignment(Qt::AlignCenter);}
}void MainWindow::on_Right_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->setAlignment(Qt::AlignRight);}
}void MainWindow::on_Justfiy_action_triggered()
{TextEdit* Edit=activateWindow();if(Edit){Edit->setAlignment(Qt::AlignJustify);}
}void MainWindow::on_Colse_action_triggered()
{// TextEdit* Edit=activateWindow();// if(Edit){// QMdiSubWindow* window=qobject_cast<QMdiSubWindow*>(Edit->parentWidget());// if(window){// window->close();// }// }//Active 活动ui->mdiArea->closeActiveSubWindow();
}void MainWindow::on_Colse_all_action_triggered()
{//All 所有ui->mdiArea->closeAllSubWindows();
}void MainWindow::on_Tittle_action_triggered()
{//tile 平铺ui->mdiArea->tileSubWindows();
}void MainWindow::on_Cascade_action_triggered()
{//cascade 层叠 SubWindows 子窗口ui->mdiArea->cascadeSubWindows();
}void MainWindow::on_Next_action_triggered()
{//activ 活动 activate 激活ui->mdiArea->activateNextSubWindow();
}void MainWindow::on_previous_action_triggered()
{//activ 活动 activate 激活 Previous 上一个ui->mdiArea->activatePreviousSubWindow();
}void MainWindow::on_Color_action_triggered()
{TextEdit *Edit=activateWindow();if(Edit){QColor color=QColorDialog::getColor(Qt::black,this,"选中字体颜色");if(color.isValid()){QTextCharFormat format;format.setForeground(color);Edit->mergeCurrentCharFormat(format);}}
}void MainWindow::on_standardcomboBox_activated(int index)
{// 获取当前活动窗口,即 TextEdit 控件TextEdit *Edit = activateWindow();if(Edit){// 如果下拉框选项为0(即取消项目符号)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); // 将当前块的缩进设置为 0cursor.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; // 未定义的列表样式break;}// 获取当前光标对象QTextCursor cursor = Edit->textCursor();cursor.beginEditBlock(); // 开始编辑块// 获取当前块的格式,并创建一个 QTextListFormat 对象来设置列表格式QTextBlockFormat blockFormat = cursor.blockFormat();QTextListFormat listFormat;// 如果当前光标所在文本属于列表的一部分QTextList* list = cursor.currentList();if(list){listFormat = list->format(); // 获取该列表的格式list->remove(cursor.block()); // 删除当前光标所在的列表项blockFormat.setIndent(0); // 设置块缩进为 0cursor.setBlockFormat(blockFormat); // 应用新的块格式}// 设置列表样式为选中的样式listFormat.setStyle(style);// 使用新的列表格式创建一个列表cursor.createList(listFormat);cursor.endEditBlock(); // 结束编辑块}
}void MainWindow::on_About_action_triggered()
{QMessageBox::about(this,tr("关于应用"),tr("这是一个WPS项目。\n版本1.0\n制作者:xiaohu"));
}
textedit.cpp
#include "textedit.h"
#include <QFileInfo>
#include <QFileDialog>
#include <QTextDocumentWriter>
#include <QCloseEvent>
#include <QMessageBox>
#include <QDebug>int TextEdit::docNo=1; //类外初始化静态数据成员
TextEdit::TextEdit(QWidget *parent):QTextEdit(parent)
{setAttribute(Qt::WA_DeleteOnClose); //关闭窗体时释放资源//initNewDoc();
}TextEdit::~TextEdit()
{}void TextEdit::initNewDoc()
{docFileName=QString("文档 %1").arg(docNo++);docWindowTitle=docFileName;//使用windowmodified机制,添加[*]占位符//当窗口显示的文档有未保存的更改,*号就会显示出来setWindowTitle(docWindowTitle + "[*]");/*document() 是 QTextEdit 类的一个成员函数,返回当前编辑器中所使用的 QTextDocument 对象。QTextDocument 类负责管理和操作文本内容。contentsChanged 是 QTextDocument 类中的一个信号。它在文档的内容发生变化时发出。文档内容变化的原因可能是用户输入文本、删除文本或其他任何修改内容的操作。*/connect(document(),&QTextDocument::contentsChanged,this,&TextEdit::setWindowModify);
}void TextEdit::setWindowModify()
{//isModified返回文档是否被用户修改setWindowModified(document()->isModified());
}void TextEdit::initOpenDoc(const QString &docName)
{docFilePath_Name=QFileInfo(docName).canonicalFilePath(); //返回绝度路径,包含文件名docFileName=QFileInfo(docName).fileName(); //返回文档名称docWindowTitle=docFileName + " " + QString::number(docNo++); //设置标题setWindowTitle(docWindowTitle + "[*]"); //设置标题并添加[*]占位符/*之所以要调用两次信号与槽,是因为信号与槽的生命周期和类是绑定的,比如说新建文档会新建一个类,那么这个时候就需要连接各种信号与槽,当关闭新建的窗口时,信号与槽就会解绑新建文档和打开文档是两个独立的功能,所绑定的信号与槽是不通用的,虽然有两个相同的类,但是内存都不同,所以每次New类的时候都需要重新绑定信号与槽*/connect(document(),&QTextDocument::contentsChanged,this,&TextEdit::setWindowModify);
}QString TextEdit::getDocFilePath() const
{return docFilePath_Name;
}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{setText(text); //纯文本显示}initOpenDoc(docName); //初始化打开的文档}return true;
}bool TextEdit::SaveDoc()
{if(document()->isModified()){ //如果文档被修改if(!docFilePath_Name.isEmpty()){ //如果路径不为空writeToDoc(docFilePath_Name);}else{return Save_save_Doc();}}return false;
}bool TextEdit::Save_save_Doc()
{QString docName=QFileDialog::getSaveFileName(this,"另存为","../","HTML文档(*.html);;文本文档(*.txt)");if(!docName.isEmpty()){return writeToDoc(docName);}return false;
}bool TextEdit::writeToDoc(const QString &docName)
{QTextDocumentWriter docWriter(docName); //用于将QTextDocument对象中的文本内容保存到文件中,参数就是文件名if(docWriter.write(this->document())){ //写入文件,document是返回TexeEdit中的QTextDocument,这类是每个QTextEdit中都有的,负责存储和管理文本docFilePath_Name=QFileInfo(docName).canonicalFilePath(); //更新路径,特别是另存为可能会改变路径document()->setModified(false); //设置文档状态未改动,设置内部为未修改setWindowModified(false); //取消窗口*号显示,设置ui界面*号消失}else{return false;}return true;
}void TextEdit::closeEvent(QCloseEvent *event)
{if(promptSave()){event->accept(); //表示你处理了事件,事件结束,不再传递。}else{event->ignore(); //表示不处理该事件,让事件继续传递到其他地方或执行默认行为。}
}bool TextEdit::promptSave()
{//document()QTextDocument 是 Qt 的文本编辑框架的核心部分//isModified() 判断文档是否被修改过if(!document()->isModified())return true;QMessageBox::StandardButton res;
// res=QMessageBox::warning(this,"提示",QString("文档%1已修改,是否保存?").arg(getDocFileName()),
// QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);res=QMessageBox::warning(this,"提示",QString::asprintf("%s已修改,是否保存?",getDocFileName().toStdString().c_str()),QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);//qDebug()<<getDocFileName();if(res==QMessageBox::Yes){return SaveDoc();}else if(res==QMessageBox::No){return true;}else if(res==QMessageBox::Cancel){return false;}return false;
}QString TextEdit::getDocFileName() const
{return docFileName;
}
main.cpp
#include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}
总结
这个项目实现了一个简单的文本编辑器,功能包括文本的基本编辑、格式化、撤销重做、剪切复制粘贴、以及文本的对齐和字体设置等。通过 Qt 提供的控件和方法,我们可以轻松地实现这些功能。下面是对整个代码实现的详细总结,帮助你更好地理解每一部分功能和实现原理。
1. 初始化与UI设置
程序的第一步是初始化应用程序及其主界面,创建一个 QMainWindow
窗口,并在其中放置一个 QTextEdit
控件,用于文本的显示和编辑。这是 Qt 中最常用的多行文本控件,支持文本的插入、编辑和格式化。通过设置 QTextEdit
,用户能够直接与文本进行交互。
在构造函数中,我们创建了菜单栏,菜单项包括“文件”和“编辑”菜单,“编辑”菜单下有撤销、重做、剪切、复制、粘贴等常见的文本操作;“文件”菜单下可以实现文本的打开、保存和新建等功能。
2. 文本操作功能
文本操作功能是这段代码的核心部分,主要包括以下几项常用的编辑功能:
-
剪切(cut):
剪切操作通过textEdit->cut()
实现。当用户点击剪切按钮时,文本框中的选中文本会被剪切到系统剪贴板,并从QTextEdit
控件中删除。这是一个标准的文本编辑操作,允许用户删除选中的文本并将其保留在剪贴板中,以便后续粘贴使用。 -
复制(copy):
复制功能通过textEdit->copy()
实现,它会将选中的文本复制到系统剪贴板中,而不会删除文本。这样用户可以将选中的内容复制并粘贴到其他地方。 -
粘贴(paste):
粘贴功能通过textEdit->paste()
方法来实现,用户可以从剪贴板中粘贴内容到当前光标的位置。粘贴功能在剪切和复制之后常用。 -
撤销(undo)与重做(redo):
这两个操作通过textEdit->undo()
和textEdit->redo()
实现。撤销功能允许用户回退到上一步的编辑状态,例如撤销输入的文字或删除的文本;而重做则是恢复上一步被撤销的操作。如果用户不小心撤销了操作,重做操作可以将其恢复。这两个功能是所有文本编辑器中必不可少的功能,确保用户能够灵活控制编辑历史。
3. 文本格式化功能
文本格式化功能是文本编辑器中的重要部分,可以通过这些功能让文本变得更加生动和富有表现力。代码实现了以下格式化功能:
-
加粗:
使用QTextCharFormat
和setFontWeight()
来设置字体的粗细。通过mergeCurrentCharFormat
方法将加粗格式应用到选中的文本。 -
斜体:
通过setFontItalic(true)
设置文本为斜体,并通过mergeCurrentCharFormat
应用到选中的文本区域。 -
下划线:
设置fontUnderline
为true
来为文本添加下划线,应用到选中的文本。 -
设置字体:
使用QFontDialog::getFont()
弹出一个字体选择对话框,允许用户选择字体及其样式。选定字体后,调用setCurrentFont()
更新文本框中的字体样式。 -
设置字号:
通过QInputDialog::getInt()
弹出一个整数输入框,让用户输入所需的字号。然后通过setPointSize()
方法设置字体的大小,从而改变文本的显示效果。 -
设置文本颜色:
使用QColorDialog::getColor()
获取用户选择的颜色,并通过setForeground()
方法将该颜色应用到选中的文本区域。 -
设置背景颜色:
类似文本颜色设置,使用QColorDialog::getColor()
获取用户选择的颜色,并通过setBackground()
设置选中文本的背景色。
4. 文本对齐功能
文本对齐是文本编辑器中一个常见的功能,通常包括左对齐、居中对齐、右对齐和两端对齐。在这段代码中,我们使用了 QTextBlockFormat
来控制文本对齐方式:
-
左对齐(setAlignment(Qt::AlignLeft))
通过QTextBlockFormat
设置文本的对齐方式为左对齐。 -
居中对齐(setAlignment(Qt::AlignCenter))
将对齐方式设置为居中。 -
右对齐(setAlignment(Qt::AlignRight))
将对齐方式设置为右对齐。 -
两端对齐(setAlignment(Qt::AlignJustify))
设置文本为两端对齐方式,使得文本在行内两边对齐,通常用于文档排版。
这些对齐功能通过 textEdit->mergeCurrentBlockFormat()
方法应用到选中的文本区域,允许用户根据需求选择合适的文本排版方式。
5. 功能实现的信号与槽机制
在 Qt 中,信号与槽是处理用户输入和界面交互的核心机制。例如,当用户点击菜单项时,会触发相应的信号。然后,这些信号会连接到相应的槽函数中,槽函数执行相应的操作。例如,点击“撤销”菜单项时,信号会触发槽函数 undo()
,进而撤销文本编辑器中的操作。
信号与槽的连接使得界面与逻辑操作分离,代码更为模块化、清晰。每个按钮或菜单项触发的操作都与相应的槽函数绑定,保证了应用的灵活性和可扩展性。
相关文章:
从零开始:用Qt开发一个功能强大的文本编辑器——WPS项目全解析
文章目录 引言项目功能介绍1. **文件操作**2. **文本编辑功能**3. **撤销与重做**4. **剪切、复制与粘贴**5. **文本查找与替换**6. **打印功能**7. **打印预览**8. **设置字体颜色**9. **设置字号**10. **设置字体**11. **左对齐**12. **右对齐**13. **居中对齐**14. **两侧对…...
LLMs之OpenAI o系列:OpenAI o3-mini的简介、安装和使用方法、案例应用之详细攻略
LLMs之OpenAI o系列:OpenAI o3-mini的简介、安装和使用方法、案例应用之详细攻略 目录 相关文章 LLMs之o3:《Deliberative Alignment: Reasoning Enables Safer Language Models》翻译与解读 LLMs之OpenAI o系列:OpenAI o3-mini的简介、安…...
DeepSeek-R1 低成本训练的根本原因是?
在人工智能领域,大语言模型(LLM)正以前所未有的速度发展,驱动着自然语言处理、内容生成、智能客服等众多应用的革新。然而,高性能的背后往往是高昂的训练成本,动辄数百万美元的投入让许多企业和研究机构望而…...
C语言:结构体
一,结构体 C语⾔已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类型还是不够的,假设我想描述学⽣,描述⼀本书,这时单⼀的内置类型是不⾏的。 描述⼀个学⽣需…...
java练习(5)
ps:题目来自力扣 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这…...
【高等数学】贝塞尔函数
贝塞尔函数(Bessel functions)是数学中一类重要的特殊函数,通常用于解决涉及圆对称或球对称的微分方程。它们在物理学、工程学、天文学等多个领域都有广泛的应用,例如在波动方程、热传导方程、电磁波传播等问题中。 贝塞尔函数的…...
贪吃蛇实现
1.资料来源 https://learn.microsoft.com/zh-cn/windows/console/getstdhandle 2.前言 简介 贪吃蛇是久负盛名的游戏,和俄罗斯方块、扫雷等游戏位列于经典游戏的行列。 《贪食蛇》中玩家控制一条不断移动的蛇,在屏幕上吃掉出现的食物。每吃掉一个食物…...
Windows电脑本地部署运行DeepSeek R1大模型(基于Ollama和Chatbox)
文章目录 一、环境准备二、安装Ollama2.1 访问Ollama官方网站2.2 下载适用于Windows的安装包2.3 安装Ollama安装包2.4 指定Ollama安装目录2.5 指定Ollama的大模型的存储目录 三、选择DeepSeek R1模型四、下载并运行DeepSeek R1模型五、使用Chatbox进行交互5.1 下载Chatbox安装包…...
在C++中,成员变量必须在对象构造完成前初始化,但初始化的方式有多种...
在C中,成员变量必须在对象构造完成前初始化,但初始化的方式可以有多种,具体取决于成员变量的类型和设计需求。以下是C中成员变量初始化的规则和相关机制: 1. 成员变量必须初始化 如果成员变量是基本类型(如 int、doub…...
maven mysql jdk nvm node npm 环境安装
安装JDK 1.8 11 环境 maven环境安装 打开网站 下载 下载zip格式 解压 自己创建一个maven库 以后在idea 使用maven时候重新设置一下 这三个地方分别设置 这时候maven才算设置好 nvm 管理 npm nodejs nvm下载 安装 Releases coreybutler/nvm-windows GitHub 一键安装且若有…...
算法随笔_37: 交替合并字符串
上一篇:算法随笔_36: 复写零-CSDN博客 题目描述如下: 给你两个字符串 word1 和 word2 。请你从 word1 开始,通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾。 返回 合并后的字符串 。 示例…...
w188校园商铺管理系统设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
(2025 年最新)MacOS Redis Desktop Manager中文版下载,附详细图文
MacOS Redis Desktop Manager中文版下载 大家好,今天给大家带来一款非常实用的 Redis 可视化工具——Redis Desktop Manager(简称 RDM)。相信很多开发者都用过 Redis 数据库,但如果你想要更高效、更方便地管理 Redis 数据&#x…...
【Block总结】Shuffle Attention,新型的Shuffle注意力|即插即用
一、论文信息 标题: SA-Net: Shuffle Attention for Deep Convolutional Neural Networks 论文链接: arXiv 代码链接: GitHub 二、创新点 Shuffle Attention(SA)模块的主要创新在于高效结合了通道注意力和空间注意力,同时通过通道重排技…...
解锁豆瓣高清海报(一) 深度爬虫与requests进阶之路
前瞻 PosterBandit 这个脚本能够根据用户指定的日期,爬取你看过的影视最高清的海报,然后使用 PixelWeaver.py 自动拼接成指定大小的长图。 你是否发现直接从豆瓣爬取下来的海报清晰度很低? 使用 .pic .nbg img CSS 选择器,在 我…...
【机器学习与数据挖掘实战】案例11:基于灰色预测和SVR的企业所得税预测分析
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支,专注于让计算机系统通过数据学习和改进。它利用统计和计算方法,使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数据集中发现模式、关联…...
聚簇索引、哈希索引、覆盖索引、索引分类、最左前缀原则、判断索引使用情况、索引失效条件、优化查询性能
聚簇索引 聚簇索引像一本按目录排版的书,用空间换时间,适合读多写少的场景。设计数据库时,主键的选择(如自增ID vs 随机UUID)会直接影响聚簇索引的性能。 什么是聚簇索引? 数据即索引:聚簇索引…...
克隆OpenAI(基于openai API和streamlit)
utils.py: from langchain_openai import ChatOpenAI from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationChain import osdef get_chat_response(api_key,prompt,memory): # memory不能是函数的内部局部变量&…...
DeepSeek技术深度解析:从不同技术角度的全面探讨
DeepSeek技术深度解析:从不同技术角度的全面探讨 引言 DeepSeek是一个集成了多种先进技术的平台,旨在通过深度学习和其他前沿技术来解决复杂的问题。本文将从算法、架构、数据处理以及应用等不同技术角度对DeepSeek进行详细分析。 一、算法层面 深度学…...
完全卸载mysql server步骤
1. 在控制面板中卸载mysql 2. 打开注册表,运行regedit, 删除mysql信息 HKEY_LOCAL_MACHINE-> SYSTEM->CurrentContolSet->Services->EventLog->Application->Mysql HKEY_LOCAL_MACHINE-> SYSTEM->CurrentContolSet->Services->Mysql …...
2025年大年初一篇,C#调用GPU并行计算推荐
C#调用GPU库的主要目的是利用GPU的并行计算能力,加速计算密集型任务,提高程序性能,支持大规模数据处理,优化资源利用,满足特定应用场景的需求,并提升用户体验。在需要处理大量并行数据或进行复杂计算的场景…...
机器学习优化算法:从梯度下降到Adam及其实验改进
机器学习优化算法:从梯度下降到Adam及其实验改进 在机器学习和深度学习领域,模型的训练过程本质上是一个优化问题。优化算法的作用是通过调整模型参数,使得模型在给定的数据 集上实现最优性能。而优化算法的效率和效果直接决定了模型的收敛速…...
在 Ubuntu 中使用 Conda 创建和管理虚拟环境
Conda 是一个广泛使用的包管理和环境管理系统,尤其适用于数据科学和 Python 开发。本文将指导你如何在 Ubuntu 系统中安装 Conda 并创建基于 python3.11 的虚拟环境。 1. 安装 Miniconda 或 Anaconda 方法 1:下载并安装 Miniconda Miniconda 是一个轻量…...
【深度学习】搭建卷积神经网络并进行参数解读
第一步 导包 import torch import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torchvision import datasets,transforms import matplotlib.pyplot as plt import numpy as np %matplotlib inline transforms 模块是 torchvision 库的…...
稀疏进化训练:机器学习优化算法中的高效解决方案
稀疏进化训练:机器学习优化算法中的高效解决方案 稀疏进化训练:机器学习优化算法中的高效解决方案引言第一部分:背景与动机1.1 传统优化算法的局限性1.2 进化策略的优势1.3 稀疏性的重要性 第二部分:稀疏进化训练的核心思想2.1 稀…...
Vue - Suspense的使用
在 Vue 3 中,Suspense 是一个用于处理异步组件的 API。它允许在加载异步组件时提供一个后备内容(例如加载指示器),从而改善用户体验。在加载期间,可以在页面上显示一个占位符,而不是让用户看到一个空白或错…...
在K8S中,pending状态一般由什么原因导致的?
在Kubernetes中,资源或Pod处于Pending状态可能有多种原因引起。以下是一些常见的原因和详细解释: 资源不足 概述:当集群中的资源不足以满足Pod或服务的需求时,它们可能会被至于Pending状态。这通常涉及到CPU、内存、存储或其他资…...
【算法】回溯算法专题② ——组合型回溯 + 剪枝 python
目录 前置知识进入正题小试牛刀实战演练总结 前置知识 【算法】回溯算法专题① ——子集型回溯 python 进入正题 组合https://leetcode.cn/problems/combinations/submissions/596357179/ 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以…...
理解红黑树
简介:红黑树是一种自平衡二叉查找树,由鲁道夫贝尔(Rudolf Bayer)在1972年发明,最初称为“对称二叉B树”。它的设计旨在解决普通二叉查找树在频繁插入和删除操作时可能退化为链表的问题,从而保持高效的查找、…...
从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(OLED设备层封装)
目录 OLED设备层驱动开发 如何抽象一个OLED 完成OLED的功能 初始化OLED 清空屏幕 刷新屏幕与光标设置1 刷新屏幕与光标设置2 刷新屏幕与光标设置3 绘制一个点 反色 区域化操作 区域置位 区域反色 区域更新 区域清空 测试我们的抽象 整理一下,我们应…...
大模型能力评估数据集都有哪些?
大模型能力的评估数据集种类繁多,涵盖了语言理解、推理、生成、代码能力、安全性和鲁棒性等多个方面。以下是一些主要的评估数据集及其特点: 通用能力评估数据集: MMLU:多模态大规模多语言任务理解数据集,覆盖从基础教育到高级专业水平的57个科目,用于评估模型的知识储备…...
论文阅读(二):理解概率图模型的两个要点:关于推理和学习的知识
1.论文链接:Essentials to Understand Probabilistic Graphical Models: A Tutorial about Inference and Learning 摘要: 本章的目的是为没有概率图形模型背景或没有深入背景的科学家提供一个高级教程。对于更熟悉这些模型的读者,本章将作为…...
《OpenCV》——图像透视转换
图像透视转换简介 在 OpenCV 里,图像透视转换属于重要的几何变换,也被叫做投影变换。下面从原理、实现步骤、相关函数和应用场景几个方面为你详细介绍。 原理 实现步骤 选取对应点:要在源图像和目标图像上分别找出至少四个对应的点。这些对…...
【16届蓝桥杯寒假刷题营】第2期DAY4
【16届蓝桥杯寒假刷题营】第2期DAY4 - 蓝桥云课 问题描述 幼儿园小班的浩楠同学有一个序列 a。 他想知道有多少个整数三元组 (i,j,k) 满足 1≤i,j,k≤n 且 aiajak。 输入格式 共2行,第一行一个整数 n,表示序列的长度。 第二行 n 个整数&#x…...
用 HTML、CSS 和 JavaScript 实现抽奖转盘效果
顺序抽奖 前言 这段代码实现了一个简单的抽奖转盘效果。页面上有一个九宫格布局的抽奖区域,周围八个格子分别放置了不同的奖品名称,中间是一个 “开始抽奖” 的按钮。点击按钮后,抽奖区域的格子会快速滚动,颜色不断变化…...
【人工智能学习笔记 一】 AI分层架构、基本概念分类与产品技术架构
新的一年2025要对AI以及LLM有个强化的学习,所以第一篇先对整体有个大概的认知,一直分不清LLM和AI的关系,在整个体系里的位置,以及AIGC是什么东西,AI AGENT类似豆包等和大语言模型的具体关系是什么,整个AI的…...
windows10 配置使用json server作为图片服务器
步骤1:在vs code中安装json server, npm i -g json-server 注意:需要安装对应版本的json server,不然可能会报错,比如: npm i -g json-server 0.16.3 步骤2:出现如下报错: json-server 不是…...
【Elasticsearch 基础入门】Centos7下Elasticsearch 7.x安装与配置(单机)
Elasticsearch系列文章目录 【Elasticsearch 基础入门】一文带你了解Elasticsearch!!!【Elasticsearch 基础入门】Centos7下Elasticsearch 7.x安装与配置(单机) 目录 Elasticsearch系列文章目录前言单机模式1. 安装 J…...
【MySQL】语言连接
语言连接 一、下载二、mysql_get_client_info1、函数2、介绍3、示例 三、其他函数1、mysql_init2、mysql_real_connect3、mysql_query4、mysql_store_result5、mysql_free_result6、mysql_num_fields7、mysql_num_rows8、mysql_fetch_fields9、mysql_fetch_row10、mysql_close …...
【零拷贝】
目录 一:了解IO基础概念 二:数据流动的层次结构 三:零拷贝 1.传统IO文件读写 2.mmap 零拷贝技术 3.sendFile 零拷贝技术 一:了解IO基础概念 理解CPU拷贝和DMA拷贝 我们知道,操作系统对于内存空间&…...
四、GPIO中断实现按键功能
4.1 GPIO简介 输入输出(I/O)是一个非常重要的概念。I/O泛指所有类型的输入输出端口,包括单向的端口如逻辑门电路的输入输出管脚和双向的GPIO端口。而GPIO(General-Purpose Input/Output)则是一个常见的术语,…...
qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记
qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记 文章目录 qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记1.例程运行效果2.例程缩略图3.项目文件列表4.main.qml5.main.cpp6.CMakeLists.txt 1.例程运行效果 运行该项目需要自己准备一个模型文件 2.例程缩略图…...
IM 即时通讯系统-01-概览
前言 有时候希望有一个 IM 工具,比如日常聊天,或者接受报警信息。 其实主要是工作使用,如果是接收报警等场景,其实DD这种比较符合场景。 那么有没有必要再创造一个DD呢? 答案是如果处于个人的私有化使用࿰…...
二叉树——429,515,116
今天继续做关于二叉树层序遍历的相关题目,一共有三道题,思路都借鉴于最基础的二叉树的层序遍历。 LeetCode429.N叉树的层序遍历 这道题不再是二叉树了,变成了N叉树,也就是该树每一个节点的子节点数量不确定,可能为2&a…...
Baklib构建高效协同的基于云的内容中台解决方案
内容概要 随着云计算技术的飞速发展,内容管理的方式也在不断演变。企业面临着如何在数字化转型过程中高效管理和协同处理内容的新挑战。为应对这些挑战,引入基于云的内容中台解决方案显得尤为重要。 Baklib作为创新型解决方案提供商,致力于…...
MP4基础
一、什么是MP4? MP4是一套用于音频、视频信息的压缩编码标准,由国际标准化组织(ISO)和国际电工委员会(IEC)下属的“动态图像专家组”(Moving Picture Experts Group,即MPEGÿ…...
年化18%-39.3%的策略集 | backtrader通过xtquant连接qmt实战
原创内容第785篇,专注量化投资、个人成长与财富自由。 大年初五,年很快就过完了。 其实就是本身也只是休假一周,但是我们赋予了它太多意义。 周五咱们发布发aitrader v4.1,带了backtraderctp期货的实盘接口: aitra…...
通过Redisson构建延时队列并实现注解式消费
目录 一、序言二、延迟队列实现1、Redisson延时消息监听注解和消息体2、Redisson延时消息发布器3、Redisson延时消息监听处理器 三、测试用例四、结语 一、序言 两个月前接了一个4万的私活,做一个线上商城小程序,在交易过程中不可避免的一个问题就是用户…...
RAG是否被取代(缓存增强生成-CAG)吗?
引言: 本文深入研究一种名为缓存增强生成(CAG)的新技术如何工作并减少/消除检索增强生成(RAG)弱点和瓶颈。 LLMs 可以根据输入给他的信息给出对应的输出,但是这样的工作方式很快就不能满足应用的需要: 因…...
MiniMax:人工智能领域的创新先锋
MiniMax:人工智能领域的创新先锋 在人工智能领域,MiniMax正以其强大的技术实力和创新的模型架构,成为全球关注的焦点。作为一家成立于2021年12月的通用人工智能科技公司,MiniMax专注于开发多模态、万亿参数的MoE(Mixt…...