我使用 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 文件。 现在我想单击蓝色链接,期望文本项自行滚动到确切的标签位置。
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();
}
}
}
}
}