4
\$\begingroup\$

Based on a question I asked on SO, I have come up with the following solution. As I am very new to Python Qt, I would like a review rather than just add it as an answer in SO.

The code runs a script in another thread. That script needs to open a file dialog to get another file from the user. To do that, I pass a signal to the script which is connected to run_cb() in the GUI thread. run_cb() will run any function given to it (callback).

The script emits this signal and passes the callback function it wants to run on the GUI thread. Inside the callback (getFileName_cb()), I fire another signal that returns the result of the callback to the script thread.

In this way, the script doesn't need to know anything about the GUI (which is one of my requirements). It just needs to know that the signal passed to it can be used to run a function on the GUI thread.

Whilst it works, I am not sure if it the correct way to do this?

Edit: I recognised that in my first implementation, got_file_and_continue() was now running in the GUI thread. So I've now changed it to wait for the callback to be done and continue in the original script thread. Although, I don't like the while loop - would appreciate any comments on this too.

import threading
import time
import sys
from PySide2.QtWidgets import QWidget, QVBoxLayout, QTextEdit, QPushButton, QApplication, QFileDialog
from PySide2 import QtCore
class script_runner(QtCore.QObject):
 get_file_cb_signal = QtCore.Signal(object)
 def __init__(self) -> None:
 super().__init__()
 self.get_file_cb_signal.connect(self.got_file_and_continue)
 self.cb_done = None
 self.filename = None
 
 def getFileName_cb(self):
 response = QFileDialog.getOpenFileName(
 parent=None
 )
 self.get_file_cb_signal.emit(response[0])
 return response[0]
 @QtCore.Slot()
 def got_file_and_continue(self, filepth):
 print("Got_f_and_c:", threading.get_ident())
 print("Finally", filepth)
 self.cb_done = True
 self.filename = filepth
 def run_script_in_bg(self, script_pth, cb_signal):
 # Assume this opens script_pth 
 # and that script needs to get user to choose another file
 print(f"{script_pth} is running. Now it needs to open file dialog and get result")
 self.cb_done = False
 print("BG_task:", threading.get_ident())
 cb_signal.emit(self.getFileName_cb)
 while not self.cb_done:
 time.sleep(0.1)
 print("Moving on with:", self.filename, threading.get_ident())
class TextEditDemo(QWidget):
 run_cb_signal = QtCore.Signal(object)
 def __init__(self, parent=None):
 super().__init__(parent)
 self.setWindowTitle("TEST")
 self.resize(600,540)
 self.textEdit = QTextEdit()
 self.btnPress1 = QPushButton("Run")
 layout = QVBoxLayout()
 layout.addWidget(self.textEdit)
 layout.addWidget(self.btnPress1)
 self.setLayout(layout)
 self.btnPress1.clicked.connect(self.btnPress1_Clicked)
 self.run_cb_signal.connect(self.run_cb)
 self.sr = script_runner()
 def btnPress1_Clicked(self):
 script_pth = self.getFileName()
 print("Main:", threading.get_ident())
 if script_pth:
 print('number of current threads is ', threading.active_count())
 threading.Thread(target=self.sr.run_script_in_bg, args=(script_pth, self.run_cb_signal, )).start() 
 @QtCore.Slot()
 def run_cb(self, cb):
 print("Run cb", threading.get_ident())
 try:
 resp = cb()
 self.textEdit.append("Script using: " + resp)
 except Exception as e:
 print(e)
 def getFileName(self):
 response = QFileDialog.getOpenFileName(
 parent=None
 )
 self.textEdit.append("Calling script: " + response[0])
 return response[0]
def main():
 app = QApplication(sys.argv)
 win = TextEditDemo()
 win.show()
 sys.exit(app.exec_())
if __name__ == "__main__":
 main()
asked Mar 15, 2022 at 18:42
\$\endgroup\$

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.