乐于分享
好东西不私藏

在 Qt 中优雅展示 Markdown 文档——therecipe/QMarkdown 详解与代码示例

在 Qt 中优雅展示 Markdown 文档——therecipe/QMarkdown 详解与代码示例

在 Qt 应用中集成 Markdown 的编辑与预览功能,最成熟、高效的方案之一就是使用 QMarkdownTextEdit。它提供了一个开箱即用的 Markdown 编辑器组件,能为你节省大量从头开发的时间。

下面我来详细介绍它的核心功能、集成方法,并提供一个完整的代码示例。

🔎 QMarkdownTextEdit 是什么?

QMarkdownTextEdit 本质上是一个基于 QPlainTextEdit 的高功能定制版编辑器。开发者 pbek 将编辑器的核心编辑区与 Markdown 语法高亮等功能深度结合,让开发者可以很方便地把一个专业的 Markdown 编辑器嵌入到自己的应用中。

它的设计初衷是处理纯文本文档,不会自动将 Markdown 代码渲染为 HTML,而是通过高亮代码块、标记特定语法等方式,让编辑过程本身更直观。

✨ 核心特性一览

QMarkdownTextEdit 的功能非常全面,覆盖了日常写作到程序员工作的各种需求:

  • Markdown 语法高亮:自动识别并高亮 # 标题**粗体***斜体*- 列表 等语法元素,让文档结构一目了然。

  • 代码块语法高亮:不仅识别 Markdown 的代码块标识符(```),还能对主流编程语言的代码进行语法高亮,对开发者来说非常实用。

  • 交互功能

    • 编辑器功能:支持多级缩进(Tab/Shift+Tab)、快速复制行(Ctrl+Alt+Down)、括号自动闭合等,提升了编辑效率。
    • 文本搜索:内置查找(Ctrl+F)、替换(Ctrl+R),并支持正则表达式和全词匹配。
  • 行号显示:支持显示行号,方便定位和调试(需要 Qt >= 5.5)。

  • Markdown 特性覆盖:支持加粗、斜体、标题、列表(有序/无序)、链接和图片、引用、表格、代码块(缩进式/围栏式)以及删除线等主流 Markdown 语法。

📦 如何集成到你的项目里?

QMarkdownTextEdit 支持通过 QMake 和 CMake 两种主流构建系统进行集成,它也同时支持 Qt5 和 Qt6 两大版本。

方式一:通过 QMake 集成

  1. 将源码仓库中的 qmarkdowntextedit.pri 文件复制到你的项目目录下。
  2. 在你项目的 .pro 文件中,通过 include 指令引入它:
include(qmarkdowntextedit/qmarkdowntextedit.pri)

方式二:通过 CMake 集成

  1. 将 QMarkdownTextEdit 的源码目录放至你的项目子目录中。
  2. 在你项目的 CMakeLists.txt 文件中,通过 add_subdirectory 添加它:
add_subdirectory(qmarkdowntextedit)

在 Qt Designer 中使用完成上述构建系统的配置后,你可以直接在 Qt Designer 中任意拖放一个 QPlainTextEdit 控件并:

  1. 右键点击该控件,选择“**Promote to…**”。
  2. 在弹出的对话框中,“Promoted class name”填写 QMarkdownTextEdit,“Base class name”确保是 QPlainTextEdit,然后点击“Add”和“Promote”即可。
  • 只使用高亮器:不想使用全部功能,只想用它的语法高亮能力,也可以这样做:

    // 假设你的编辑器控件叫 plainTextEdit
    auto doc = ui->plainTextEdit->document();
    // 单独创建高亮器对象,并绑定到指定控件的文档上
    auto *highlighter = new MarkdownHighlighter(doc);

💻 一个完整的代码示例

下面是一个完整的 Qt Widgets 应用示例,它创建了一个简单的 Markdown 编辑器,编辑区右侧有一个预览区,会将输入的 Markdown 实时渲染。

#include<QApplication>
#include<QMainWindow>
#include<QSplitter>
#include<QTextEdit>
#include<QTimer>
#include<QFile>

// 引入 QMarkdownTextEdit
#include"qmarkdowntextedit.h"

classMainWindow :public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
// 1. 创建编辑器组件和高亮器
        editor = new QMarkdownTextEdit(this);
// 启用行号显示
        editor->showLineNumbers(true);
// 设置一个占位符文本
        editor->setPlaceholderText("在这里输入 Markdown...");

// 设置 Markdown 高亮器
        MarkdownHighlighter *highlighter = new MarkdownHighlighter(editor->document());
        Q_UNUSED(highlighter); // 避免编译器警告

// 2. 创建预览区
        preview = new QTextEdit(this);
        preview->setReadOnly(true); // 预览区只读

// 3. 将编辑器与预览区放入分割窗口
        QSplitter *splitter = new QSplitter(Qt::Horizontal, this);
        splitter->addWidget(editor);
        splitter->addWidget(preview);
        splitter->setSizes({width() / 2, width() / 2});
        setCentralWidget(splitter);

        setWindowTitle(tr("Markdown 编辑器 - QMarkdownTextEdit 示例"));
        resize(1000700);

// 4. 实时预览:将编辑器内容变化与预览更新关联
        connect(editor, &QMarkdownTextEdit::textChanged, this, &MainWindow::updatePreview);

// 5. 初始加载一些示例文本
        QTimer::singleShot(0this, &MainWindow::loadExampleText);
    }

private slots:
voidupdatePreview(){
if (!preview) return;

// 获取编辑区当前 Markdown 文本
        QString mdText = editor->toPlainText();

// 方法一:利用 QTextDocument 内置的 Markdown 转换 (Qt 5.14+)
// ---------------------------------------------
// 这是最简单、最直接的方法,无需引入额外库
        QTextDocument doc;
        doc.setMarkdown(mdText); // 将 Markdown 文本设置到文档
        QString html = doc.toHtml(); // 获取转换后的 HTML

// 方法二:如果需要扩展语法支持 (如 LaTeX / Mermaid)
// ---------------------------------------------
// 可以将 mdText 传递给外部转换库 (如 cmark, hoedown, discount 等)
// 或使用 Qt WebEngine 加载 JavaScript Markdown 渲染器
// 这里为了保持示例简单,使用方法一

// 将 HTML 设置到预览区
        preview->setHtml(html);
    }

voidloadExampleText(){
        QString exampleText = 
"# 欢迎使用 QMarkdownTextEdit!\n\n"
"这是一个 **功能强大** 的 Markdown 编辑器组件。\n\n"
"## 主要特性\n\n"
"- 实时语法高亮\n"
"- 代码块高亮\n"
"- 行号显示\n"
"- 搜索/替换\n\n"
"## 代码示例\n\n"
"```cpp\n"
"#include <iostream>\n"
"int main() {\n"
"    std::cout << \"Hello, Markdown!\" << std::endl;\n"
"    return 0;\n"
"}\n"
"```\n\n"
"> 这是一个引用块。\n\n"
"更多信息请访问 [GitHub 仓库](https://github.com/pbek/qmarkdowntextedit)。";

        editor->setPlainText(exampleText);
    }

private:
    QMarkdownTextEdit *editor;
    QTextEdit *preview;
};

intmain(int argc, char *argv[]){
QApplication app(argc, argv);
    MainWindow window;
    window.show();
return app.exec();
}

// 如果你在使用 Qt 5 且编译时遇到 moc 问题,请确保该文件被包含在项目的 HEADERS 中,
// 或者将上述类定义和实现分开到头文件和源文件中。
#include"main.moc"
  • 构建配置:请务必根据你使用的构建工具(QMake 或 CMake)正确集成 QMarkdownTextEdit
  • Qt版本要求:代码中用于预览的 doc.setMarkdown() 方法要求 Qt 5.14 或更高版本。
  • 依赖管理QMarkdownTextEdit 本身是纯头文件/源码的组件,无需安装额外的动态库或静态库,直接包含源文件即可编译。

如果你需要更高级的渲染(例如支持 LaTeX 或 Mermaid 图表),可以考虑将上述代码中的 updatePreview() 方法替换为连接一个本地的 HTTP 服务,通过 QWebEngineView 加载一个成熟的 JavaScript 库(如 marked.js + highlight.js + katex)来进行渲染。

💎 总结与补充

总的来说,QMarkdownTextEdit 为你提供了一个近乎 QPlainTextEdit 的平替选择,是一个强大、高效的 Markdown 编辑器组件。如果你的应用场景是纯编辑,这个库几乎不需要你做额外工作。

  • 常用特性快捷键
    • **Ctrl+Click**:打开链接或文件路径。
    • **Ctrl+Alt+Down**:复制当前行。
    • **Ctrl+F / Ctrl+R**:查找与替换。
  • 常见问题解决
    • 编译错误:确保你的 Qt 版本支持所用特性,并已正确配置构建系统以包含库的源文件和头文件。
    • 高亮不生效:检查是否正确创建了 MarkdownHighlighter 实例并绑定到了目标控件上。
    • 老版本 Qt (5.14 以下) 预览方案
    1. **使用 QTextDocumentWriter**:利用 Qt 内置的 QTextDocumentWriter 将文档转为 HTML。
    2. **使用 QWebEngineView**:在应用内嵌入一个轻量级浏览器控件。
    3. 使用外部库:集成 cmark 或 hoedown 等高性能 C 库进行转换。

如果你计划创建一个兼具所见即所得体验的编辑器,也可以考虑 QMarkdownView(主要提供预览功能)或功能更全面的 QMarkdowner,它们在这个方向上探索得更深。