Невозможно PaintCell после использования QItemDelegate для изменения положения даты для QCalendarWidget

Я пытаюсь переопределить метод paintCell() QCalendarWidget, чтобы нарисовать красный контур в ячейке с сегодняшней датой и нарисовать события, которые будут определены пользователем. Для моего календаря я использовал QItemDelegate, чтобы изменить выравнивание флагов даты, чтобы у меня было больше места для рисования событий. Однако я не могу заставить QItemDelegate и paintCell() работать вместе. Я могу иметь только одну или другую работу одновременно. Если я пытаюсь сделать и то, и другое, отображается только Делегат и ничего не рисуется.

from PySide2.QtWidgets import QMainWindow, QCalendarWidget, QApplication, QItemDelegate, QTableView
from PySide2.QtGui import QPen
from PySide2.QtCore import Qt
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__()
        self.calendar = CustomCalendar()
        self.calendarview = self.calendar.findChild(QTableView, "qt_calendar_calendarview")
        self.calendardelegate = CalendarItemDelegate(self.calendarview)
        self.calendarview.setItemDelegate(self.calendardelegate)
        self.setCentralWidget(self.calendar)
        self.show()


class CustomCalendar(QCalendarWidget):
    def __init__(self, parent=None):
        super().__init__()

    def paintCell(self, painter, rect, date):
        QCalendarWidget.paintCell(self, painter, rect, date)
        pen = QPen()
        pen.setColor(Qt.red)
        painter.setPen(pen)
        if date == date.currentDate():
            painter.save()
            painter.drawRect(rect.adjusted(0, 0, -1, -1))
            painter.restore()


class CalendarItemDelegate(QItemDelegate):
    def paint(self, painter, option, index):
        painter._date_flag = index.row() > 0
        super().paint(painter, option, index)

    def drawDisplay(self, painter, option, rect, text):
        if painter._date_flag:
            option.displayAlignment = Qt.AlignTop | Qt.AlignLeft
        super().drawDisplay(painter, option, rect, text)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

Как я могу заставить работать оба сразу?

введите здесь описание изображения

делегат

введите здесь описание изображения

PaintCell


person Streeter    schedule 06.01.2021    source источник


Ответы (1)


Когда делегат пользовательского элемента установлен в виджете календаря, значение по умолчанию paintCell просто игнорируется, поскольку его вызов является обязанностью (частного) делегата.

Поскольку вы используете QItemDelegate, вы можете воспользоваться преимуществом drawFocus() и проверьте, установлен ли для option.state флаг State_Selected (технически вы могли бы сделать это и в drawDisplay(), так как функция все равно вызывается, а опция имеет те же значения):

    def drawFocus(self, painter, option, rect):
        super().drawFocus(painter, option, rect)
        if option.state & QStyle.State_Selected:
            painter.save()
            painter.setPen(Qt.red)
            painter.drawRect(rect.adjusted(0, 0, -1, -1))
            painter.restore()
person musicamante    schedule 07.01.2021
comment
Меня интересует вызов paintCell из делегата. Как я мог это сделать? - person Streeter; 07.01.2021
comment
Qt делает это с помощью внутреннего делегата: у него есть ссылка на виджет календаря, поэтому он получает дату, используя текущий месяц, строку и столбец, затем вызывает paintCell() с рисовальщиком, option.rect и датой, вычисленной ранее. - person musicamante; 08.01.2021
comment
@Streeter обратите внимание, что paintCell на самом деле вызывает рисунок делегата, поэтому это не имеет большого смысла. Вместо этого вы могли бы выяснить, является ли текущий индекс является текущей датой. Это немного сложно, но это можно сделать, повторно реализовав на python исходную реализацию C++. - person musicamante; 08.01.2021