QGraphicesItem испускает сигнал при hoverEnterEvent
Каков наилучший метод / практика для подачи сигнала при входе в QGraphicsWidget
или QGraphicsItem
?
В моем MWE я хотел бы вызвать вызов MainWindow.update
, от Square.hoverEnterEvent
всякий раз, когда пользователь щелкает мышью по элементу в QGraphicsScene. Беда в том, что 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
как необходимо.
1 ответ
Как сказал бы закон Мерфи, Эхуморо уже дает ответ.
Кажется, нужно подкласс QGraphicsScene
и добавьте необходимый сигнал. это тогда срабатывает от QGraphicsItem/Widget
, Это требует, чтобы все элементы в пределах сцены были разделены на подклассы, чтобы гарантировать, что они вызывают соответствующую функцию emit, но, похоже, они должны это делать в любом случае при работе с графической сценой.
Я не буду отмечать это как ответ на некоторое время в случае, если у кого-то есть лучшее предложение.
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)
...
И переключатель из self.data = QGraphicsScene(...)
в self.data = GraphicsScene
в MainWindow
Функция инициализации.