You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt4日历应用:单日期选中高亮的信号传递实现问题

解决PyQt日历应用中仅保留最后点击日期蓝色背景的问题

我正在开发一款日历应用,通过排列QGraphicsItemGroup元素实现自定义月视图,所有QGraphicsItemGroup元素存入列表以便遍历。鼠标悬停日期时背景变为灰色,点击日期时背景变为蓝色,但当前所有被点击的日期都会保持蓝色,需求是仅最后点击的日期显示蓝色背景,其余日期元素均为白色背景。我无法实现列表中单个QGraphicsItemGroup元素向列表内所有元素发送信号。

我来帮你搞定这个问题!核心思路是让管理所有日期元素的CalendarList类作为中间协调者,通过自定义信号与槽实现全局状态同步:当某个日期被点击时,通知CalendarList,由它来重置所有其他日期的背景,只保留当前点击的日期为蓝色。

关键修改思路

  • 给DateElement添加信号能力:因为QGraphicsItemGroup不属于QObject体系,需要多继承QObject来支持信号
  • 让CalendarList作为信号接收者:实现槽函数遍历所有元素,重置非当前点击元素的背景
  • 绑定信号与槽:每个日期元素创建时,将点击信号连接到CalendarList的处理函数

修改后的完整代码

# coding=utf-8
from PyQt4.QtCore import Qt, QObject, pyqtSignal
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)

# 多继承QObject和QGraphicsItemGroup,添加信号支持
class DateElement(QObject, QGraphicsItemGroup):
    # 定义点击信号,传递当前被点击的日期元素实例
    dateClicked = pyqtSignal(object)

    def __init__(self, scene, status=False, date=datetime.today(), coordinates=()):
        QObject.__init__(self)
        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):
        # 避免覆盖已选中的蓝色背景
        if self.rectangle.brush().color() != Qt.blue:
            self.rectangle.setBrush(QBrush(Qt.white))
        self.update()

    def mousePressEvent(self, event):
        # 发射信号通知CalendarList处理全局状态
        self.dateClicked.emit(self)
        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()

# 继承QObject,实现槽函数处理全局状态
class CalendarList(QObject):
    def __init__(self, date, scene):
        QObject.__init__(self)
        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:
                    date_elem = DateElement(self.scene, True, dateobjekt, (daycount*100, weekcount*100, 100, 100))
                    # 绑定每个日期的点击信号到处理函数
                    date_elem.dateClicked.connect(self.onDateClicked)
                    self.dateelements.append(date_elem)
                else:
                    self.dateelements.append(DateElement(self.scene))
                daycount += 1
            else:
                daycount = 0
                weekcount += 1
                if dateobjekt.month == self.date.month:
                    date_elem = DateElement(self.scene, True, dateobjekt, (daycount*100, weekcount*100, 100, 100))
                    date_elem.dateClicked.connect(self.onDateClicked)
                    self.dateelements.append(date_elem)
                else:
                    self.dateelements.append(DateElement(self.scene))
                daycount += 1

    def onDateClicked(self, clicked_date):
        # 遍历所有元素,重置非当前点击的有效日期背景
        for elem in self.dateelements:
            if elem != clicked_date and elem.status:
                elem.clearRectangle()

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

核心修改点说明

  1. DateElement多继承QObject:给原本不支持信号的QGraphicsItemGroup添加信号能力,定义dateClicked信号传递自身实例
  2. CalendarList的槽函数:onDateClicked函数负责遍历所有日期元素,调用clearRectangle重置非当前点击元素的背景
  3. 信号绑定:每个有效日期元素创建时,将其点击信号连接到CalendarList的处理函数,实现全局状态同步
  4. 优化悬停事件:在hoverLeaveEvent中增加判断,避免覆盖已选中的蓝色背景

内容的提问来源于stack exchange,提问作者Kingmaker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:15:36