In a web browser, when you hover the mouse over a link it changes to the pointing hand. I want to achieve the same in QML.
Here is a QML Text
element containing a block of text, using HTML markup, that includes a couple of links:
Text { id: bodyMessage
anchors.fill: parent
textFormat: Text.RichText
wrapMode: Text.WordWrap
text:
'<p>' + qsTr('Here is my first paragraph.') + '</p>' +
'<p>' + qsTr('My second paragraph contains the <a href="link1">first link</a>.') + '</p>' +
'<p>' + qsTr('My third paragraph contains the <a href="link2">second link</a> and that is it.') + '</p>'
onLinkActivated:
(link) =>
console.log('Link activated to: `' + link + '`')
}
The problem is that the mouse cursor does not change to a pointing hand when it is over either link.
I tried a child MouseArea
as follows:
MouseArea {
anchors.fill: parent
hoverEnabled: true
onPositionChanged:
(mouse) =>
cursorShape = bodyMessage.linkAt(mouse.x, mouse.y) ? Qt.PointingHandCursor : Qt.ArrowCursor
}
This does get the mouse cursor to change as desired, but it blocks mouse signals to Text
, so onLinkActivated
no longer works.
To solve that new problem, I added the following to MouseArea
:
onClicked:
(mouse) =>
{
let link = bodyMessage.linkAt(mouse.x, mouse.y)
if (link.length > 0)
console.log('Link activated to: `' + link + '`')
}
While this does work, it renders Text.linkActivated
obsolete, which seems to me the wrong approach and the code looks bloated to me.
Consider adding HoverHandler
to your Text
:
Text {
HoverHandler {
enabled: parent.hoveredLink
cursorShape: Qt.PointingHandCursor
}
}
If we wish to control the color of the link when it's hovered, not hovered, we use a conditional on hoveredLink:
Text {
text: qsTr('<style>a:link{color:%1;}</style>My second paragraph contains the <a href="https://stackoverflow.com"> StackOverflow link</a>.').arg(hoveredLink ? "purple" : "red")
}
Here's a full working example:
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
title: "HoverHandler Demo"
ColumnLayout {
width: parent.width
spacing: 10
Frame { Label { text: "Initial Solution" } }
LinkText {
text: `
<p>${qsTr('Here is my first paragraph.')}</p>
<p>${qsTr('My second paragraph contains the <a href="link1">first link</a>.')}</p>
<p>${qsTr('My third paragraph contains the <a href="link2">second link</a> and that is it.')}</p>
`
}
Frame { Label { text: "Revised Solution" } }
LinkText { text: qsTr('Here is my first paragraph.') }
LinkText { text: qsTr('<style>a:link{color:%1;}</style>My second paragraph contains the <a href="https://stackoverflow.com"> StackOverflow link</a>.').arg(hoveredLink ? "purple" : "red") }
LinkText { text: qsTr('<style>a:link{color:%1;}</style>My third paragraph contains the <a href="https://www.google.com" style="{link:red}">Google link</a> and that is it.').arg(hoveredLink ? "purple" : "red") }
}
}
// LinkText.qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Text {
Layout.fillWidth: true
textFormat: Text.RichText
wrapMode: Text.WordWrap
HoverHandler {
enabled: parent.hoveredLink
cursorShape: Qt.PointingHandCursor
}
onLinkActivated: {
console.log('Link activated to: `' + link + '`');
Qt.openUrlExternally(link);
}
}
You can Try it Online!
References: