qt - 如何从组件 QTextDocument 获取没有元信息的 HTML 文本

标签 qt qml richtext qtextdocument qtextcursor

描述

我创建了一个 TextArea QML 中的组件,类似于 this例如,我基于指向 QQuickTextDocument 的指针创建了一个 DocumentHandler 类。 ,这是通过 textDocument 获取的属性(property)。我需要这个以便能够格式化文本,即使其粗体、下划线、斜体、删除线等。

我需要什么

我需要获取一个文本,其中格式化部分将显示为 HTML 标记。

例如粗体文本最终我想采用<b>Bold text</b>形式。或者例如粗体和斜体文本我想采用<b><i>Bold and italic text</i></b>形式(标签放置的顺序并不重要)。

我尝试了什么

我尝试使用 toHtml()函数,但这个函数不适合我,因为:

  1. 它会生成很多我不需要的不必要信息。例如,对于粗体文本,它返回以下结果:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
</style></head><body style=" font-family:'Roboto'; font-size:14px; font-weight:400; font-style:normal;">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Bold text</span></p></body></html>
  • 我需要表示文本的常用标签( <b><i> 等),该函数以 style 的形式形成<span> 的属性标签。因此它用这一行更改了粗体:<span style=" font-weight:600;"> .
  • 最佳答案

    描述

    如果我理解正确的话,目前没有办法在没有 QTextDocument 生成的元信息的情况下获取带有 HTML 标签的格式化文本。使用toHtml()功能。因此,我决定使用 QTextCursor 手动完成这项工作。类。

    代码

    我有一个提供有关标签信息的结构:

    struct Tag
    {
        Tag() = default;
        Tag(const QString& openTag,
            const QString& closeTag,
            const std::function<bool(const QTextCursor& cursor)>& canBeOpened);
    
        QString getOpenTag() const
        {
            return m_openTag;
        }
    
        QString getCloseTag() const
        {
            return m_closeTag;
        }
    
        bool canBeOpened(const QTextCursor& cursor) const
        {
            return m_canBeOpened(cursor);
        }
    
    private:
        QString m_openTag;
        QString m_closeTag;
        std::function<bool(const QTextCursor&)> m_canBeOpened;
    };
    

    我有一个std::vector我初始化如下的此类结构:

    m_tags{ { "<b>", "</b>", [](const QTextCursor& cursor) { return cursor.charFormat().fontWeight() == QFont::Bold; } },
            { "<i>", "</i>", [](const QTextCursor& cursor) { return cursor.charFormat().fontItalic(); } },
            { "<u>", "</u>", [](const QTextCursor& cursor) { return cursor.charFormat().fontUnderline(); } },
            { "<s>", "</s>", [](const QTextCursor& cursor) { return cursor.charFormat().fontStrikeOut(); } } }
    

    最重要的是getFormattedText()使用 Tag 这个向量的函数对象返回格式化文本。主要思想是手动在纯文本中放置标签,即开始标签放置在格式开始的地方,结束标签放置在格式结束的地方。有关文本中何处使用什么格式的信息可以从 QTextCursor 获取。类,我们的对象 can create基于QTextDocument类(class)。结果,我们有以下功能:

    QString getFormattedText()
    {
        auto cursor{ textCursor() };
        if (!cursor.isNull())
        {
            int offset{};
            auto result{ cursor.document()->toPlainText() };
            auto currentTextFormat{ getTextFormat() };
            for (int i{}; i < cursor.document()->characterCount(); ++i)
            {
                cursor.setPosition(i);
    
                const auto localTextFormat{ getTextFormat(cursor) };
                if (currentTextFormat != localTextFormat)
                {
                    const auto closedFormat{ getClosedFormat(currentTextFormat) };
                    const auto openedFormat{ getOpenedFormat(localTextFormat) };
                    result.insert(i - (i > 0 ? 1 : 0) + offset, closedFormat + openedFormat);
                    offset += closedFormat.size() + openedFormat.size();
                    currentTextFormat = localTextFormat;
                }
            }
            result += getClosedFormat(currentTextFormat);
            return result.replace("\n", "<br>");
        }
        return {};
    }
    

    currentTextFormat 相关的逻辑和localTextFormat为了“及时”关闭一种格式组合并打开一种新格式,变量是必要的。这种格式的组合被命名为:

    using TextFormat = std::vector<std::pair<FontFormat, bool>>;
    

    哪里FontFormat是:

    enum class FontFormat
    {
        Bold,
        Italic,
        Underline,
        Strikethrough
    };
    

    获取TextFormat的函数:

    TextFormat getTextFormat()
    {
        TextFormat textFormat;
        for (const auto& format : m_formats)
        {
            textFormat.push_back({ format.first, false });
        }
        return textFormat;
    }
    
    TextFormat getTextFormat(const QTextCursor& cursor)
    {
        TextFormat textFormat;
        for (const auto& format : m_formats)
        {
            textFormat.push_back({ format.first, format.second.canBeOpened(cursor) });
        }
        return textFormat;
    }
    

    获取 TextFormat 文本解释的函数:

    QString getOpenedFormat(const TextFormat& textFormat)
    {
        const auto append = [](QString& result, const Tag& tag) {
            result.push_back(tag.getOpenTag());
        };
        return getFormat(textFormat, append);
    }
    
    QString getClosedFormat(const TextFormat& textFormat)
    {
        const auto append = [](QString& result, const Tag& tag) {
            result.prepend(tag.getCloseTag());
        };
        return getFormat(textFormat, append);
    }
    
    QString getFormat(const TextFormat& textFormat, const std::function<void(QString&, const Tag&)>& append)
    {
        QString result;
        for (const auto& format : textFormat)
        {
            if (format.second)
            {
                const auto fndFontFormat{ m_formats.find(format.first) };
                if (fndFontFormat != m_formats.end())
                {
                    append(result, fndFontFormat->second);
                }
            }
        }
        return result;
    }
    

    例如有这样的文字:abc。本文的每个字母都有不同的格式组合,当从一个字母迭代到另一个字母时,有必要考虑到这一点,关闭旧的组合并打开一个新的组合。

    因此 abc 将转换为:<b>a</b><b><s>b</b></s><s>c</s> .

    关于qt - 如何从组件 QTextDocument 获取没有元信息的 HTML 文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67920546/

    相关文章:

    c++ - Qt中的单例类问题

    qt - __FILE __,__ LINE__和__FUNCTION__用于QML文件吗?

    qt - 如何将 JavaScript 文件注入(inject) WebEngineView 页面?

    c# - 将 .rtf 文件加载到 RichTextBox 中并维护/保留格式

    ruby-on-rails - 无法在控制台中获取 Rails 操作文本

    qt - 如何在上下文菜单中添加选中/取消选中 QAction?

    c++ - 尽管调用了 wakeAll,仍有 2 个线程在 QWaitCondition 上等待

    qt - Qml 项目状态 : previous state

    flutter - FutureBuilder 方法 'findRenderObject' 被调用为 null

    python - PyQt 中信号处理程序会内存泄漏吗?