Разница между PyQt и Qt при обработке определяемого пользователем сигнала/слота

Что ж, я знаком с Qt, но при использовании PyQt синтаксис signal/slot меня сильно смущал. При использовании C++/Qt компилятор даст вам подсказку, где вы ошибаетесь в отношении сигнала/слота, но конфигурация PyQt по умолчанию не дает подсказки об ошибке. Существуют ли способы или такие, как режим триггера отладки, чтобы позволить PyQt отображать больше информации? Код выглядит следующим образом:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import time

class workThread(QThread):

    def __init__(self,parent = None):
        super(workThread,self).__init__(parent)
        self.mWorkDoneSignal = pyqtSignal() ## some people say this should be defined as clas member, however, I defined it as class member and still fails.

    def run(self):
        print "workThread start"
        time.sleep(1)
        print "workThread stop"
        print self.emit(SIGNAL("mWorkDoneSignal"))

class MainWidget(QWidget):
    def __init__(self , parent = None):
        super(MainWidget,self).__init__(parent)

    @pyqtSlot()
    def display(self):
        print "dispaly"

if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    c = workThread()
    d = MainWidget()
    ##In Qt, when using QObject::connect or such things, the return value will show the 
    ## signal/slot binding is success or failed
    print QObject.connect(c,SIGNAL('mWorkDoneSignal()'),d,SLOT('display()'))
    c.start()
    d.show()
    app.exec_()

В C++ возвращаемое значение QObject::connect покажет успешность привязки сигнала/слота. В PyQt возвращаемое значение равно True, но слот не активируется. Мой вопрос: 1) Должен ли сигнал быть членом класса или членом экземпляра? 2) Если возвращаемое значение QObject.connect не может дать намек на успешность привязки или нет, есть ли другие способы определить это? Я хочу связать сигнал/слот вне отправителя сигнала и получателя слота, поэтому я предпочитаю использовать способы QObject.connect. Но как я могу написать это правильно, я пробовал следующие способы, оба не работают.

 QObject.connect(c,SIGNAL('mWorkDoneSignal'),d,SLOT('display'))
 QObject.connect(c,SIGNAL('mWorkDoneSignal()'),d,SLOT('display()'))

person python    schedule 21.07.2013    source источник


Ответы (1)


Во-первых, вы действительно должны использовать сигналы нового стиля с pyqt. Фактически, QObject.connect и QObject.emit больше не будет в PyQt5.

def __init__(self,parent = None):
    super(workThread,self).__init__(parent)
    self.mWorkDoneSignal = pyqtSignal()

Это создает несвязанный сигнал и присваивает его переменной экземпляра mWorkDoneSignal, которая на самом деле не имеет эффекта. Если вы хотите создать сигнал, вам действительно нужно объявить его в классе.

Итак, если вы действительно не создали здесь сигнал, то почему этот вызов удался:

QObject.connect(c,SIGNAL('mWorkDoneSignal()'),d,SLOT('display()'))

Ответ заключается в обработке сигналов старого стиля от PyQt4:

Акт выдачи сигнала PyQt4 неявно определяет его.

По этой причине, когда вы подключаете сигнал к слоту, проверяется только существование слота. Сам сигнал на самом деле не обязательно должен существовать в этот момент, поэтому вызов всегда будет успешным, если слот не существует.

Я пробовал следующие способы, оба не работают.

QObject.connect(c,SIGNAL('mWorkDoneSignal'),d,SLOT('display'))
QObject.connect(c,SIGNAL('mWorkDoneSignal()'),d,SLOT('display()'))

Первый не удается, потому что display (без скобок) не является допустимым слотом.
Второй успешно. Причина, по которой это не работает, заключается в том, что вы испускаете mWorkDoneSignal, но на самом деле вам нужно испустить:

self.emit(SIGNAL("mWorkDoneSignal()"))

Используя сигналы нового стиля, невозможно испортить такие вещи:

from utils import sigint
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import time

class workThread(QThread):

    mWorkDoneSignal = pyqtSignal()

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

    def run(self):
        print "workThread start"
        time.sleep(1)
        print "workThread stop"
        self.mWorkDoneSignal.emit()

class MainWidget(QWidget):
    def __init__(self , parent = None):
        super(MainWidget,self).__init__(parent)

    @pyqtSlot()
    def display(self):
        print "dispaly"

if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    c = workThread()
    d = MainWidget()
    c.mWorkDoneSignal.connect(d.display)
    c.start()
    d.show()
    app.exec_()
person mata    schedule 21.07.2013