I am developing an application in Qt with Quick and some QML.
I need to interact with the contents of a pdf file opened inside of QPdfMultipageView. More specifically, I need the text to be selectable with mouse. Currently, there is no clear example in Qt documentation of how to achieve this with an already pre-defined view, such as PdfMultipageView.
ApplicationWindow {
id: root
width: 800
height: 1024
color: "darkgrey"
title: doc.title
visible: true
property string source // for main.cpp
PdfMultiPageView {
id: view
anchors.fill: parent
document: doc
}
PdfDocument {
id: doc
source: Qt.resolvedUrl(root.source)
}
PdfSelection {
id: selection
document: doc
from: textSelectionDrag.centroid.pressPosition
to: textSelectionDrag.centroid.position
hold: !textSelectionDrag.active
}
Shape {
ShapePath {
PathMultiline {
paths: selection.geometry
}
}
}
DragHandler {
id: textSelectionDrag
acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
target: null
}
In docs, under the PdfSelection type description, there is an example, but it does not include view, only the document.
In my case, PdfMultipageView handles the input in first place, hence not letting it pass to the DragHandler, which, in turn, should handle and update text selection. Also, there is no property in the view related to its ability to handle input, so I cannot tell it to not handle the input - it is always interactive and I cannot change this.
Any help would be greatly appreciated.
I've found a way to achieve desired functionality.
I put the PdfMultipageView under the MouseArea and placed the mouse area on top of the PdfMultipageView by specifying z: -1
for the PdfMultipageView component. MouseArea has handlers for different signals, but the important ones are onPressed, onPositionChanged and onReleased.
In the onPressed handler I set the accepted flag of the incoming mouse event to true, so this event is not passed further, thus pdfView won't consume it and will not move. Also I set the textSelection.from point to the mouse press position.
In the onPositionChanged handler (active when mouse is being moved and left key is pressed) the textSelection.to is being constantly updated until mouse button is released.
ApplicationWindow{
id: root
width: 800
height: 1024
color: "darkgrey"
title: doc.title
visible: true
required property url source // for main.py
property real scaleStep: Math.sqrt(2)
PdfDocument{
id: doc
source: Qt.resolvedUrl(root.source)
}
Shape {
z: 1
opacity: 0.3
ShapePath {
strokeWidth: 0
fillColor: "blue"
PathMultiline {
paths: textSelection.geometry
}
}
}
PdfSelection {
id: textSelection
anchors.fill: parent
from: "0,0"
to: "0,0"
document: doc
hold: !pdfMouseArea.dragIsActive
}
MouseArea {
id: pdfMouseArea
anchors.fill: parent
property bool dragIsActive: false
PdfMultiPageView {
z: -1
id: pdfView
anchors.fill: parent
anchors.leftMargin: -8
document: doc
Component.onCompleted: {
//pdfView.scaleToPage(parent.width, parent.height);
textSelection.renderScale = pdfView.renderScale;
}
}
onPressed: (event) => {
pdfMouseArea.dragIsActive = true;
textSelection.from = textSelection.to = event.x + "," + event.y;
console.log("MouseArea: onPressed");
}
onPositionChanged: (event) => {
event.accepted = true;
console.log("PosChangeSignalCoords: ", event.x, event.y);
textSelection.to = event.x + "," + event.y;
console.log("PosChangeSignalTextSelectionCoords: From: ",
textSelection.from, " To: ", textSelection.to);
cursorShape = Qt.IBeamCursor;
console.log(textSelection.text);
}
onReleased: (event) => {
event.accepted = true;
console.log("MouseArea: onReleased");
cursorShape = Qt.ArrowCursor;
pdfMouseArea.dragIsActive = false;
}
}
}
However, it is still very buggy since by default selection and its path are not linked to the page where the text content is. So the coordinates of the selection path don't consider any margins of the PdfMultipageView. In case of scrolling through pages the selection path is still being drawn at the same place it was previously drawn, like it is living on a separate layer. This logic needs to be implemented manually, unfortunately.