-->

Run Pyqt GUI main app as a separate, non-blocking

2020-06-22 07:26发布

问题:

I'm looking for the possibility of running a pyqt GUI from the python or ipython console.

Basically the main idea is to use the Pyqt GUI like one would use a matplotlib plot or image, where you pass arguments to a GUI from the console to look at data, continue to do stuff in the console, maybe open another window, close the first one, do more stuff in the console and so on.

I've implemented this solution using threading (Run pyQT GUI main app in seperate Thread), and as predicted in the comments it crashes the python console after a few cycles.

Here is the pilot code:

import sys
from PyQt5 import QtWidgets, QtGui, QtCore

class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        # call super class constructor
        super(MainWindow, self).__init__()
        # build the objects one by one
        layout = QtWidgets.QVBoxLayout(self)
        self.pb_load = QtWidgets.QPushButton('Load')
        self.pb_clear= QtWidgets.QPushButton('Clear')
        self.edit = QtWidgets.QTextEdit()
        layout.addWidget(self.edit)
        layout.addWidget(self.pb_load)
        layout.addWidget(self.pb_clear)
        # connect the callbacks to the push-buttons
        self.pb_load.clicked.connect(self.callback_pb_load)
        self.pb_clear.clicked.connect(self.callback_pb_clear)

    def callback_pb_load(self):
        self.edit.append('hello world')
    def callback_pb_clear(self):
        self.edit.clear()

def mythread():
    app = QtWidgets.QApplication(sys.argv)
    win = MainWindow()
    win.show()
    app.exec_()

def show():
    import threading
    t = threading.Thread(target = mythread)
    t.daemon = True
    t.start()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    win = MainWindow()
    win.show()
    sys.exit(app.exec_())

Running the file would run the GUI normally. Importing it and then run show() would attempt to run the GUI from the console in a non-blocking manner.

Is there a way to spawn a thread or process embedding the PyQt app that would behave like a matplotlib window would ?

回答1:

Threading is irrelevant here. PyQt is already designed to work in a normal python interactive session, so there is no need to do anything special to make it work.

I would suggest you remove the mythread and show functions and replace them with something like this:

if QtWidgets.QApplication.instance() is None:
    app = QtWidgets.QApplication(sys.argv)

Then you can use your gui module like this:

>>> from mygui import MainWindow
>>> win = MainWindow()
>>> win.show()
>>> win.callback_pb_load()

Do not ever call app.exec_(). PyQt will take care of the event-loop itself.