从列表中的一个 QGraphicsItem 向该列表中的所有项目发出信号

Signaling from one QGraphicsItem in a list to all items in that list

背景:我正在尝试制作一个日历应用程序。我通过为给定 month.All 中的每个日期排列 QGraphicsItemGroup 元素来创建月份的自定义视图 QGraphicsItemGroup 元素位于列表中以便于迭代。当鼠标悬停在日期上时,背景变为灰色。单击日期时,背景变为蓝色。单击另一个日期时,它会标记为蓝色,并且会清除之前的日期。

月份概览

问题:我只希望最后点击的日期有蓝色背景,而不是所有点击的日期。所有其他日期元素都应该有白色背景。我不知道如何将信号从日期列表中的一个 QGraphicsItemGroup 元素发送到该列表中的所有元素。

当前代码:

# coding=utf-8
from PyQt4.QtCore import Qt
import sys
from datetime import *
from calendar import Calendar
from PyQt4.QtGui import (QApplication, QDialog, QGraphicsView, QGraphicsScene, QGraphicsRectItem, QVBoxLayout,
                         QGraphicsSimpleTextItem, QBrush, QFont, QGraphicsItemGroup)

class GraficsView(QDialog):

    def __init__(self, parent=None):
        monthnames = ("Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "November",
                      "Dezember")
        super(GraficsView, self).__init__(parent)
        self.viewbox = QGraphicsView()
        layout = QVBoxLayout()
        layout.addWidget(self.viewbox)
        self.setLayout(layout)

        self.scene = QGraphicsScene(self.viewbox)
        self.scene.setSceneRect(0,0,701,501)
        self.calendarList = CalendarList(datetime(2018,2,1), self.scene)

        self.viewbox.setScene(self.scene)


class DateElement(QGraphicsItemGroup):

    def __init__(self, scene, status=False, date=datetime.today(), coordinates=()):
        QGraphicsItemGroup.__init__(self, scene=scene)
        wochentage = ("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag")
        self.status = status
        if self.status:
            self.setdate(date)
            self.setcoordinates(coordinates)

    def setdate(self, date):
        wochentage = ("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag")
        self.date = date

        self.dayname = wochentage[self.date.weekday()]
        self.daynumber = self.date.day

    def setcoordinates(self, coordinates):
        self.coordinates = coordinates

        self.rectangle = QGraphicsRectItem(self.coordinates[0], self.coordinates[1], self.coordinates[2],
                                           self.coordinates[3])
        self.rectangle.setAcceptHoverEvents(True)

        self.fontA = QFont("Verdana", 10, QFont.Bold)
        self.fontB = QFont("Verdana", 18, QFont.Bold)

        self.lableday = QGraphicsSimpleTextItem()
        if self.dayname in ("Samstag", "Sonntag"):
            self.lableday.setBrush(QBrush(Qt.red))
        else:
            self.lableday.setBrush(QBrush(Qt.black))
        self.lableday.setFont(self.fontA)
        self.lableday.setText(self.dayname)
        self.lableday.setPos(self.coordinates[0]+3, self.coordinates[1])

        self.lablenumber = QGraphicsSimpleTextItem()
        if self.dayname in ("Samstag", "Sonntag"):
            self.lablenumber.setBrush(QBrush(Qt.red))
        else:
            self.lablenumber.setBrush(QBrush(Qt.black))
        self.lablenumber.setFont(self.fontB)
        self.lablenumber.setText(str(self.daynumber)+".")
        self.lablenumber.setPos(self.coordinates[0]+3, self.coordinates[1]+12)

        self.addToGroup(self.rectangle)
        self.addToGroup(self.lableday)
        self.addToGroup(self.lablenumber)

    def hoverEnterEvent(self, event):
        self.rectangle.setBrush(QBrush(Qt.lightGray))
        self.update()

    def hoverLeaveEvent(self, event):
        self.rectangle.setBrush(QBrush(Qt.white))
        self.update()

    def mousePressEvent(self, event):
        self.rectangle.setAcceptHoverEvents(False)
        self.rectangle.setBrush(QBrush(Qt.blue))
        self.update()

    def clearRectangle(self):
        self.rectangle.setAcceptHoverEvents(True)
        self.rectangle.setBrush(QBrush(Qt.white))
        self.update()

class CalendarList():

    def __init__(self, date, scene):
        self.date = date
        self.scene = scene
        self.dateelements = []

        self.createdates()

    def createdates(self):
        weekcount = 0
        daycount = 0
        calendarobjekt = Calendar()

        for dateobjekt in calendarobjekt.itermonthdates(self.date.year, self.date.month):
            if daycount < 7:
                if dateobjekt.month == self.date.month:
                    self.dateelements.append(DateElement(self.scene, True, dateobjekt, (daycount*100, weekcount*100, 100, 100)))
                else:
                    self.dateelements.append(DateElement(self.scene))
                daycount += 1
            else:
                daycount = 0
                weekcount += 1
                if dateobjekt.month == self.date.month:
                    self.dateelements.append(DateElement(self.scene, True, dateobjekt, (daycount*100, weekcount*100, 100, 100)))
                else:
                    self.dateelements.append(DateElement(self.scene))
                daycount += 1

app = QApplication(sys.argv)
form = GraficsView()
form.show()
app.exec_()

可能的解决方案:

  1. 在 CalendarList class 中创建一个信号,该信号可以由 DateElement 引发,然后触发 CalendarList 中所有项目的 clearBackground 方法。

CalendarList 不是继承自 QObject 的 class,因此它不支持信号,我的回答是通过 scene().items() 获取项目的意义, 那么我们就把DateElement class 的item过滤出来, 状态为true, 那么就会用到clearRectangle() 方法:

def mousePressEvent(self, event):
    for item in self.scene().items():
        if isinstance(item, DateElement):
            if item.status:
                item.clearRectangle()
    self.rectangle.setAcceptHoverEvents(False)
    self.rectangle.setBrush(QBrush(Qt.blue))
    #self.update()