在 QCalendarWidget 中将项目添加到 QTableView

时间:2023-03-11
本文介绍了在 QCalendarWidget 中将项目添加到 QTableView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我目前正在制作一个带有日历的待办事项应用程序.每当用户在特定日期有事件时,左上角会出现一个红色圆圈.每当用户双击日期时,我希望它显示一个包含当天事件信息的新窗口.但是,我无法将信息存储到每个日期中.我怎样才能使每个日期都有一个可以存储事件的列表?

I'm currently making a to-do application which has a calendar. Whenever the user has an event on a specific date, A red circle appears in the top left corner. Whenever the user double clicks on the date, I want it to display a new window with information on event for the day. However, I am having trouble storing information into each date. How can I make it so each date has a sort of list that can store events?

这是用户界面:

这是子类 QCalendarWidget 的代码:

Here is the code for the subclassed QCalendarWidget:

class TodoCalendar(QtWidgets.QCalendarWidget):
    def __init__(self, list_of_events, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.list_of_events = list_of_events
        //list_of_events is a list of all events the user has created

        self.table = self.findChild(QtWidgets.QTableView)
        self.table.viewport().installEventFilter(self)

    def paintCell(self, painter, rect, date):
        super().paintCell(painter, rect, date)
        for event in self.list_of_events.values():
            if event.due_time == date:
                painter.setBrush(Qt.red)
                painter.drawEllipse(rect.topLeft() + QPoint(12, 7), 3, 3)

    def eventFilter(self, source, event):
        if (event.type() == QtCore.QEvent.MouseButtonDblClick and source is self.table.viewport()):
            index = self.table.indexAt(event.pos())
            print(f"row: {index.row()}, column: {index.column()}, text: {index.data()}")
        return super().eventFilter(source, event)

这里还有 list_of_events 的列表:

Also here is the list for list_of_events:

{'test changed': <CustomWidgets.TodoEvent object at 0x00000230A5A72908>, 'due 10/8': <CustomWidgets.TodoEvent object at 0x00000230A5AA5080>, 'also due 10/9': <CustomWidgets.TodoEvent object at 0x00000230A5AC4B00>, 'also due 10/9 too': <CustomWidgets.TodoEvent object at 0x00000230A5AD0550>, 'due 10/9 too too': <CustomWidgets.TodoEvent object at 0x00000230A5AD0A90>, '10/9 2': <CustomWidgets.TodoEvent object at 0x00000230A5AD6438>, '10/10': <CustomWidgets.TodoEvent object at 0x00000230A5AD64A8>, '10/10 also': <CustomWidgets.TodoEvent object at 0x00000230A5AD64E0>, '10/10 2': <CustomWidgets.TodoEvent object at 0x00000230A5AD6550>, '10/10 3': <CustomWidgets.TodoEvent object at 0x00000230A5AD65C0>, '10/10 4': <CustomWidgets.TodoEvent object at 0x00000230A5AD6630>, 'due 10/9 changed': <CustomWidgets.TodoEvent object at 0x00000230A5AD6668>}

每个 toDoEvent 都有一个标题、到期时间、提醒时间和描述

each toDoEvent has a title, due_time, remind_time, and description

推荐答案

另一种方法是获取给定行和列的日期,然后过滤事件.

Instead of storing in some event by date another approach is to get the date given the row and column, and then filter the events.

问题是没有公共方法来计算给定行和列的日期,所以我的解决方案使用 Qt 私有 API 代码.

The problem is that there is no public method to calculate the date given the row and column, so my solution uses the Qt private API code.

综合以上,解决办法是:

Considering the above, the solution is:

import random
from dataclasses import dataclass

from PyQt5 import QtCore, QtGui, QtWidgets


@dataclass
class Todo:
    date: QtCore.QDate
    name: str


class TodoCalendar(QtWidgets.QCalendarWidget):
    def __init__(self, list_of_events, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.list_of_events = list_of_events

        self.table = self.findChild(QtWidgets.QTableView)
        self.table.viewport().installEventFilter(self)

    def paintCell(self, painter, rect, date):
        super().paintCell(painter, rect, date)
        for event in self.list_of_events:
            if event.date == date:
                painter.setBrush(QtCore.Qt.red)
                painter.drawEllipse(rect.topLeft() + QtCore.QPoint(12, 7), 3, 3)

    def eventFilter(self, source, event):
        if (
            event.type() == QtCore.QEvent.MouseButtonDblClick
            and source is self.table.viewport()
        ):
            index = self.table.indexAt(event.pos())
            date = self.dateForCell(index.row(), index.column())
            today_events = [ev for ev in self.list_of_events if ev.date == date]
            if today_events:
                print(today_events)
        return super().eventFilter(source, event)

    def referenceDate(self):
        refDay = 1
        while refDay <= 31:
            refDate = QtCore.QDate(self.yearShown(), self.monthShown(), refDay)
            if refDate.isValid():
                return refDate
            refDay += 1
        return QtCore.QDate()

    @property
    def firstColumn(self):
        return (
            1
            if self.verticalHeaderFormat() == QtWidgets.QCalendarWidget.ISOWeekNumbers
            else 0
        )

    @property
    def firstRow(self):
        return (
            0
            if self.horizontalHeaderFormat()
            == QtWidgets.QCalendarWidget.NoHorizontalHeader
            else 1
        )

    def columnForDayOfWeek(self, day):
        if day < 1 or day > 7:
            return -1
        column = day - self.firstDayOfWeek()
        if column < 0:
            column += 7
        return column + self.firstColumn

    def columnForFirstOfMonth(self, date):
        return (self.columnForDayOfWeek(date.dayOfWeek()) - (date.day() % 7) + 8) % 7

    def dateForCell(self, row, column):
        if (
            row < self.firstRow
            or row > (self.firstRow + 6 - 1)
            or column < self.firstColumn
            or column > (self.firstColumn + 7 - 1)
        ):
            return QtCore.QDate()
        refDate = self.referenceDate()
        if not refDate.isValid():
            return QtCore.QDate()
        columnForFirstOfShownMonth = self.columnForFirstOfMonth(refDate)
        if columnForFirstOfShownMonth - self.firstColumn < 1:
            row -= 1
        requestedDay = (
            7 * (row - self.firstRow)
            + column
            - columnForFirstOfShownMonth
            - refDate.day()
            + 1
        )
        return refDate.addDays(requestedDay)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    events = [
        Todo(QtCore.QDate.currentDate().addDays(random.randint(1, 10)), f"name-{i}")
        for i in range(15)
    ]

    w = TodoCalendar(events)
    w.show()
    sys.exit(app.exec_())

这篇关于在 QCalendarWidget 中将项目添加到 QTableView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:将信号连接到插槽立即导致信号被发射 下一篇:pyqt5不显示窗口

相关文章