Python Forum
Auto populate dictionary with names/values of QT widgets
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Auto populate dictionary with names/values of QT widgets
#1
Hi all,

I am trying to build a GUI in PyQt5 (Python 3.9) with a bunch of QTextEdits that the user will type into. From there, I am using jinja2 to populate word.docx templates. If you don't use jinja, in a nutshell, it searches a word.docx for curly braces containing variable names such as {{myVar}} and replaces them according to a predefined dictionary where the keys are matched with {{variables}} and then the {{variables}} are replaced with the values.

If my GUI has hundreds of QTextEdits, which frequently changed as the app is updated, I have to keep hard coding the dictionary. Instead, I'd like to automate this process of creating a dictionary. To do this, I deliberately name each text edit as it will appear in the docx template. For example, I have a text edit named 'address' and my word doc has a jinja tag {{address}}. I thought I could loop through all QT widgets and, if the widget type == QTextEdit, then widget_name = the name of the widget ('address') and widget_val = the value the user entered into that widget. My example below has five textedit widets (name, address, colour, phone, textedit (because I forgot to give the last one a unique name)).

I keep getting errors because the class of widgets is not iterable.

I have two modules: main.py is where I'm coding the logic, and mainWindow.py is where my widgets live. Here are both. Any suggestions would be greatly appreciated.

main.py:
from mainWindow import *
import sys
from docxtpl import DocxTemplate

import os


class GUI(Ui_MainWindow):

    def __init__(self, window):
        self.setupUi(window)
        self.pushButton.clicked.connect(self.generate)

    def generate(self):
        doc = DocxTemplate("firstdoc.docx" )
        #-------INSERT FOR LOOP HERE TO POPULATE THE 'context{}' DICTIONARY BELOW--------
        context = {}
        doc.render(context)
        doc.save("gendoc.docx")
        os.startfile(os.getcwd() + "\\gendoc.docx")


app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = GUI(MainWindow)
MainWindow.show()
app.exec_()
And the GUI module:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(449, 661)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(220, 480, 151, 61))
        self.pushButton.setObjectName("pushButton")
        self.name = QtWidgets.QTextEdit(self.centralwidget)
        self.name.setGeometry(QtCore.QRect(60, 40, 271, 121))
        self.name.setObjectName("name")
        self.address = QtWidgets.QTextEdit(self.centralwidget)
        self.address.setGeometry(QtCore.QRect(60, 190, 271, 81))
        self.address.setObjectName("address")
        self.colour = QtWidgets.QTextEdit(self.centralwidget)
        self.colour.setGeometry(QtCore.QRect(60, 290, 271, 91))
        self.colour.setObjectName("colour")
        self.phone = QtWidgets.QTextEdit(self.centralwidget)
        self.phone.setGeometry(QtCore.QRect(60, 390, 261, 20))
        self.phone.setObjectName("phone")
        self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
        self.textEdit.setGeometry(QtCore.QRect(20, 480, 171, 61))
        self.textEdit.setObjectName("textEdit")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 449, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "Generate Document"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
buran write Mar-23-2021, 05:26 AM:
Please, use proper tags when post code, traceback, output, etc. This time I have added tags for you.
See BBcode help for more info.
Reply
#2
I would do things in reverse. Use the dictionary to automatically build the GUI. Or maybe a list to build them both? I would make a list of fields automatically extracted from the word documents and use that to automatically build the dictionary and GUI program

Widgets are not iterable, but you can ask for the child widgets of a widget, and that gives you an iterator. I posted this a while back as a way to clear all the line edit widgets in a form.
for w in form.findChildren(QLineEdit):
    w.clear()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [PyQt] populate a QListWidget devilonline 1 1,574 Apr-10-2023, 02:52 AM
Last Post: deanhystad
  [PyQt] [Solved]Populate ComboBox with for loop? Extra 3 2,137 Jul-31-2022, 09:01 PM
Last Post: Extra
  Problems getting tk Combobox contents to populate properly dford 4 3,797 Jan-08-2022, 02:39 PM
Last Post: dford
  [PyQt] How to populate a treeview on a GUI with a dictionary mart79 1 8,236 Aug-05-2019, 01:30 PM
Last Post: Denni
  populate list with images and be able to select them ricardons 0 2,127 Jan-11-2019, 03:45 PM
Last Post: ricardons
  Hardest time getting DataFrame to populate Tree Widget WuchaDoin 4 7,354 Oct-15-2018, 08:29 PM
Last Post: nilamo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020