0

In form.py I have a Form class, which allows the user input various data. The idea is to use this data to update the values in a dictionary in document.py, which is then used to populate a pdf file. The "write custom pdf" method which creates said pdf is invoked via a button in my main logic file. However, the method get_input_1 below (imported from form to doc) is not able to update the dictionary at all. I have tried various options, including the solution described here, but none of them seem to work. Any help would be highly appreciated!

gui.py

from PyQt5 import QtWidgets, QtCore

class UiMainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("File Manager")
        MainWindow.resize(1120, 750)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")

        self.button1 = QtWidgets.QPushButton(self.centralwidget)
        self.button1.setGeometry(QtCore.QRect(10, 80, 121, 41))

        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("File Manager", "File Manager"))
        self.button1.setText(_translate("MainWindow", "+ New File"))

main.py

from PyQt5 import QtWidgets, QtCore
from gui import UiMainWindow
from document import Doc
import sys

class Logic(QtWidgets.QMainWindow, UiMainWindow, Doc):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        self.button1.clicked.connect(self.write_custom_pdf)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    logic = Logic()
    logic.show()
    sys.exit(app.exec_())

form.py

from PyQt5.QtWidgets import *

class Form(QDialog):
    """Show a pop-up form for the user to input file data."""
    NumGridRows = 3
    NumButtons = 4

    def __init__(self, parent=None):
        super().__init__(parent)
        self.input_1 = QLineEdit(self)

        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok |
                                       QDialogButtonBox.Cancel, self)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)

        self.formbox = QGroupBox("Please provide data below: ")
        layout = QFormLayout()
        layout.addRow(QLabel("Business name: "), self.input_1)
        layout.addRow(QLabel("Customer name: "), self.input_2)
        self.formbox.setLayout(layout) 

        main_layout = QVBoxLayout()
        main_layout.addWidget(self.formbox)
        main_layout.addWidget(self.button_box)
        self.setLayout(main_layout)

    def get_input_1(self):
        return self.input_1.text()

document.py

from PyQt5.QtWidgets import *
from form import Form
import os

class Doc(QInputDialog):
    """Create an doc and populate it based on user input."""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.work_dir = os.path.join("C:\\", "Document Manager", "Work environment")
        self.dialog = Form()
        self.template_path = 'invoice_template.pdf'
        input_1 = self.dialog.get_input_1()
        self.data_dict = {
            'business_name_1': f"{input_1}",
            'customer_name': 'company.io'}

        new_pdf = self.process_pdf(self.template_path)
        self.dialog.accepted.connect(lambda: self.produce_invoice(self.output_path, new_pdf))

    def write_custom_pdf(self):
        """Create an invoice based on a pdf template."""
        user_input = QInputDialog()
        active = True
        while active:
            text, ok = user_input.getText(self, "Invoice name", "Please enter a name")
            if ok and text != '':
                self.name = text
                self.output_path = f"{self.work_dir}" + "\\" + f"{self.name}" + ".pdf"
                if not os.path.exists(self.output_path):
                    self.open_dialog()
                    active = False
                else:
                    self.show_popup()
            else:
                active = False

    def open_dialog(self):
        self.dialog.exec_()

    def process_pdf(self, template_path):
        template_pdf = pdfrw.PdfReader(template_path)
        template_pdf.Root.AcroForm.update(
            pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true')))
        annotations = template_pdf.pages[0][ANNOT_KEY]
        for annotation in annotations:
            if annotation[SUBTYPE_KEY] == WIDGET_SUBTYPE_KEY:
                if annotation[ANNOT_FIELD_KEY]:
                    key = annotation[ANNOT_FIELD_KEY][1:-1]
                    if key in self.data_dict.keys():
                        annotation.update(pdfrw.PdfDict(
                            V=f"{self.data_dict[key]}"))
        return template_pdf

    def produce_invoice(self, output_path, new_pdf):
        new_invoice = pdfrw.PdfWriter().write(output_path, new_pdf)
        return new_invoice

1 Answers1

0

It doesn't work because the dictionary is only updated in the __init__.
The get_input_1() function is not some sort of "dynamic" thing, it just immediately returns the current value of the text field, which is empty when the form is created.

To update the dictionary, call the function after the dialog's exec(), then process the pdf.

    def open_dialog(self):
        if self.dialog.exec_():
            self.data_dict['business_name_1'] = self.dialog.get_input_1()
            newpdf = self.process_pdf(self.template_path)
            self.produce_invoice(self.output_path, newpdf)
musicamante
  • 41,230
  • 6
  • 33
  • 58
  • It worked :) Thank you for the explanation as well, I had a feeling it was something to do with the initialization, but could not figure it out. Absolute legend, much appreciated! – Dimovik Mar 26 '20 at 14:12