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

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

相关推荐
小陈工4 小时前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
科技小花8 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸8 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain8 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希9 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神9 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员9 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java9 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿9 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴10 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存