输入QGraphicsWidget
或QGraphicsItem
时发出信号的最佳方法/实践是什么?
在我的MWE中,每当用户鼠标(s(通过qgraphicsScene中的项目,我想从Square.hoverEnterEvent
触发MainWindow.update
的呼叫。问题是QGraphicsItem/Widget
并非真正设计用于发射信号。取而代之的是设置这些类以处理QGraphicsScene
传递给它们的事件。QGraphicsScene
处理了用户选择项目但似乎没有处理鼠标条目事件的情况,至少没有entryEvent
的机制可以渗透到父窗口/窗口。
import sys
from PyQt5.QtWidgets import QWidget, QApplication, qApp, QMainWindow, QGraphicsScene, QGraphicsView, QStatusBar, QGraphicsWidget, QStyle
from PyQt5.QtCore import Qt, QSizeF
class Square(QGraphicsWidget) :
"""
doc string
"""
def __init__(self,*args, name = None, **kvps) :
super().__init__(*args, **kvps)
self.radius = 5
self.name = name
self.setAcceptHoverEvents(True)
def sizeHint(self, hint, size):
size = super().sizeHint(hint, size)
print(size)
return QSizeF(50,50)
def paint(self, painter, options, widget):
self.initStyleOption(options)
ink = options.palette.highLight() if options.state == QStyle.State_Selected else options.palette.button()
painter.setBrush(ink) # ink
painter.drawRoundedRect(self.rect(), self.radius, self.radius)
def hoverEnterEvent(self, event) :
print("Enter Event")
super().hoverEnterEvent(event)
class MainWindow(QMainWindow):
def __init__(self, *args, **kvps) :
super().__init__(*args, **kvps)
# Status bar
self.stat = QStatusBar(self)
self.setStatusBar(self.stat)
self.stat.showMessage("Started")
# Widget(s)
self.data = QGraphicsScene(self)
self.view = QGraphicsView(self.data, self)
item = self.data.addItem(Square())
self.view.ensureVisible(self.data.sceneRect())
self.setCentralWidget(self.view)
# Visibility
self.showMaximized()
def update(self, widget) :
self.stat.showMessage(str(widget.name))
if __name__ == "__main__" :
# Application
app = QApplication(sys.argv)
# Scene Tests
main = MainWindow()
main.show()
# Loop
sys.exit(app.exec_())
文档指出QGraphicsItem
并非旨在发出信号,而是旨在响应QGraphicsScene
发送给它的事件。相比之下,QGraphicsWidget
似乎是为此而设计的,但我不确定该入口应该在哪里。就我个人而言,我认为QGraphicsScene
确实应该从我对设计的理解中发出这些信号,但在这种情况下也不确定入口点应该在哪里。
目前,我看到以下可能的解决方案,#3是首选方法。我想知道其他人是否有更好的策略:
- 创建一个
QGraphicsScene
子类,我们将其称为Scene
,将其称为每个QgraphicsItem/qgraphicsWidget,然后从每个窗口小部件上调用Scene
的自定义触发器/信号。在这里,我将不得不将我打算在现场中包括的任何项目子类别。 - 将
Mainwindow
设置为场景或场景本身上每个项目的事件过滤器,并调用MainWindow.update
。 - 将
Mainwindow.data
设置为QGraphicsScene
的子类,我们称其为Scene
,然后让其过滤其自己的事件,该事件发出hoverEntry
信号。然后,hoverEntry
在必要时连接到MainWindow.update
。
,因为墨菲定律会让ekhumoro提供答案。
似乎应该亚类QGraphicsScene
并添加必要的信号。然后从QGraphicsItem/Widget
触发这。这就要求将场景中的所有项目分属级别,以确保它们调用相应的发射功能,但似乎必须在使用图形场景的东西时执行此操作。
如果有人有更好的建议,我不会将其标记为回答。
import sys
from PyQt5.QtWidgets import QWidget, QApplication, qApp, QMainWindow, QGraphicsScene, QGraphicsView, QStatusBar, QGraphicsWidget, QStyle, QGraphicsItem
from PyQt5.QtCore import Qt, QSizeF, pyqtSignal
class Square(QGraphicsWidget) :
"""
doc string
"""
def __init__(self,*args, name = None, **kvps) :
super().__init__(*args, **kvps)
self.radius = 5
self.name = name
self.setAcceptHoverEvents(True)
self.setFlag(self.ItemIsSelectable)
self.setFlag(self.ItemIsFocusable)
def sizeHint(self, hint, size):
size = super().sizeHint(hint, size)
print(size)
return QSizeF(50,50)
def paint(self, painter, options, widget):
self.initStyleOption(options)
ink = options.palette.highLight() if options.state == QStyle.State_Selected else options.palette.button()
painter.setBrush(ink) # ink
painter.drawRoundedRect(self.rect(), self.radius, self.radius)
def hoverEnterEvent(self, event) :
super().hoverEnterEvent(event)
self.scene().entered.emit(self)
self.update()
class GraphicsScene(QGraphicsScene) :
entered = pyqtSignal([QGraphicsItem],[QGraphicsWidget])
class MainWindow(QMainWindow):
def __init__(self, *args, **kvps) :
super().__init__(*args, **kvps)
# Status bar
self.stat = QStatusBar(self)
self.setStatusBar(self.stat)
self.stat.showMessage("Started")
# Widget(s)
self.data = GraphicsScene(self)
self.data.entered.connect(self.itemInfo)
self.data.focusItemChanged.connect(self.update)
self.view = QGraphicsView(self.data, self)
item = Square(name = "A")
item.setPos( 50,0)
self.data.addItem(item)
item = Square(name = "B")
item.setPos(-50,0)
self.data.addItem(item)
self.view.ensureVisible(self.data.sceneRect())
self.setCentralWidget(self.view)
# Visibility
self.showMaximized()
def itemInfo(self, item):
print("Here it is -> ", item)
if __name__ == "__main__" :
# Application
app = QApplication(sys.argv)
# Scene Tests
main = MainWindow()
main.show()
# Loop
sys.exit(app.exec_())
感兴趣的魔术线是QGrahicsScene
子类。
class GraphicsScene(QGraphicsScene) :
entered = pyqtSignal([QGraphicsItem],[QGraphicsWidget])
QGraphicsWidget.hoverEnterEvent
触发entered
信号。(这是我卡住的地方(
def hoverEnterEvent(self, event) :
...
self.scene().entered.emit(self)
...
和MainWindow
的init函数中的self.data = QGraphicsScene(...)
到self.data = GraphicsScene
的Switcheroo。