从零开始:用Qt开发一个功能强大的文本编辑器——WPS项目全解析

文章目录

  • 引言
  • 项目功能介绍
      • [1. **文件操作**](#1. 文件操作)
      • [2. **文本编辑功能**](#2. 文本编辑功能)
      • [3. **撤销与重做**](#3. 撤销与重做)
      • [4. **剪切、复制与粘贴**](#4. 剪切、复制与粘贴)
      • [5. **文本查找与替换**](#5. 文本查找与替换)
      • [6. **打印功能**](#6. 打印功能)
      • [7. **打印预览**](#7. 打印预览)
      • [8. **设置字体颜色**](#8. 设置字体颜色)
      • [9. **设置字号**](#9. 设置字号)
      • [10. **设置字体**](#10. 设置字体)
      • [11. **左对齐**](#11. 左对齐)
      • [12. **右对齐**](#12. 右对齐)
      • [13. **居中对齐**](#13. 居中对齐)
      • [14. **两侧对齐**](#14. 两侧对齐)
      • [15. **加粗**](#15. 加粗)
      • [16. **斜体**](#16. 斜体)
      • [17. **下划线**](#17. 下划线)
      • [18. **设置项目符号**](#18. 设置项目符号)
  • 代码解析(部分)
      • [1. **剪切(`cut`)**](#1. 剪切(cut)
      • [2. **复制(`copy`)**](#2. 复制(copy)
      • [3. **粘贴(`paste`)**](#3. 粘贴(paste)
      • [4. **撤销(`undo`)**](#4. 撤销(undo)
      • [5. **重做(`redo`)**](#5. 重做(redo)
      • [6. **加粗(`setBold`)**](#6. 加粗(setBold)
      • [7. **斜体(`setItalic`)**](#7. 斜体(setItalic)
      • [8. **下划线(`setUnderline`)**](#8. 下划线(setUnderline)
      • [9. **设置字体(`setFont`)**](#9. 设置字体(setFont)
      • [10. **设置字号(`setSize`)**](#10. 设置字号(setSize)
      • [11. **设置文本颜色(`setTextColor`)**](#11. 设置文本颜色(setTextColor)
      • [12. **设置背景颜色(`setBackgroundColor`)**](#12. 设置背景颜色(setBackgroundColor)
      • [13. **设置左对齐(`setLeftAlignment`)**](#13. 设置左对齐(setLeftAlignment)
      • [14. **设置居中对齐(`setCenterAlignment`)**](#14. 设置居中对齐(setCenterAlignment)
      • [15. **设置右对齐(`setRightAlignment`)**](#15. 设置右对齐(setRightAlignment)
  • 源代码
  • 总结
      • [1. **初始化与UI设置**](#1. 初始化与UI设置)
      • [2. **文本操作功能**](#2. 文本操作功能)
      • [3. **文本格式化功能**](#3. 文本格式化功能)
      • [4. **文本对齐功能**](#4. 文本对齐功能)
      • [5. **功能实现的信号与槽机制**](#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

cpp 复制代码
void TextEditor::cut()
{
    QTextCursor cursor = textEdit->textCursor();  // 获取当前光标位置
    if (cursor.hasSelection()) {
        textEdit->cut();  // 如果有选中的文本,执行剪切操作
    }
}
  • textEdit->textCursor() 获取当前 QTextEdit 控件的文本光标 (QTextCursor)。
  • cursor.hasSelection() 检查当前光标位置是否有选中的文本。
  • 如果有选中的文本,调用 textEdit->cut() 执行剪切操作,将选中的文本从编辑器中删除,并复制到剪贴板。

2. 复制(copy

cpp 复制代码
void TextEditor::copy()
{
    QTextCursor cursor = textEdit->textCursor();  // 获取当前光标位置
    if (cursor.hasSelection()) {
        textEdit->copy();  // 如果有选中的文本,执行复制操作
    }
}
  • textEdit->textCursor() 获取当前的文本光标。
  • cursor.hasSelection() 检查是否选中了文本。
  • 如果选中了文本,调用 textEdit->copy() 将选中的文本复制到剪贴板。

3. 粘贴(paste

cpp 复制代码
void TextEditor::paste()
{
    textEdit->paste();  // 将剪贴板的内容粘贴到光标当前位置
}
  • textEdit->paste() 会将剪贴板中的内容粘贴到当前光标的位置。如果剪贴板没有内容,则不会有任何变化。

4. 撤销(undo

cpp 复制代码
void TextEditor::undo()
{
    textEdit->undo();  // 撤销上一步操作
}
  • textEdit->undo() 执行撤销操作,即撤回上一步在文本编辑器中做的更改。例如,撤回输入的文字或删除的内容。

5. 重做(redo

cpp 复制代码
void TextEditor::redo()
{
    textEdit->redo();  // 重做上一步撤销的操作
}
  • textEdit->redo() 执行重做操作,即将撤销的操作恢复。如果没有撤销操作,则此操作无效。

6. 加粗(setBold

cpp 复制代码
void TextEditor::setBold()
{
    QTextCharFormat format;
    format.setFontWeight(QFont::Bold);  // 设置字体为加粗
    textEdit->mergeCurrentCharFormat(format);  // 将格式应用到当前选中的文本
}
  • QTextCharFormat format 创建一个 QTextCharFormat 对象,用来设置文本格式。
  • format.setFontWeight(QFont::Bold) 设置字体加粗。
  • textEdit->mergeCurrentCharFormat(format) 将新的字体格式应用到当前选中的文本。

7. 斜体(setItalic

cpp 复制代码
void TextEditor::setItalic()
{
    QTextCharFormat format;
    format.setFontItalic(true);  // 设置字体为斜体
    textEdit->mergeCurrentCharFormat(format);  // 将格式应用到当前选中的文本
}
  • format.setFontItalic(true) 设置字体为斜体。
  • textEdit->mergeCurrentCharFormat(format) 将斜体格式应用到当前选中的文本。

8. 下划线(setUnderline

cpp 复制代码
void TextEditor::setUnderline()
{
    QTextCharFormat format;
    format.setFontUnderline(true);  // 设置字体为下划线
    textEdit->mergeCurrentCharFormat(format);  // 将格式应用到当前选中的文本
}
  • format.setFontUnderline(true) 设置字体加下划线。
  • textEdit->mergeCurrentCharFormat(format) 将下划线格式应用到当前选中的文本。

9. 设置字体(setFont

cpp 复制代码
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

cpp 复制代码
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

cpp 复制代码
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

cpp 复制代码
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

cpp 复制代码
void TextEditor::setLeftAlignment()
{
    QTextBlockFormat format;
    format.setAlignment(Qt::AlignLeft);  // 设置为左对齐
    textEdit->mergeCurrentBlockFormat(format);  // 将对齐方式应用到当前选中的文本
}
  • format.setAlignment(Qt::AlignLeft) 设置对齐方式为左对齐。
  • textEdit->mergeCurrentBlockFormat(format) 将左对齐的格式应用到当前选中的文本块。

14. 设置居中对齐(setCenterAlignment

cpp 复制代码
void TextEditor::setCenterAlignment()
{
    QTextBlockFormat format;
    format.setAlignment(Qt::AlignCenter);  // 设置为居中对齐
    textEdit->mergeCurrentBlockFormat(format);  // 将对齐方式应用到当前选中的文本
}
  • format.setAlignment(Qt::AlignCenter) 设置对齐方式为居中对齐。
  • textEdit->mergeCurrentBlockFormat(format) 将居中对齐的格式应用到当前选中的文本块。

15. 设置右对齐(setRightAlignment

cpp 复制代码
void TextEditor::setRightAlignment()
{
    QTextBlockFormat format;
    format.setAlignment(Qt::AlignRight);  // 设置为右对齐
    textEdit->mergeCurrentBlockFormat(format);  // 将对齐方式应用到当前选中的文本
}
  • format.setAlignment(Qt::AlignRight) 设置对齐方式为右对齐。
  • textEdit->mergeCurrentBlockFormat(format) 将右对齐的格式应用到当前选中的文本块。

源代码

mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTextEdit>
#include <QMdiSubWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class TextEdit;
class QPrinter;
class QActionGroup;
class QSignalMapper;
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    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

cpp 复制代码
#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

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();          //初始化Mdi
    initFontSize();         //初始化字体框
    initWindowAction();     //初始化窗体action状态
    //initTextAction(false);   //初始化文本action状态
    //当在mdi中添加活动窗体时会触发subWindowActivated信号,关闭窗口会返回0
    connect(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指针,没有返回0
    QMdiSubWindow* 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)){    //初始化Edit
            statusBar()->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);  // 将当前块的缩进设置为 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;  // 未定义的列表样式
            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);  // 设置块缩进为 0
            cursor.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

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

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. 文本格式化功能

文本格式化功能是文本编辑器中的重要部分,可以通过这些功能让文本变得更加生动和富有表现力。代码实现了以下格式化功能:

  • 加粗:

    使用 QTextCharFormatsetFontWeight() 来设置字体的粗细。通过 mergeCurrentCharFormat 方法将加粗格式应用到选中的文本。

  • 斜体:

    通过 setFontItalic(true) 设置文本为斜体,并通过 mergeCurrentCharFormat 应用到选中的文本区域。

  • 下划线:

    设置 fontUnderlinetrue 来为文本添加下划线,应用到选中的文本。

  • 设置字体:

    使用 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(),进而撤销文本编辑器中的操作。

信号与槽的连接使得界面与逻辑操作分离,代码更为模块化、清晰。每个按钮或菜单项触发的操作都与相应的槽函数绑定,保证了应用的灵活性和可扩展性。

相关推荐
人工智能教学实践3 小时前
基于 YOLOv8+PyQt5 界面自适应的无人机红外目标检测系统项目介绍框架
qt·yolo·无人机
40岁的系统架构师4 小时前
17 一个高并发的系统架构如何设计
数据库·分布式·系统架构
安的列斯凯奇5 小时前
Redis篇 Redis如何清理过期的key以及对应的解决方法
数据库·redis·缓存
小小虫码5 小时前
MySQL和Redis的区别
数据库·redis·mysql
飞翔的佩奇7 小时前
Java项目: 基于SpringBoot+mybatis+maven+mysql实现的图书管理系统(含源码+数据库+答辩PPT+毕业论文)
java·数据库·spring boot·mysql·spring·毕业设计·图书管理
一 乐8 小时前
基于vue船运物流管理系统设计与实现(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·后端·船运系统
jerry6099 小时前
注解(Annotation)
java·数据库·sql
m0_6996595610 小时前
QT知识点复习
开发语言·qt
vcshcn10 小时前
DBASE DBF数据库文件解析
数据库·dbase