css 如何在QcalendarWidget中设置禁用日期的颜色

9rygscc1  于 2023-01-10  发布在  其他
关注(0)|答案(2)|浏览(296)

我尝试在PySide 2中使用CSS来设置我的QcalendarWidget的样式,并将我的最大日期设置为22/12/2022。我可以将下个月的文本颜色更改为绿色,将正常日期更改为白色,但有没有办法更改介于两者之间的日期的颜色?(即从22/12/2022更改为08/01/2023)

#qt_calendar_calendarview {
    outline: 0px;
    selection-background-color: #43ace6;
    alternate-background-color: #2c313c;
    background_color:rgb(170, 0, 0)
}

QCalendarWidget QAbstractItemView:!enabled { 
    color:"green"
 }

QCalendarWidget QAbstractItemView:enabled{ 
    color:"white"
 }
rjzwgtxy

rjzwgtxy1#

不幸的是,不能使用样式表或调色板。
不过,还是有一些可能的解决方案。

覆盖paintCell()

这是最简单的方法,因为我们可以使用paintCell()来绘制内容。不幸的是,这有一些限制:我们只得到了画家、矩形和日期,这意味着我们完全有责任选择如何绘制单元格和日期,并且它可能与小部件的其余部分(特别是标题)不一致。

设置日期文本格式

QCalendarWidget提供了setDateTextFormat(),它允许为任意日期设置特定的QTextCharFormat
诀窍是为最小/最大月份范围之外的日期设置格式:假设日历不能切换到可用日期范围之外的月份,因此我们只需要设置月份边界中这些特定日期的格式。

class CustomCalendar(QCalendarWidget):
    def fixDateFormats(self):
        fmt = QTextCharFormat()
        # clear existing formats
        self.setDateTextFormat(QDate(), fmt)

        fmt.setForeground(QBrush(QColor('green')))

        for ref, delta in ((self.minimumDate(), -1), (self.maximumDate(), 1)):
            month = ref.month()
            date = ref.addDays(delta)
            while date.month() == month:
                self.setDateTextFormat(date, fmt)
                date = date.addDays(delta)

    def setDateRange(self, minimum, maximum):
        super().setDateRange(minimum, maximum)
        self.fixDateFormats()

    def setMinimumDate(self, date):
        super().setMinimumDate(date)
        self.fixDateFormats()

    def setMaximumDate(self, date):
        super().setMaximumDate(date)
        self.fixDateFormats()

唯一的缺点是它不允许改变属于 another month的单元格的颜色,虽然可以使用OP编写的样式表,但这不包括周末的例外情况。

使用自定义项委托

这个解决方案有点过于复杂,但也是最理想的,因为它与小部件和样式完全一致,同时还允许一些进一步的定制。
由于日历实际上是一个使用QTableView显示日期的复合小部件,这意味着,就像任何其他Qt项视图一样,我们可以覆盖它的委托。
默认的委托是QItemDelegate(QStyledItemDelegates的更简单版本,通常用于项目视图)。虽然我们可以通过完全覆盖委托的paint()来手动绘制单元格的内容,但在这一点上,第一种解决方案要简单得多。相反,我们使用默认的绘制并区分何时/如何显示实际显示值:如果它在日历范围内,则保留默认行为,否则使用自定义颜色更改QStyleOptionViewItem并显式调用drawDisplay()

class CalDelegate(QItemDelegate):
    cachedOpt = QStyleOptionViewItem()
    _disabledColor = None
    def __init__(self, calendar):
        self.calendar = calendar
        self.view = calendar.findChild(QAbstractItemView)
        super().__init__(self.view)
        self.view.setItemDelegate(self)
        self.dateReference = self.calendar.yearShown(), self.calendar.monthShown()
        self.calendar.currentPageChanged.connect(self.updateReference)

    def disabledColor(self):
        return self._disabledColor or self.calendar.palette().color(
            QPalette.Disabled, QPalette.Text)

    def setDisabledColor(self, color):
        self._disabledColor = color
        self.view.viewport().update()

    def updateReference(self, year, month):
        self.dateReference = year, month

    def dateForCell(self, index):
        day = index.data()
        row = index.row()
        if self.calendar.horizontalHeaderFormat():
            if row == 0:
                return
            row -= 1
        col = index.column()
        if self.calendar.verticalHeaderFormat():
            if col == 0:
                return
            col -= 1
        year, month = self.dateReference
        if row < 1 and day > 7:
            # previous month
            month -= 1
            if month < 1:
                month = 12
                year -= 1
        elif row > 3 and day < 15:
            # next month
            month += 1
            if month > 12:
                month = 1
                year += 1
        return QDate(year, month, day)

    def drawDisplay(self, qp, opt, rect, text):
        if self.doDrawDisplay:
            super().drawDisplay(qp, opt, rect, text)
        else:
            self.cachedOpt = QStyleOptionViewItem(opt)

    def paint(self, qp, opt, index):
        date = self.dateForCell(index)
        self.doDrawDisplay = not bool(date)
        super().paint(qp, opt, index)
        if self.doDrawDisplay:
            return
        year, month = self.dateReference
        if (
            date.month() != month 
            or not self.calendar.minimumDate() <= date <= self.calendar.maximumDate()
        ):
            self.cachedOpt.palette.setColor(
                QPalette.Text, self.disabledColor())
        super().drawDisplay(qp, self.cachedOpt, 
            self.cachedOpt.rect, str(index.data()))

app = QApplication([])
cal = QCalendarWidget()
delegate = CalDelegate(cal)
delegate.setDisabledColor(QColor('green'))
cal.setDateRange(QDate(2022, 12, 4), QDate(2023, 1, 27))
cal.show()
app.exec()
a1o7rhls

a1o7rhls2#

我不确定使用css的方法,但可以使用代码。
如果覆盖QCalenderWidget.paintCell方法,则可以单独设置每个日期的样式。
例如:

class Calendar(QCalendarWidget):
    def __init__(self, parent) -> None:
        super().__init__(parent)
        self.start_date = QDate(2022, 12, 22)
        self.end_date = QDate(2023, 8, 1)

    def paintCell(self, painter, rect, date):
        if date.daysTo(self.end_date) > 0 and date.daysTo(self.start_date) < 0:
            painter.setPen("green")
            brush = painter.brush()
            brush.setColor("black") 
            brush.setStyle(Qt.SolidPattern)
            painter.setBrush(brush)
            painter.drawRect(rect)
            painter.drawText(rect, Qt.AlignmentFlag.AlignCenter, str(date.day()))
        else:
            super().paintCell(painter, rect, date)

相关问题