I've been building a fairly simple program using PyQt5 for the GUI for the past few days and I have the following problem which I can't seem to find a solution for.
Here's an oversimplified version of my code (kept the absolute basics to keep things short):
def run_blueprint(file):
# doing stuff to the file and returning the path to the output file
return full_path
class Window(QMainWindow, Ui_MainWindow):
# some variables here
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.connectSignalsSlots()
def connectSignalsSlots(self):
self.pushButton.clicked.connect(self.processFiles)
def processFiles(self):
self.toggleElements()
for i, file in enumerate(self.selected_files_directories):
temp_full_path = run_blueprint(file)
self.listWidget_3.insertItem(i, temp_full_path)
self.toggleElements()
def toggleElements(self):
self.pushButton_2.setEnabled(not self.pushButton_2.isEnabled())
self.listWidget.setEnabled(not self.listWidget.isEnabled())
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())
Let's assume that I have selected an item from the listWidget
and also have a list of file paths stored in the selected_files_directories[]
variable.
If I run the code as is, when it's time for processFiles(self)
to run I get some weird behavior. For some reason the for loop is ran first, then the first toggleElements()
and after that the second toggleElements()
. This results in the two elements that I want to temporarily disable until the for loop is over staying enabled the whole time.
However if I don't call the run_blueprint(file)
method at all, but instead run any other code inside the for loop or even completely discard the loop, those two elements are disabled first, then the rest of the code runs and finally they are enabled again.
I believe the problem has something to do with me calling a static method outside the class. Do you have any ideas on how to solve this issue? Thanks in advance!
Edit: Below is the simplified version of the run_blueprint()
function.
The basic functionality of this program is as follows: I select a template file (.docx)
and input file(s) (.pdf)
. Then using the docxtpl
and pdfplumber
libraries, for each of the selected input files I get specific text pieces from them and place them inside the template document and save that as a .docx file.
In the following code assume that template_path
and bp_path
show the path to the template file and blueprint file respectively.
def run_blueprint(file):
doc = DocxTemplate(template_path) # docxtpl method
global lns
lns = export_data(file) # function I made that uses pdfplumber to get all the text from a pdf file
global context
context = {}
with open(bp_path, 'r', encoding='utf8') as f:
blueprint = f.read() # blueprint contains python code that populates the context variable. I do it this way to easily change between blueprints
exec(blueprint, globals(), locals()) # I know it's not a good practice to use exec but it's intended for personal use
doc.render(context) # docxtpl method
output_path = "D:\\Desktop" # could be any path
doc.save(output_path) # docxtpl method
return output_path
The blueprint code usually contains API calls that take a few milliseconds to send a response. Apart from that it's mostly regex
used to locate the text pieces I'm looking for.