how to emit signal from a non PyQt class?

pyqt, pyqt4, python, python-2.7, twisted

Solution

This is what I use in my one code for sending signals from QGraphicsItems (because they are not derived from QObject and cannot send/receive signals by default). It's basically a simplified version of Radio-'s answer.

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

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

`SenderObject` is a tiny class derived from QObject where you can put all the signals you need to emit. In this case only one is defined.

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()

In the non-QObject class you add a `SenderObject` as a `sender` variable. Anywhere where the non-QObject class is used you can connect the signal from the `sender` to anything you need.

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

UPDATE

The full code is this and should print out "Something happened...":

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()

UPDATE 2

Instead of

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

you should have:

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

This means you also need to get hold of the `protocol` instance in `self.pf` (by the way, do you import `Protocol` and then define it yourself as well?)

In the Protocol class instead of

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

you need to, first, instantiate a SenderObject in the Protocol.

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

and then, in `register_procedure` emit the signal through `sender`: self.sender.registered.emit()

For all of this to work you'll have to have defined SenderObject as:

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

Problem

i'm programming an application in python using twisted and PyQt . the problem that i'm facing is that when a function in my twisted code is executed i have to print a line in the GUI, i'm trying to achieve this by emiting a signal (Non PyQt class). This does not seem to work, i have a doubt that the twisted event loop is screwing things for PyQt. Because the closeEvent signal is not being trapped by the program. Here's the code snippet: ``` 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() ```

Original source