MousePressEvents für Elemente innerhalb QGraphicsItemGroup

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
tigger
User
Beiträge: 2
Registriert: Samstag 4. März 2017, 20:05

Ich arbeite mich gerade in das Thema QGraphicsView ein. Dabei habe ich versucht ein C++ Tutorial von Nokia aus dem Jahr 2011 (YouTube: Qt DevDays 2011, Advanced Qt -A Deep Dive 1/6) in Python umzusetzen. Es wird ein einfaches Haus gezeichnet, welches sich beim Mausklick umdreht, auf der Rückseite des Hauses erscheint ein Combobox-Menü für eine Farbauswahl. Hierbei bin ich auf das Problem gestossen, das man bis Qt 4.7 für abgeleitete Klassen der Klasse QGraphicsItemGroup die Eigenschaft setHandlesChildEvents(False) setzten konnte, damit die Events (MousePressEvent usw.) an die Kinder der Gruppe weitergeleitet werden. Diese Funktion ist ab Qt 4.7 obsolet und nicht mehr einsetzbar. Alternativen konnte ich in der Dokumentation nicht finden. Wie kann erreichen, dass die Elemente innerhalb des QGraphicsProxyWidget-Containers die Events erhalten ?

Vielen Dank im voraus !

Datei: main_house.py

Code: Alles auswählen

from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView
from PyQt5.QtCore import Qt
import sys
from House.house import House

app = QApplication([])
scene = QGraphicsScene()

house_1 = House(Qt.blue, Qt.yellow)
scene.addItem(house_1)

scene.setSceneRect(0, 0, 500, 500)
view = QGraphicsView(scene)
view.show()
view.resize(600, 600)

sys.exit(app.exec_())
Datei: house.py

Code: Alles auswählen

from PyQt5.QtWidgets import QGraphicsItemGroup, QGraphicsProxyWidget, QGraphicsRectItem, QGraphicsPolygonItem, \
    QWidget, QVBoxLayout, QLabel, QComboBox, QPushButton
from PyQt5.QtCore import QTimeLine, QPointF, QRectF, Qt
from PyQt5.QtGui import QColor, QPolygonF, QTransform


class House(QGraphicsItemGroup):
    def __init__(self, roofcolor: QColor, facadecolor: QColor, parent=None):
        super(House, self).__init__(parent)
        self._front = True
        self._timeline = None
        self._graphics = None
        self._configpage = None
        self._facade = None
        self._roof = None

        self.roof_polygon = QPolygonF()
        self.roof_polygon << QPointF(0, 200) << QPointF(100, 0) << QPointF(200, 200)

        self.body_rect = QRectF(0, 200, 200, 200)

        self.create_roof(roofcolor)
        self.create_front(facadecolor)
        self.create_back(roofcolor, facadecolor)
        
        # =================================================
        # self.setHandlesChildEvents(False)  # obsolete since Qt 4.7
 

    def mousePressEvent(self, event):
        if not self._timeline:
            self._timeline = QTimeLine(1000)
            self._timeline.setCurveShape(QTimeLine.EaseInOutCurve)
            self._timeline.valueChanged.connect(self.rotate_house)
            self._timeline.finished.connect(self.reset)
            self._timeline.start()

    def reset(self):
        self._timeline = None

    def rotate_house(self, pos):
        angle = int(pos * 180)
        if self._front is True:
            angle += 180
        transform = QTransform()
        transform.translate(100, 0)
        transform.rotate(angle, Qt.YAxis)
        transform.translate(-100, 0)
        self.setTransform(transform)

        if pos == 1.0:
            self._front = not self._front

        config = angle < 90 or angle >= 270
        self._configpage.setVisible(config)
        self._facade.setVisible(not config)

    def update_roof_color(self):
        combo = self.sender()
        color = combo.itemData(combo.currentIndex()).value()
        self._roof.setBrush(color)

    def update_house_color(self):
        combo = self.sender()
        color = combo.itemData(combo.currentIndex()).value()
        self._facade.setBrush(color)

    def create_roof(self, color: QColor):
        self._roof = QGraphicsPolygonItem(self.roof_polygon)
        self.addToGroup(self._roof)
        self._roof.setBrush(color)

    def create_front(self, color: QColor):
        self._facade = QGraphicsRectItem(self.body_rect)
        self._facade.setBrush(color)
        self.addToGroup(self._facade)

    def create_back(self, roof_color: QColor, facade_color: QColor):
        self._configpage = QGraphicsProxyWidget()
        self._configpage.setWidget(self.create_config_widget(roof_color, facade_color))
        self._configpage.setGeometry(self.body_rect)
        self.addToGroup(self._configpage)
        self._configpage.hide()

    def create_config_widget(self, roof_color: QColor, facade_color: QColor) -> QWidget:
        res = QWidget()
        layout = QVBoxLayout(res)
        label = QLabel('Roof color:')
        layout.addWidget(label)
        self.roof_combo = self.create_color_combobox(roof_color)  # combobox does not receive events
        layout.addWidget(self.roof_combo)
        self.roof_combo.activated.connect(self.update_roof_color)
        label = QLabel('House color:')
        layout.addWidget(label)
        self.facade_combo = self.create_color_combobox(facade_color)
        layout.addWidget(self.facade_combo)
        self.facade_combo.activated.connect(self.update_house_color)
        bt = QPushButton('Test')
        bt.setCheckable(True)
        layout.addWidget(bt)
        layout.addStretch(1)
        return res

    def create_color_combobox(self, color: QColor) -> QComboBox:
        res = QComboBox()
        res.addItem('red', QColor(Qt.red))
        res.addItem('blue', QColor(Qt.blue))
        res.addItem('green', QColor(Qt.green))
        res.addItem('white', QColor(Qt.white))
        res.setCurrentIndex(res.findData(color))
        return res
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

»setHandlesChildEvents« wurde anscheinend von installSceneEventFilter abgelöst.

Und was soll das lustige Pfeilchen bei »create_color_combobox«?
tigger
User
Beiträge: 2
Registriert: Samstag 4. März 2017, 20:05

Seit Python 3.5 kann man durch das "typing-module" type hints nutzen. Der return-Datentyp wird durch den Pfeil kenntlich gemacht, die Übergabe-Argument-Datentypen der Methoden/Funktionen durch einen Doppelpunkt, gefolgt vom erwarteten Datentyp. Sehr praktisch, wenn man z.B. mit PyCharm arbeitet.

Grüße
Sven
Antworten