繁体   English   中英

如何在 PyQt5 中“打印预览”由 QTextDocument 创建的文档?

[英]How can I "Print Preview" of document created by QTextDocument in PyQt5?

专家您好!! 我希望你有美好的一天。 我是 GUI 编程的新手,特别是 PyQt5。 我正在练习简单的 GUI 发票应用程序。 在这个应用程序中,我成功地生成了 Invoice By QTextDocument。 现在我想添加打印对话框和打印预览选项。 我在代码中遇到了问题。 这是在说

AttributeError: 'InvoiceForm' 对象没有属性 'printpreviewDialog

因为我是新手,所以我在那里有点困惑。 你能修复一下代码吗? 这对我学习有很大帮助。 非常感谢。 代码如下:-

import sys
from PyQt5.QtCore import pyqtSignal, QSize, QSizeF, QDate
from PyQt5.QtGui import QTextDocument, QTextCursor, QFont
from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
from PyQt5.QtWidgets import QWidget, QFormLayout, QLineEdit, QPlainTextEdit, QSpinBox, QDateEdit, QTableWidget, \
    QHeaderView, QPushButton, QHBoxLayout, QTextEdit, QApplication, QMainWindow

font= QFont('Arial',16)

class InvoiceForm(QWidget):
    submitted = pyqtSignal(dict)
    def __init__(self):
        super().__init__()
        self.setLayout(QFormLayout())
        self.inputs = dict()
        self.inputs['Customer Name'] = QLineEdit()
        self.inputs['Customer Address'] = QPlainTextEdit()
        self.inputs['Invoice Date'] = QDateEdit(date=QDate.currentDate(), calendarPopup=True)
        self.inputs['Days until Due'] = QSpinBox()
        for label, widget in self.inputs.items():
            self.layout().addRow(label, widget)

        self.line_items = QTableWidget(rowCount=10, columnCount=3)
        self.line_items.setHorizontalHeaderLabels(['Job', 'Rate', 'Hours'])
        self.line_items.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.layout().addRow(self.line_items)
        for row in range(self.line_items.rowCount()):
            for col in range(self.line_items.columnCount()):
                if col > 0:
                    w = QSpinBox()
                    self.line_items.setCellWidget(row, col, w)

        submit = QPushButton('Create Invoice', clicked=self.on_submit)
        print = QPushButton('Print Invoice', clicked=self.printpreviewDialog)
        self.layout().addRow(submit,print)

    def on_submit(self):
        data = {'c_name': self.inputs['Customer Name'].text(),
                'c_addr': self.inputs['Customer Address'].toPlainText(),
                'i_date': self.inputs['Invoice Date'].date().toString(),
                'i_due': self.inputs['Invoice Date'].date().addDays(self.inputs['Days until Due'].value()).toString(),
                'i_terms': '{} days'.format(self.inputs['Days until Due'].value()),
                'line_items': list()}

        for row in range(self.line_items.rowCount()):
            if not self.line_items.item(row, 0):
                continue
            job = self.line_items.item(row, 0).text()
            rate = self.line_items.cellWidget(row, 1).value()
            hours = self.line_items.cellWidget(row, 2).value()
            total = rate * hours
            row_data = [job, rate, hours, total]
            if any(row_data):
                data['line_items'].append(row_data)

        data['total_due'] = sum(x[3] for x in data['line_items'])
        self.submitted.emit(data)
        # remove everything else in this function below this point

class InvoiceView(QTextEdit):
    dpi = 72
    doc_width = 8.5 * dpi
    doc_height = 6 * dpi

    def __init__(self):
        super().__init__(readOnly=True)
        self.setFixedSize(QSize(self.doc_width, self.doc_height))

    def build_invoice(self, data):
        document = QTextDocument()
        self.setDocument(document)
        document.setPageSize(QSizeF(self.doc_width, self.doc_height))
        document.setDefaultFont(font)
        cursor = QTextCursor(document)
        cursor.insertText(f"Customer Name: {data['c_name']}\n")
        cursor.insertText(f"Customer Address: {data['c_addr']}\n")
        cursor.insertText(f"Date: {data['i_date']}\n")
        cursor.insertText(f"Total Due: {data['total_due']}\n")

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        central = QWidget()
        self.setCentralWidget(central)
        layout = QHBoxLayout(central)

        self.invoiceForm = InvoiceForm()
        layout.addWidget(self.invoiceForm)

        self.invoiceView = InvoiceView()
        layout.addWidget(self.invoiceView)
        # hide the widget right now...
        self.invoiceView.setVisible(False)

        self.invoiceForm.submitted.connect(self.showPreview)

    def showPreview(self, data):
        self.invoiceView.setVisible(True)
        self.invoiceView.build_invoice(data)

    def printpreviewDialog(self):
        printer = QPrinter(QPrinter.HighResolution)
        previewDialog = QPrintPreviewDialog(printer, self)
        previewDialog.paintRequested.connect(self.printPreview)
        previewDialog.exec_()

    def printPreview(self, printer):
        self.invoiceView.build_invoice.print_(printer)

def main():
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()

if __name__ == '__main__':
    main()

主要的问题是, self.printpreviewDialog是其成员的MainWindow ,而不是InvoiceForm ,所以不应将连接clicked信号从主窗口代替。

另请注意,您尝试使用self.invoiceView.build_invoice.print_() ,但这不起作用,因为您没有调用build_invoice ,即使您这样做了,该函数也不会返回任何内容。

您应该使用self.invoiceView.document()代替,但您必须确保之前已经构建了数据。

class InvoiceForm(QWidget):
    submitted = pyqtSignal(dict)
    def __init__(self):
        # ...
        submit = QPushButton('Create Invoice', clicked=self.on_submit)
        # make the button a member of the instance instead of a local variable, 
        # so that we can connect from the main window instance
        self.printButton = QPushButton('Print Invoice')
        self.layout().addRow(submit, self.printButton)

# ...

class MainWindow(QMainWindow):
    def __init__(self):
        # ...
        self.invoiceForm.printButton.clicked.connect(self.printpreviewDialog)
    # ...

    def printPreview(self, printer):
        self.invoiceView.document().print_(printer)

注意:永远不要使用内置函数和语句作为变量名,比如print

尝试一下:

import sys
from PyQt5.QtCore import pyqtSignal, QSize, QSizeF, QDate
from PyQt5.QtGui import QTextDocument, QTextCursor, QFont
from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
from PyQt5.QtWidgets import (QWidget, QFormLayout, QLineEdit, QPlainTextEdit, 
    QSpinBox, QDateEdit, QTableWidget, QHeaderView, QPushButton, QHBoxLayout, 
    QTextEdit, QApplication, QMainWindow)


font = QFont('Arial',16)


class InvoiceForm(QWidget):
    submitted = pyqtSignal(dict)
    
    def __init__(self, parent=None):                                        # + parent=None
        super().__init__(parent)                                            # + parent
        self.setLayout(QFormLayout())
        self.inputs = dict()
        self.inputs['Customer Name'] = QLineEdit()
        self.inputs['Customer Address'] = QPlainTextEdit()
        self.inputs['Invoice Date'] = QDateEdit(date=QDate.currentDate(), calendarPopup=True)
        self.inputs['Days until Due'] = QSpinBox()
        for label, widget in self.inputs.items():
            self.layout().addRow(label, widget)

        self.line_items = QTableWidget(rowCount=10, columnCount=3)
        self.line_items.setHorizontalHeaderLabels(['Job', 'Rate', 'Hours'])
        self.line_items.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.layout().addRow(self.line_items)
        for row in range(self.line_items.rowCount()):
            for col in range(self.line_items.columnCount()):
                if col > 0:
                    w = QSpinBox()
                    self.line_items.setCellWidget(row, col, w)

        submit = QPushButton('Create Invoice', clicked=self.on_submit)
        
# +     vvvvvv                                        vvvvvvvvvvvvv 
        _print = QPushButton('Print Invoice', clicked=self.window().printpreviewDialog)  # + _print, + self.window()
        self.layout().addRow(submit, _print)                                             # + _print

    def on_submit(self):
        data = {'c_name': self.inputs['Customer Name'].text(),
                'c_addr': self.inputs['Customer Address'].toPlainText(),
                'i_date': self.inputs['Invoice Date'].date().toString(),
                'i_due': self.inputs['Invoice Date'].date().addDays(self.inputs['Days until Due'].value()).toString(),
                'i_terms': '{} days'.format(self.inputs['Days until Due'].value()),
                'line_items': list()}

        for row in range(self.line_items.rowCount()):
            if not self.line_items.item(row, 0):
                continue
            job = self.line_items.item(row, 0).text()
            rate = self.line_items.cellWidget(row, 1).value()
            hours = self.line_items.cellWidget(row, 2).value()
            total = rate * hours
            row_data = [job, rate, hours, total]
            if any(row_data):
                data['line_items'].append(row_data)

        data['total_due'] = sum(x[3] for x in data['line_items'])
        self.submitted.emit(data)
        # remove everything else in this function below this point
# +
        return data                                                            # +++
        

class InvoiceView(QTextEdit):
    dpi = 72
    doc_width = 8.5 * dpi
    doc_height = 6 * dpi

    def __init__(self):
        super().__init__(readOnly=True)
        self.setFixedSize(QSize(self.doc_width, self.doc_height))

    def build_invoice(self, data):
        document = QTextDocument()
        self.setDocument(document)
        document.setPageSize(QSizeF(self.doc_width, self.doc_height))
        document.setDefaultFont(font)
        cursor = QTextCursor(document)
        cursor.insertText(f"Customer Name: {data['c_name']}\n")
        cursor.insertText(f"Customer Address: {data['c_addr']}\n")
        cursor.insertText(f"Date: {data['i_date']}\n")
        cursor.insertText(f"Total Due: {data['total_due']}\n")
# +        
        return document                                                         # +++
        

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        central = QWidget()
        self.setCentralWidget(central)
        layout = QHBoxLayout(central)
# +                                    vvvv
        self.invoiceForm = InvoiceForm(self)                                    # + self
        
        layout.addWidget(self.invoiceForm)
        self.invoiceView = InvoiceView()
        layout.addWidget(self.invoiceView)
        # hide the widget right now...
        self.invoiceView.setVisible(False)
        self.invoiceForm.submitted.connect(self.showPreview)

    def showPreview(self, data):
        self.invoiceView.setVisible(True)
        self.invoiceView.build_invoice(data)

# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    def printpreviewDialog(self):
        previewDialog = QPrintPreviewDialog()
        previewDialog.paintRequested.connect(self.printPreview)  
        previewDialog.exec_()

    def printPreview(self, printer):
#        self.invoiceView.build_invoice.print_(printer)        
        data = self.invoiceForm.on_submit()
        document = self.invoiceView.build_invoice(data)
        document.print_(printer)
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


def main():
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()

if __name__ == '__main__':
    main()

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM