[英]how to emit signal from a non PyQt class?
i'm programming an application in python using twisted and PyQt .我正在使用 Twisted 和 PyQt 在 python 中编写应用程序。 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).
我面临的问题是,当我扭曲代码中的一个函数被执行时,我必须在 GUI 中打印一行,我试图通过发出一个信号(非 PyQt 类)来实现这一点。 This does not seem to work, i have a doubt that the twisted event loop is screwing things for PyQt.
这似乎不起作用,我怀疑扭曲的事件循环正在为 PyQt 搞砸事情。 Because the closeEvent signal is not being trapped by the program.
因为 closeEvent 信号没有被程序捕获。
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()
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). 这是我在我的一个代码中用于从QGraphicsItems发送信号的原因(因为它们不是从QObject派生的,并且默认情况下不能发送/接收信号)。 It's basically a simplified version of Radio-'s answer.
它基本上是Radio-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. SenderObject
是一个从QObject派生的小类,您可以在其中放置所需的所有信号。 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. 在非QObject类中,您将
SenderObject
添加为sender
变量。 Anywhere where the non-QObject class is used you can connect the signal from the sender
to anything you need. 在使用非QObject类的任何地方,您都可以将
sender
的信号连接到您需要的任何信号。
class ROIManager(QC.QObject):
def add_snaproi(self, snaproi):
snaproi.sender.something_happened.connect(...)
UPDATE 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 更新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?) 这意味着您还需要在
self.pf
获取protocol
实例(顺便说一句,您是否导入Protocol
,然后自己定义它?)
In the Protocol class instead of 在Protocol类而不是
QtCore.QObject.emit( QtCore.SIGNAL('registered')
you need to, first, instantiate a SenderObject in the Protocol. 首先,您需要在协议中实例化SenderObject。
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() 然后,在
register_procedure
通过sender
发出信号:self.sender.registered.emit()
For all of this to work you'll have to have defined SenderObject as: 要使所有这些工作,您必须将SenderObject定义为:
class SenderObject(QC.QObject):
registered = QC.pyqtSignal()
This is an old post, but it helped me. 这是一个老帖子,但它帮了我。 Here is my version.
这是我的版本。 One item that is not a QObject signaling two other non QObject's to run their methods.
一个不是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
The two basic problems are that: 两个基本问题是:
1) Something has to know the sender and receiver of the signals 1)必须知道信号的发送者和接收者
Consider a more frequent case in Qt where you may have multiple buttons, each with a 'clicked' signal. 考虑Qt中更频繁的情况,您可能有多个按钮,每个按钮都有一个“点击”信号。 Slots need to know which button was clicked, so catching a generic signal does not make much sense.
插槽需要知道单击了哪个按钮,因此捕获通用信号没有多大意义。
and 2) The signals have to originate from a QObject. 2)信号必须来自QObject。
Having said that, I'm not sure what the canonical implementation is. 话虽如此,我不确定规范实现是什么。 Here is one way to do it, using the idea of a Bridge that you had in one of your earlier posts, and a special Emitter class inside of Protocol.
这是一种方法,使用您在之前的帖子中拥有的Bridge的概念,以及Protocol内部的特殊Emitter类。 Running this code will simply print 'Working it' when protocol.register() is called.
运行此代码只会在调用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
I improved the solution of @Ryan Trowbridge a bit to deal with a generic type.我改进了@Ryan Trowbridge 的解决方案来处理泛型类型。 I hoped to use
Generic[T]
but turned out too complicated.我希望使用
Generic[T]
但结果太复杂了。
class GenSignal:
def __init__(self,typ):
Emitter = type('Emitter', (QtCore.QObject,), {'signal': Signal(typ)})
self.emitter = Emitter()
def emit(self,*args,**kw):
self.emitter.signal.emit(*args,**kw)
def connect(self, slot):
self.emitter.signal.connect(slot)
To use, x=GenSignal(int)
and continue as usual.要使用,
x=GenSignal(int)
并照常继续。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.