如何使用QPrinter和QPrintPreviewDialog
我想通过打印机预览并打印一份报告,使用的是PyQt。我试了以下代码:
printer = QtGui.QPrinter()
doc = QtGui.QTextDocument("testing")
dialog = QtGui.QPrintDialog(printer)
dialog.setModal(True)
dialog.setWindowTitle("printerrr")
pdialog = QtGui.QPrintPreviewDialog(printer)
pdialog.setWindowFlags(QtCore.Qt.Window)
pdialog.exec_()
我该怎么做才能先预览我的报告,然后再打印呢?
2 个回答
2
这是一个关于PyQt5的更新,参考了ekhumoro的示例,这个更新提供了图表的打印预览和打印功能:
from PyQt5 import QtChart, QtCore, QtGui, QtPrintSupport, QtWidgets
import sys
import random
class Window(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.setWindowTitle(self.tr('Chart Printing'))
self.chart = QtChart.QChart()
self.chart_view = QtChart.QChartView(self.chart)
self.chart_view.setRenderHint(QtGui.QPainter.Antialiasing)
self.buttonPreview = QtWidgets.QPushButton('Preview', self)
self.buttonPreview.clicked.connect(self.handle_preview)
self.buttonPrint = QtWidgets.QPushButton('Print', self)
self.buttonPrint.clicked.connect(self.handle_print)
layout = QtWidgets.QGridLayout(self)
layout.addWidget(self.chart_view, 0, 0, 1, 2)
layout.addWidget(self.buttonPreview, 1, 0)
layout.addWidget(self.buttonPrint, 1, 1)
self.create_chart()
def create_chart(self):
self.chart.setTitle("Chart Print Preview and Print Example")
for i in range(5):
series = QtChart.QLineSeries()
series.setName("Line {}".format(i + 1))
series.append(0, 0)
for i in range(1, 10):
series.append(i, random.randint(1, 9))
series.append(10, 10)
self.chart.addSeries(series)
self.chart.createDefaultAxes()
def handle_print(self):
printer = QtPrintSupport.QPrinter(QtPrintSupport.QPrinter.HighResolution)
dialog = QtPrintSupport.QPrintDialog(printer, self)
if dialog.exec_() == QtPrintSupport.QPrintDialog.Accepted:
self.handle_paint_request(printer)
def handle_preview(self):
dialog = QtPrintSupport.QPrintPreviewDialog()
dialog.paintRequested.connect(self.handle_paint_request)
dialog.exec_()
def handle_paint_request(self, printer):
painter = QtGui.QPainter(printer)
painter.setViewport(self.chart_view.rect())
painter.setWindow(self.chart_view.rect())
self.chart_view.render(painter)
painter.end()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())
补充说明:如果想让上面的示例代码在Windows上运行,需要:
> pip install PyQt5
> pip install pyqt5-tools
> pip install PyQtChart
22
这是一个关于Qt打印对话框的基本演示:
更新:
除了下面提到的解决方案,还有一个替代方案是使用Qt WebEngine来渲染和打印文档。这样可以支持更多类型的文档,不仅限于HTML,还包括PDF、图片、纯文本等。在下面的例子中,Printer
类是基于Qt文档中的WebEngine Widgets PrintMe示例。
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import QtPrintSupport, QtWebEngineWidgets
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.viewer = QtWebEngineWidgets.QWebEngineView(self)
self.viewer.settings().setAttribute(
QtWebEngineWidgets.QWebEngineSettings.PluginsEnabled, True)
self.viewer.settings().setAttribute(
QtWebEngineWidgets.QWebEngineSettings.PdfViewerEnabled, True)
self.buttonOpen = QtWidgets.QPushButton('Open', self)
self.buttonOpen.clicked.connect(self.handleOpen)
self.buttonPrint = QtWidgets.QPushButton('Print', self)
self.buttonPrint.clicked.connect(self.handlePrint)
self.buttonPreview = QtWidgets.QPushButton('Preview', self)
self.buttonPreview.clicked.connect(self.handlePreview)
layout = QtWidgets.QGridLayout(self)
layout.addWidget(self.viewer, 0, 0, 1, 3)
layout.addWidget(self.buttonOpen, 1, 0)
layout.addWidget(self.buttonPrint, 1, 1)
layout.addWidget(self.buttonPreview, 1, 2)
self.printer = Printer(self.viewer.page(), self)
def handleOpen(self):
if path := QtWidgets.QFileDialog.getOpenFileName(self)[0]:
self.viewer.load(QtCore.QUrl.fromLocalFile(path))
def handlePrint(self):
if self.viewer.url().isValid():
self.printer.print()
def handlePreview(self):
if self.viewer.url().isValid():
self.printer.preview()
class Printer(QtCore.QObject):
def __init__(self, page, parent=None):
super().__init__(parent)
self._page = page
self._printing = False
def render(self, printer):
loop = QtCore.QEventLoop()
failed = False
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
def callback(result):
nonlocal failed
failed = not result
QtWidgets.QApplication.restoreOverrideCursor()
loop.quit()
self._page.print(printer, callback)
loop.exec()
if failed:
painter = QtGui.QPainter()
if painter.begin(printer):
font = painter.font()
font.setPixelSize(20)
painter.setFont(font)
painter.drawText(QtCore.QPointF(10, 25),
'Could not generate print preview')
painter.end()
def preview(self):
if not self._printing:
self._printing = True
printer = QtPrintSupport.QPrinter()
printer.setResolution(300)
dialog = QtPrintSupport.QPrintPreviewDialog(
printer, self._page.view())
dialog.paintRequested.connect(self.render)
dialog.exec()
dialog.deleteLater()
self._printing = False
def print(self):
printer = QtPrintSupport.QPrinter(
QtPrintSupport.QPrinter.HighResolution)
dialog = QtPrintSupport.QPrintDialog(printer, self._page.view())
if dialog.exec() == QtWidgets.QDialog.Accepted:
self.render(printer)
dialog.deleteLater()
if __name__ == '__main__':
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
app = QtWidgets.QApplication(['Printing Demo'])
window = Window()
window.setGeometry(600, 100, 800, 600)
window.show()
app.exec()
之前的示例:
PyQt4:
import sys, os
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.setWindowTitle('Document Printer')
self.editor = QtGui.QTextEdit(self)
self.editor.textChanged.connect(self.handleTextChanged)
self.buttonOpen = QtGui.QPushButton('Open', self)
self.buttonOpen.clicked.connect(self.handleOpen)
self.buttonPrint = QtGui.QPushButton('Print', self)
self.buttonPrint.clicked.connect(self.handlePrint)
self.buttonPreview = QtGui.QPushButton('Preview', self)
self.buttonPreview.clicked.connect(self.handlePreview)
layout = QtGui.QGridLayout(self)
layout.addWidget(self.editor, 0, 0, 1, 3)
layout.addWidget(self.buttonOpen, 1, 0)
layout.addWidget(self.buttonPrint, 1, 1)
layout.addWidget(self.buttonPreview, 1, 2)
self.handleTextChanged()
def handleOpen(self):
path = QtGui.QFileDialog.getOpenFileName(
self, 'Open file', '',
'HTML files (*.html);;Text files (*.txt)')
if path:
file = QtCore.QFile(path)
if file.open(QtCore.QIODevice.ReadOnly):
stream = QtCore.QTextStream(file)
text = stream.readAll()
info = QtCore.QFileInfo(path)
if info.completeSuffix() == 'html':
self.editor.setHtml(text)
else:
self.editor.setPlainText(text)
file.close()
def handlePrint(self):
dialog = QtGui.QPrintDialog()
if dialog.exec_() == QtGui.QDialog.Accepted:
self.editor.document().print_(dialog.printer())
def handlePreview(self):
dialog = QtGui.QPrintPreviewDialog()
dialog.paintRequested.connect(self.editor.print_)
dialog.exec_()
def handleTextChanged(self):
enable = not self.editor.document().isEmpty()
self.buttonPrint.setEnabled(enable)
self.buttonPreview.setEnabled(enable)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())
PyQt5:
import sys, os
from PyQt5 import QtCore, QtWidgets, QtPrintSupport
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.setWindowTitle('Document Printer')
self.editor = QtWidgets.QTextEdit(self)
self.editor.textChanged.connect(self.handleTextChanged)
self.buttonOpen = QtWidgets.QPushButton('Open', self)
self.buttonOpen.clicked.connect(self.handleOpen)
self.buttonPrint = QtWidgets.QPushButton('Print', self)
self.buttonPrint.clicked.connect(self.handlePrint)
self.buttonPreview = QtWidgets.QPushButton('Preview', self)
self.buttonPreview.clicked.connect(self.handlePreview)
layout = QtWidgets.QGridLayout(self)
layout.addWidget(self.editor, 0, 0, 1, 3)
layout.addWidget(self.buttonOpen, 1, 0)
layout.addWidget(self.buttonPrint, 1, 1)
layout.addWidget(self.buttonPreview, 1, 2)
self.handleTextChanged()
def handleOpen(self):
path = QtWidgets.QFileDialog.getOpenFileName(
self, 'Open file', '',
'HTML files (*.html);;Text files (*.txt)')[0]
if path:
file = QtCore.QFile(path)
if file.open(QtCore.QIODevice.ReadOnly):
stream = QtCore.QTextStream(file)
text = stream.readAll()
info = QtCore.QFileInfo(path)
if info.completeSuffix() == 'html':
self.editor.setHtml(text)
else:
self.editor.setPlainText(text)
file.close()
def handlePrint(self):
dialog = QtPrintSupport.QPrintDialog()
if dialog.exec_() == QtWidgets.QDialog.Accepted:
self.editor.document().print_(dialog.printer())
def handlePreview(self):
dialog = QtPrintSupport.QPrintPreviewDialog()
dialog.paintRequested.connect(self.editor.print_)
dialog.exec_()
def handleTextChanged(self):
enable = not self.editor.document().isEmpty()
self.buttonPrint.setEnabled(enable)
self.buttonPreview.setEnabled(enable)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())
要打印预览一个图形视图,可以使用它的render
方法:
def handlePreview(self):
# dialog = QtPrintSupport.QPrintPreviewDialog() # PyQt5
dialog = QtGui.QPrintPreviewDialog()
dialog.paintRequested.connect(self.handlePaintRequest)
dialog.exec_()
def handlePaintRequest(self, printer):
self.view.render(QtGui.QPainter(printer))