PDF Multipage Viewer Example
A PDF viewer that allows scrolling through the pages.
PDF Multipage Viewer demonstrates how to use the PdfMultiPageView component to render PDF documents and search for text in them.
Running the Example
To run the example from Qt Creator, open the Welcome mode and select the example from Examples. For more information, visit Building and Running an Example.
Creating the Main Window
Instantiate an ApplicationWindow, bind its title to the title of the PDF document, and create a toolbar:
ApplicationWindow { id: root width: 800 height: 1024 color: "lightgrey" title: document.title visible: true property string source // for main.cpp header: ToolBar { RowLayout { anchors.fill: parent anchors.rightMargin: 6
The toolbar has buttons for most of the common actions:
ToolButton { action: Action { shortcut: StandardKey.Open icon.source: "qrc:/pdfviewer/resources/document-open.svg" onTriggered: fileDialog.open() } } ToolButton { action: Action { shortcut: StandardKey.ZoomIn enabled: view.renderScale < 10 icon.source: "qrc:/pdfviewer/resources/zoom-in.svg" onTriggered: view.renderScale *= Math.sqrt(2) } } ToolButton { action: Action { shortcut: StandardKey.ZoomOut
Declare a PdfDocument and bind the status
property and passwordRequired
signal to inform the user when an error occurs or a password is required:
Dialog { id: passwordDialog title: "Password" standardButtons: Dialog.Ok | Dialog.Cancel modal: true closePolicy: Popup.CloseOnEscape anchors.centerIn: parent width: 300 TextField { id: passwordField placeholderText: qsTr("Please provide the password") echoMode: TextInput.Password width: parent.width onAccepted: passwordDialog.accept() } onAccepted: document.password = passwordField.text } Dialog { id: errorDialog title: "Error loading " + document.source standardButtons: Dialog.Ok modal: true closePolicy: Popup.CloseOnEscape anchors.centerIn: parent width: 300 Label { id: errorField text: document.error } } PdfDocument { id: document source: Qt.resolvedUrl(root.source) onStatusChanged: { if (status === PdfDocument.Error) errorDialog.open() view.document = (status === PdfDocument.Ready ? document : undefined) } onPasswordRequired: { passwordDialog.open() passwordField.forceActiveFocus() } }
Add the main component, PdfMultiPageView:
PdfMultiPageView { id: view anchors.fill: parent anchors.leftMargin: searchDrawer.position * searchDrawer.width document: root.document searchString: searchField.text onCurrentPageChanged: currentPageSB.value = view.currentPage + 1 }
A Drawer holds a ListView to show search results from the searchModel:
Drawer { id: searchDrawer edge: Qt.LeftEdge modal: false width: 300 y: root.header.height height: view.height dim: false clip: true ListView { id: searchResultsList anchors.fill: parent anchors.margins: 2 model: view.searchModel ScrollBar.vertical: ScrollBar { } delegate: ItemDelegate { width: parent ? parent.width : 0 RowLayout { anchors.fill: parent spacing: 0 Label { text: "Page " + (page + 1) + ": " } Label { text: contextBefore elide: Text.ElideLeft horizontalAlignment: Text.AlignRight Layout.fillWidth: true Layout.preferredWidth: parent.width / 2 } Label { font.bold: true text: view.searchString width: implicitWidth } Label { text: contextAfter elide: Text.ElideRight Layout.fillWidth: true Layout.preferredWidth: parent.width / 2 } } highlighted: ListView.isCurrentItem onClicked: { searchResultsList.currentIndex = index view.goToLocation(page, location, 0) view.searchModel.currentResult = indexOnPage } } } }
Finally, add a second toolbar as a footer, to hold the search field, search up/down buttons and some status information:
footer: ToolBar { height: footerRow.implicitHeight RowLayout { id: footerRow anchors.fill: parent ToolButton { action: Action { icon.source: "qrc:/pdfviewer/resources/go-up-search.svg" shortcut: StandardKey.FindPrevious onTriggered: view.searchBack() } ToolTip.visible: enabled && hovered ToolTip.delay: 2000 ToolTip.text: "find previous" } TextField { id: searchField placeholderText: "search" Layout.minimumWidth: 150 Layout.fillWidth: true onAccepted: searchDrawer.open() Image { visible: searchField.text !== "" source: "qrc:/pdfviewer/resources/edit-clear.svg" anchors { right: parent.right top: parent.top bottom: parent.bottom margins: 3 rightMargin: 5 } TapHandler { onTapped: searchField.clear() } } } ToolButton { action: Action { icon.source: "qrc:/pdfviewer/resources/go-down-search.svg" shortcut: StandardKey.FindNext onTriggered: view.searchForward() } ToolTip.visible: enabled && hovered ToolTip.delay: 2000 ToolTip.text: "find next" } Label { id: statusLabel property size implicitPointSize: document.pagePointSize(view.currentPage) text: "page " + (currentPageSB.value) + " of " + document.pageCount + " scale " + view.renderScale.toFixed(2) + " original " + implicitPointSize.width.toFixed(1) + "x" + implicitPointSize.height.toFixed(1) + " pt" visible: document.pageCount > 0 } } } }
Files and Attributions
Files:
- multipage/CMakeLists.txt
- multipage/main.cpp
- multipage/multipage.pro
- multipage/resources/document-open.svg
- multipage/resources/edit-clear.svg
- multipage/resources/edit-copy.svg
- multipage/resources/edit-select-all.svg
- multipage/resources/go-down-search.svg
- multipage/resources/go-next-view-page.svg
- multipage/resources/go-previous-view-page.svg
- multipage/resources/go-up-search.svg
- multipage/resources/rotate-left.svg
- multipage/resources/rotate-right.svg
- multipage/resources/zoom-fit-best.svg
- multipage/resources/zoom-fit-width.svg
- multipage/resources/zoom-in.svg
- multipage/resources/zoom-original.svg
- multipage/resources/zoom-out.svg
- multipage/viewer.qml
- multipage/viewer.qrc
© 2022 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.