PySide/PyQT5:如何从 QGraphicsItem 发出信号?
Posted
技术标签:
【中文标题】PySide/PyQT5:如何从 QGraphicsItem 发出信号?【英文标题】:PySide/PyQT5: How to emit signals from a QGraphicsItem? 【发布时间】:2018-04-15 05:20:59 【问题描述】:我想在双击QGraphicsItem
时发出一个信号,以便更改主窗口中的小部件。 graphics-scene/-item 不提供emit()
方法,但我只是想知道是否有另一种方法可以做到这一点。下面的代码在QGraphicsView
类中有一个函数,当双击一个项目时,它将打印到终端。我怎样才能把它变成一个槽/信号(如果QGraphicsItem
不支持信号/槽)?
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class MyFrame(QGraphicsView):
def __init__( self, parent = None ):
super(MyFrame, self).__init__(parent)
scene = QGraphicsScene()
self.setScene(scene)
self.setFixedSize(500, 500)
pen = QPen(QColor(Qt.green))
brush = QBrush(pen.color().darker(150))
item = scene.addEllipse(0, 0, 45, 45, pen, brush)
item.setPos(0,0)
def mouseDoubleClickEvent(self, event):
print("Circle Clicked!")
# this double click event prints to terminal but how to setup
# signal/slot to update the QWidget QLabel text instead?
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
top = QLabel("Double Click Green Circle (Howto change this QWidget Label with signals?)")
bottom = MyFrame()
splitter = QSplitter(Qt.Vertical)
splitter.addWidget(top)
splitter.addWidget(bottom)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.setGeometry(0, 0, 500, 600)
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
【问题讨论】:
在QGraphicsScene
的子类上定义一个自定义的itemDoubleClicked
信号,然后从项目中执行self.scene().itemDoubleClicked.emit()
。
你有例子吗?
class GS(QGraphicsScene): itemDoubleClicked = QtCore.pyqtSignal()
.
嗨,是的,不起作用。 “没有 emit() 属性”的错误。制作一个单独的 QGraphicsObject 子类并在那里调用 func 不会出错,但也不会发出。我已经看到这个关于 QGraphicsItem 的信号/插槽问题在搜索中被多次提出,但没有人能提供一个例子或证据,这实际上可以在不完全重写 QGraphicsScene 的情况下完成。这就是大多数人所做的,所以猜测它不可能从 QGraphis 向 QWidget 发出信号。耻辱,使 QGraphics 类在实际应用程序中毫无用处。我想是时候开发我自己的 QGraphics 了。
我发布的代码非常适合我。不知道你做错了什么。我猜你没有创建 QGraphicsScene
子类的实例并将其设置在视图上。
【参考方案1】:
下面是一个简单的示例,展示了一种从图形项发出信号的方法。这在QGraphicsScene
的子类上定义了一个自定义信号,然后使用图形项的scene()
方法发出它:
import sys
from PySide import QtCore, QtGui
class GraphicsScene(QtGui.QGraphicsScene):
itemDoubleClicked = QtCore.Signal(object)
class GraphicsRectangle(QtGui.QGraphicsRectItem):
def mouseDoubleClickEvent(self, event):
self.scene().itemDoubleClicked.emit(self)
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.view = QtGui.QGraphicsView()
self.scene = GraphicsScene(self)
self.view.setScene(self.scene)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.view)
for i in range(1, 4):
self.scene.addItem(GraphicsRectangle(50 * i, 50 * i, 20, 20))
self.scene.itemDoubleClicked.connect(self.handleItemDoubleClicked)
def handleItemDoubleClicked(self, item):
print(item.boundingRect())
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
更新:
以下是基于您问题中的代码的示例。基本思想是相同的:在可用的QObject
(本例中为图形视图)上定义一个自定义信号,并使用它来发出双击通知。
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class MyFrame(QGraphicsView):
itemDoubleClicked = Signal(object)
def __init__(self, parent=None):
super(MyFrame, self).__init__(parent)
scene = QGraphicsScene()
self.setScene(scene)
self.setFixedSize(500, 500)
for i, color in enumerate('red blue green'.split()):
pen = QPen(QColor(color))
brush = QBrush(pen.color().darker(150))
item = scene.addEllipse(i * 50, i * 50, 45, 45, pen, brush)
item.setData(0, color.upper())
def mouseDoubleClickEvent(self, event):
item = self.itemAt(event.pos())
if item is not None:
self.itemDoubleClicked.emit(item)
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
top = QLabel('Double Click a Circle')
bottom = MyFrame()
bottom.itemDoubleClicked.connect(
lambda item, top=top:
top.setText('Double Clicked: %s' % item.data(0)))
splitter = QSplitter(Qt.Vertical)
splitter.addWidget(top)
splitter.addWidget(bottom)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.setGeometry(0, 0, 500, 600)
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
【讨论】:
嗨,谢谢,回答了一个问题,但我更新了上面的代码,以便更好地了解我试图在 QGraphicsEvents 和 QWidgets 之间进行通信事件的位置。如何在嵌套在 QWindow 内的 QGraphicsScene 之间连接信号,以使用当前打印到终端的文本更新 QLabel?即,以便单击将 QLabel 更改为“Circle Clicked!”? @cvw76。我添加了基于您的第二个示例。 (PS:如果您现在将此答案标记为已接受,我将不胜感激 - 即单击对勾符号)。 太棒了! lambda 非常优雅,我变得复杂了,这完美地解决了我试图在我的小应用程序中实现的问题。非常感谢!!我将其标记为完美回答。以上是关于PySide/PyQT5:如何从 QGraphicsItem 发出信号?的主要内容,如果未能解决你的问题,请参考以下文章
PySide2(PyQt5) 实现tab切换及方法详解(不定时更新)