개발/Python

[파이썬] non PyQt 클래스에서 신호를 방출하는 방법은 무엇입니까?

MinorMan 2021. 1. 11. 06:38
반응형

<질문>

twisted 및 PyQt를 사용하여 파이썬으로 응용 프로그램을 프로그래밍하고 있습니다. 내가 직면 한 문제는 꼬인 코드의 함수가 실행될 때 GUI에 줄을 인쇄해야한다는 것입니다. 신호를 방출하여 이것을 달성하려고합니다 (비 PyQt 클래스). 이것은 작동하지 않는 것 같습니다. 꼬인 이벤트 루프가 PyQt를 망치고 있는지 의심됩니다. closeEvent 신호가 프로그램에 의해 트랩되지 않기 때문입니다.

다음은 코드 조각입니다.

from PyQt4 import QtGui, QtCore
import sys
from twisted.internet.protocol import Factory, Protocol
from twisted.protocols import amp
import qt4reactor

class register_procedure(amp.Command):
    arguments = [('MAC',amp.String()),
                        ('IP',amp.String()),
                        ('Computer_Name',amp.String()),
                        ('OS',amp.String())
                        ]
    response = [('req_status', amp.String()),
         ('ALIGN_FUNCTION', amp.String()),
                         ('ALIGN_Confirmation', amp.Integer()),
                         ('Callback_offset',amp.Integer())
                        ]

class Ui_MainWindow(QtGui.QMainWindow):

    def __init__(self,reactor, parent=None):
        super(Ui_MainWindow,self).__init__(parent)
        self.reactor=reactor
        self.pf = Factory()
        self.pf.protocol = Protocol
        self.reactor.listenTCP(3610, self.pf) # listen on port 1234

        def setupUi(self,MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(903, 677)
        self.centralwidget = QtGui.QWidget(MainWindow)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
        self.centralwidget.setSizePolicy(sizePolicy)

        self.create_item()


        self.retranslateUi(MainWindow)
        self.connect(self, QtCore.SIGNAL('triggered()'), self.closeEvent)
        QtCore.QObject.connect(self,QtCore.SIGNAL('registered()'),self.registered)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.pushButton_4.setText(_translate("MainWindow", "Delete System ", None))
        self.pushButton.setText(_translate("MainWindow", "Add System", None))
        self.label_2.setText(_translate("MainWindow", "SYSTEM STATUS", None))
        self.label.setText(_translate("MainWindow", "Monitoring Output", None))


    def registered(self):# this function is not being triggered
        print "check" 
        self.textbrowser.append()

    def closeEvent(self, event):#neither is this being triggered
        print "asdf"
        self.rector.stop()
        MainWindow.close()
        event.accept()


class Protocol(amp.AMP):
    @register_procedure.responder
    def register_procedure(self,MAC,IP,Computer_Name,OS):
        self.bridge_conn=bridge()
        cursor_device.execute("""select * FROM devices where MAC = ?;""",[(MAC)])
        exists_val=cursor_device.fetchone()
        cursor_device.fetchone()
        print "register"
        if not exists_val== "":
            cursor_device.execute("""update devices set IP= ? , Computer_name= ? , OS = ?  where MAC= ?;""",[IP,Computer_Name,OS,MAC])
            QtCore.QObject.emit( QtCore.SIGNAL('registered')) # <--emits signal
            return {'req_status': "done" ,'ALIGN_FUNCTION':'none','ALIGN_Confirmation':0,'Callback_offset':call_offset(1)}
        else:
            cursor_device.execute("""INSERT INTO devices(Mac,Ip,Computer_name,Os) values (?,?,?,?);""",[MAC,IP,Computer_Name,OS])
            QtCore.QObject.emit( QtCore.SIGNAL('registered'))#<--emits signal
            return {'req_status': "done" ,'ALIGN_FUNCTION':'main_loop()','ALIGN_Confirmation':0,'Callback_offset':0}



if  __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    try:
        import qt4reactor
    except ImportError:
        from twisted.internet import qt4reactor
    qt4reactor.install()

    from twisted.internet import reactor
    MainWindow = QtGui.QMainWindow() # <-- Instantiate QMainWindow object.
    ui = Ui_MainWindow(reactor)
    ui.setupUi(MainWindow)
    MainWindow.show()
    reactor.run()

<답변1>

이것은 QGraphicsItems에서 신호를 보내기 위해 하나의 코드에서 사용하는 것입니다 (QObject에서 파생되지 않고 기본적으로 신호를 보내고받을 수 없기 때문입니다). 그것은 기본적으로 Radio-의 대답의 단순화 된 버전입니다.

from PyQt4 import QtGui as QG
from PyQt4 import QtCore as QC

class SenderObject(QC.QObject):
    something_happened = QC.pyqtSignal()

SenderObject방출하는 데 필요한 모든 신호를 넣을 수있는 QObject에서 파생 된 작은 클래스입니다. 이 경우 하나만 정의됩니다.

class SnapROIItem(QG.QGraphicsRectItem):
    def __init__(self, parent = None):
        super(SnapROIItem, self).__init__(parent)
        self.sender = SenderObject()
    def do_something_and_emit(self):
        ...
        self.sender.something_happened.emit()

비 QObject 클래스에서SenderObject가지고있다sender변하기 쉬운. 비 QObject 클래스가 사용되는 곳이면 어디에서나sender필요한 모든 것에.

class ROIManager(QC.QObject):
    def add_snaproi(self, snaproi):
        snaproi.sender.something_happened.connect(...)

최신 정보

전체 코드는 다음과 같으며 "뭔가 발생했습니다 ..."를 출력해야합니다.

from PyQt4 import QtGui as QG
from PyQt4 import QtCore as QC

class SenderObject(QC.QObject):
    something_happened = QC.pyqtSignal()

class SnapROIItem(QG.QGraphicsItem):
    def __init__(self, parent = None):
        super(SnapROIItem, self).__init__(parent)
        self.sender = SenderObject()
    def do_something_and_emit(self):
        self.sender.something_happened.emit()

class ROIManager(QC.QObject):
    def __init__(self, parent=None):
        super(ROIManager,self).__init__(parent)
    def add_snaproi(self, snaproi):
        snaproi.sender.something_happened.connect(self.new_roi)
    def new_roi(self):
        print 'Something happened in ROI!'

if __name__=="__main__":)
    roimanager = ROIManager()
    snaproi = SnapROIItem()
    roimanager.add_snaproi(snaproi)
    snaproi.do_something_and_emit()

업데이트 2

대신에

QtCore.QObject.connect(self,QtCore.SIGNAL('registered()'),self.registered) 

다음이 있어야합니다.

protocol.sender.registered.connect(self.registered)

즉,protocol인스턴스self.pf(덧붙여서 수입합니까Protocol그런 다음 직접 정의 하시겠습니까?)

대신 프로토콜 클래스에서

QtCore.QObject.emit( QtCore.SIGNAL('registered')

먼저 프로토콜에서 SenderObject를 인스턴스화해야합니다.

class Protocol(amp.AMP):
    def __init__( self, *args, **kw ):
       super(Protocol, self).__init__(*args, **kw)
       self.sender = SenderObject()

그리고 나서register_procedure신호를 보내다sender: self.sender.registered.emit ()

이 모든 것이 작동하려면 SenderObject를 다음과 같이 정의해야합니다.

class SenderObject(QC.QObject):
    registered = QC.pyqtSignal()

<답변2>

이것은 오래된 게시물이지만 도움이되었습니다. 여기 내 버전입니다. QObject가 아닌 하나의 항목은 두 개의 다른 비 QObject가 해당 메서드를 실행하도록 신호를 보냅니다.

from PyQt4 import QtGui, QtCore

class Signal(object):
    class Emitter(QtCore.QObject):
        registered = QtCore.pyqtSignal()
        def __init__(self):
            super(Signal.Emitter, self).__init__()

    def __init__(self):
        self.emitter = Signal.Emitter()

    def register(self):
        self.emitter.registered.emit()

    def connect(self, signal, slot):
        signal.emitter.registered.connect(slot)

class item(object):
    def __init__(self, name):
        self.name = name
        self.signal = Signal()

    def something(self):
        print self.name, ' says something'

>>> itemA = item('a')
>>> itemB = item('b')
>>> itemC = item('c')
>>> itemA.signal.connect(itemA.signal, itemB.something)
>>> itemA.signal.connect(itemA.signal, itemC.something)
>>> itemA.signal.register()

b  says something
c  says something

<답변3>

두 가지 기본적인 문제는 다음과 같습니다.

1) 무언가 신호의 발신자와 수신자를 알아야합니다.

Qt에서 각각 '클릭 된'신호가있는 여러 버튼이있을 수있는 더 빈번한 경우를 고려하십시오. 슬롯은 어떤 버튼이 클릭되었는지 알아야하므로 일반적인 신호를 포착하는 것은 의미가 없습니다.

2) 신호는 QObject에서 시작되어야합니다.

하지만 정식 구현이 무엇인지 잘 모르겠습니다. 다음은 이전 게시물 중 하나에있는 Bridge 개념과 Protocol 내부의 특수 Emitter 클래스를 사용하는 한 가지 방법입니다. 이 코드를 실행하면 protocol.register ()가 호출 될 때 'Working it'이 출력됩니다.

from PyQt4 import QtGui, QtCore
import sys

class Ui_MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(Ui_MainWindow, self).__init__()

    def work(self):
        print "Working it"

class Protocol(object):
    class Emitter(QtCore.QObject):
        registered = QtCore.pyqtSignal()
        def __init__(self):
            super(Protocol.Emitter, self).__init__()

    def __init__(self):
        self.emitter = Protocol.Emitter()

    def register(self):
        self.emitter.registered.emit()

class Bridge(QtCore.QObject):
    def __init__(self, gui, protocol):
        super(Bridge, self).__init__()
        self.gui = gui
        self.protocol = protocol

    def bridge(self):
        self.protocol.emitter.registered.connect(self.gui.work)

app = QtGui.QApplication(sys.argv)
gui = Ui_MainWindow()
protocol = Protocol()
bridge = Bridge(gui, protocol)
bridge.bridge()
#protocol.register() #uncomment to see 'Working it' printed to the console
반응형