Signals and Slots PyQt clarification

五迷三道 提交于 2019-12-08 11:58:22

问题


I have noticed that there are a lot of users, myself included, who don't quite grasp the concept of signals and slots in Qt. I was hoping to get some clarification on the following:

#I have a function that runs as soon as the GUI is built, this takes the information from     
#a list and puts it into a string which is then uploaded to a texbox. At the bottom of this 
#loop, I want it to call a function in the parent thread via signals and slots, as 
#recommended by other users.
class MainWindow(QtGui.QMainWindow):
    #all the code needed to build the GUI
    thread_mythread = threading.Thread(target = self.updateText, args = ())
    thread_mythread.start()

    def clearText(self):
        self.TextEdit.clear()

    def updateText(self):
        self.trigger.connect(self.clearText)

        while True:
            self.trigger.emit()
            NewString = list.pop(0)
            #I think I may have to use append, as setText() is not safe outside of the parent thread
            self.TextEdit.append(NewString)

Although probably terribly incorrect, I attempt to use signals. Is this the proper way to do it? I also get an error that says that the Main Window object has no attribute "trigger",why is this?

thank you.


回答1:


The reason you get that error is exactly the reason described by the error message - the signal trigger has not been defined anywhere in your class. You need to define it before you can emit it.

Signals and slots are used to communicate between different objects. In your example you are trying to do everything from within your MainWindow class and there is no interaction with other objects. You also only need to make the call to connect() once. You would typically call this either in the class constructor or from your main function after instantiating the objects you want to connect together.

Take a look at http://pyqt.sourceforge.net/Docs/PyQt4/new_style_signals_slots.html for some examples of how to use signals and slots properly in PyQt.

For threading, use QThread rather than threading.Thread as it is better integrated with the Qt framework. This post shows some simple examples of how to use QThread in PyQt. The second method (using moveToThread()) is considered to be the most correct way to create new threads.

The basic idea for your kind of problem is:

  • handle GUI operations from the main thread
  • handle blocking operations (in your case the while loop) in a separate thread
  • emit signals from the worker thread to call functions (slots) in the main thread and vice versa

Also note that:

  • You cannot call any methods of QWidget its descendents from a secondary thread
  • Signals can also send data if you need to pass it between threads



回答2:


To add to @user3419537 good answer. A very quick threading example:

from PyQt4.QtCore import QObject, pyqtSlot, pyqtSignal, QThread, \
    Q_ARG, Qt, QMetaObject

class MyWorker(QObject):
    # define signal
    clear = pyqtSignal()
    update_text_signal = pyqtSignal(str)  # passes a string back
    finished = pyqtSignal()

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


    # Add functions etc.
    @pyqtSlot(list)
    def update_text(self, string_list):
        #Intensive operation
        self.clear.emit()  # moved outside of while
        while(True):
            #This is infinite loop so thread runs forever
            new_string = self.string_list.pop(0)
            self.update_text_signal.emit(new_string)  # Fixed this line

        #Finished
        self.finished.emit()

Then in your MainWindow class

self.my_thread = QThread()
self.handler = MyWorker()
self.handler.moveToThread(self.my_thread)
self.handler.clear.connect(self.clearText)
self.handler.update_text_signal.connect(self.update_line_edit)
self.handler.finished.connect(self.my_thread.quit)
# Start Thread
self.my_thread.start()

@pyqtSlot(str)
def update_line_edit(self, text):
    self.TextEdit.append(text)

QMetaObject.invokeMethod(self.handler, 'update_text',
                         Qt.QueuedConnection,
                         Q_ARG(list, string_list))

You will need to call self.my_thread.quit() before your application closes to stop the thread and avoid the error: QThread: Destroyed while thread is still running

Please read docs for QMetaObject.invokeMethod.



来源:https://stackoverflow.com/questions/24433872/signals-and-slots-pyqt-clarification

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!