如何使用 RichText textFormat 跳转到大型 Qt/QML 文本项中的 href 哈希标记位置

问题描述 投票:0回答:1

我使用 Qt/QML 文本项来渲染带有一些内部 href 哈希链接的大型独立 HTML 页面。并且容器高度小于其内容高度。一切正常;我可以单击链接并查看控制台日志,但无法将文本项的视觉位置跳转到 href 标记位置。请帮忙。

当我单击 href 链接时,容器中文本项的 y 属性应该已更新。

为了简化我的问题,让我在这里给出一个最小的可重现示例。

import QtQuick

Window {
    id: root
    width: 640
    height: 480
    visible: true

    Rectangle {
        id:container
        height: root.height*.95
        width: root.width*.8
        anchors.centerIn: parent
        Text {
            id: label
            width: container.width
            textFormat: Text.RichText
            wrapMode:Text.WordWrap

            onLinkActivated: function(link){
                console.log(link)
            }
            TapHandler {
                onTapped:function(eventPoint, button){
                    ani.running = !ani.running
                }
            }
            SequentialAnimation on y {
                id: ani
                loops: Animation.Infinite
                running: true
                PropertyAnimation { to: -label.contentHeight/100;duration: 3000 }
                PropertyAnimation { to: 0 ;duration: 3000}
            }
        }
    }
    function makeRequest()
    {
        var doc = new XMLHttpRequest();
        label.text = "";
        doc.onreadystatechange = function() {
            if (doc.readyState === XMLHttpRequest.DONE) {
                label.text = doc.responseText;
            }
        }
        doc.open("GET", "https://www.mpfr.org/mpfr-current/mpfr.html");
        doc.send();
    }
    Component.onCompleted: {
        // label.text = backEnd.loadFile("C:/ebook/GNU MPFR 4.2.1.htm")
        makeRequest()
    }
}

并且可以从 URL 链接手动下载 HTML 文件。 现在我想单击蓝色链接,期望文本项自行滚动到确切的标签位置。

app shuold be like this

html qt qml href
1个回答
0
投票

Text
组件缺乏检索指定文本位置坐标的能力。但是,您可以使用
TextEdit
,其中包含一个
positionToRectangle
方法,该方法可为给定文本
QRect
返回
position

挑战在于文本位置必须对应于纯文本,不包括任何 HTML 或 XML 标签。因此,您需要在格式化文本中找到目标标签的位置,然后将该位置映射到

TextEdit
中的纯文本。由于没有内置函数可以完成此操作,因此我创建了一个辅助组件来确定目标标签在纯文本中的位置。

* 还有一点我忘记提到的是,在

<h1 id="h1">h1</h1>
初始化之后,
<h1><a name="h1"></a>
将转换为
TextEdit
。因此,搜索应该是
<a name="${link}"></a>

ScrollView {
    id: scrollView
    contentWidth: width

    function textgen() {
        return `Table of content:<ul id="top"><li><a href="#h1">h1</a></li><li>
            <a href="#h2">h2</a></li><li><a href="#h3">h3</a></li><li><a href="#h4">h4</a></li></ul>
            <h1 id="h1">h1<sub><a href="#top">top</a></sub></h1>${'sss '.repeat(200)}
            <h1 id="h2">h2<sub><a href="#top">top</a></sub></h1>${'sss '.repeat(200)}
            <h1 id="h3">h3<sub><a href="#top">top</a></sub></h1>${'sss '.repeat(200)}
            <h1 id="h4">h4<sub><a href="#top">top</a></sub></h1>${'sss '.repeat(200)}`;
    }

    NumberAnimation {
        id: animateScroll

        target: scrollView.ScrollBar.vertical
        property: 'position'
        duration: 1000
        easing.type: Easing.InOutCubic
    }

    TextEdit {
        id: textedit

        property TextEdit helper: TextEdit { textFormat: Text.RichText }

        width: root.width
        text: scrollView.textgen()
        readOnly: true
        wrapMode:Text.WordWrap
        textFormat: Text.RichText
        selectByMouse: false
        
        HoverHandler { cursorShape: textedit.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor }
        
        onLinkActivated: link => {
            if(link.startsWith('#')) {
                let idx = text.match(`<a name="${link.slice(1)}"></a>`)?.index ?? -1;
                idx = text.indexOf('>', idx) + 1;

                if(idx !== -1) {
                    // Copying the first slice from the beginning to the target index into the helper TextEdit
                    helper.text = text.slice(0, idx);
                    // The `helper.length` will represent the target position within the plain text.
                    const rect = positionToRectangle(helper.length);

                    animateScroll.to = rect.y/textedit.height;
                    animateScroll.restart();
                }
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.