Python 将项目添加到QCalendarWidget内的QTableView

Python 将项目添加到QCalendarWidget内的QTableView,python,python-3.x,pyqt,pyqt5,qcalendarwidget,Python,Python 3.x,Pyqt,Pyqt5,Qcalendarwidget,我目前正在制作一个有日历的待办事项应用程序。每当用户在特定日期发生事件时,左上角就会出现一个红色圆圈。每当用户双击日期时,我希望它显示一个新窗口,其中包含当天事件的信息。但是,我在将信息存储到每个日期时遇到问题。如何使每个日期都有一个可以存储事件的列表 以下是用户界面: 下面是子类QCalendarWidget的代码: class TodoCalendar(QtWidgets.QCalendarWidget): def __init__(self, list_of_events, *a

我目前正在制作一个有日历的待办事项应用程序。每当用户在特定日期发生事件时,左上角就会出现一个红色圆圈。每当用户双击日期时,我希望它显示一个新窗口,其中包含当天事件的信息。但是,我在将信息存储到每个日期时遇到问题。如何使每个日期都有一个可以存储事件的列表

以下是用户界面:

下面是子类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)
以下是事件列表的列表:

{'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>}
{'test changed':,'due 10/8':,'due 10/9':,'due 10/9 too','due 10/9 too':,'10/9 2':,'10/10':,'10/10还':,'10/10 2','10/10 3','10/10 4','due 10/9 changed':}

每个toDoEvent都有一个标题、到期时间、提醒时间和描述,而不是按日期存储在某些事件中。另一种方法是获取给定行和列的日期,然后过滤事件

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

考虑到上述情况,解决方案是:

随机导入
从数据类导入数据类
从PyQt5导入QtCore、QtGui、QtWidgets
@数据类
类待办事项:
日期:QtCore.QDate
姓名:str
类TodoCalendar(QtWidgets.QCalendarWidget):
定义初始化(self,事件列表,*args,**kwargs):
super()
self.list\u of_events=list\u of_events
self.table=self.findChild(qtwidts.QTableView)
self.table.viewport().installEventFilter(self)
def paintCell(自身、油漆工、rect、日期):
super().paintCell(painter、rect、date)
对于self.list\u中的事件\u事件:
如果event.date==日期:
油漆工.退刀(QtCore.Qt.红色)
painter.drawerlipse(rect.topLeft()+QtCore.QPoint(12,7,3,3)
def eventFilter(自身、源、事件):
如果(
event.type()==QtCore.QEvent.mousebuttondbl单击
源是self.table.viewport()
):
index=self.table.indexAt(event.pos())
date=self.dateForCell(index.row(),index.column())
今天的事件=[ev for ev in self.list\如果ev.date==date,则事件列表中的ev为ev]
如果今天发生以下事件:
打印(今日活动)
return super().eventFilter(源,事件)
def referenceDate(自身):
refDay=1
而第7天:
返回-1
column=day-self.firstDayOfWeek()
如果列<0:
列+=7
返回列+self.firstColumn
def列第1个月(自我,日期):
return(self.columnForDayOfWeek(date.dayOfWeek())-(date.day()%7)+8)%7
def dateForCell(自身、行、列):
如果(
行(self.firstRow+6-1)
或列(self.firstColumn+7-1)
):
返回QtCore.QDate()
refDate=self.referenceDate()
如果不是refDate.isValid():
返回QtCore.QDate()
columnForFirstOfShownMonth=self.columnForFirstOfMonth(参考日期)
如果columnForFirstOfShownMonth-self.firstColumn<1:
行-=1
请求日期=(
7*(第行-第1行)
+纵队
-shownmonth第一列
-refDate.day()
+ 1
)
返回refDate.addDays(requestedDay)
如果名称=“\uuuuu main\uuuuuuuu”:
导入系统
app=qtwidts.QApplication(sys.argv)
事件=[
Todo(QtCore.QDate.currentDate().addDays(random.randint(1,10)),f“name-{i}”)
对于范围内的i(15)
]
w=TodoCalendar(事件)
w、 show()
sys.exit(app.exec_())

什么是
list\u of_events
?我想存储一天内所有toDoEvent对象的列表,因此当用户在某一天双击时,显示当天的所有事件。list\u of_events是用户创建的所有事件的列表显示事件列表。编辑代码并提供,你的上一个版本没有任何帮助。为什么不使用已经返回双击单元格日期的信号?@musicamante mmm,它不仅是由双击发出的(也通过按Enter和Return键),这可能不是OP的要求。是的,但可能应该在答案中注明,因为如果OP不需要区分Enter/Return,这会容易得多,而如果需要使用这些键执行不同的操作,则过滤器应返回True,否则它将对过滤器和信号做出反应;此外,我认为应该检查日期是否在日历日期范围内。另一个问题:为什么要使用一段时间作为referenceDate?据我所知,它将始终返回显示的当前年/月的第一天(如果我没有遗漏某些内容,则始终是有效日期),对吗?@musicamante我没有对逻辑进行太多分析,我只公开了Qt的私有API的逻辑:好的,我有一些有趣的见解,感谢您指出!问题来自于儒略历法,它“没有”1月1日,考虑到臭名昭著的日期从1582年10月5日跳到14日。您报告的代码依赖于QCalendar,qtalendar将在Qt5.14中提供,但同时,由于Qt5,QDate只支持公历,因此1582年之前的开关和4713b.C.1月1日之前的开关已被删除。被认为是有效的:因此Qt5总是将所有第一天发生的情况报告为有效(而Qt4没有),除非(将)添加QCalendar作为参数。