問題描述
我目前正在制作一個帶有日歷的待辦事項應用程序.每當用戶在特定日期有事件時,左上角會出現一個紅色圓圈.每當用戶雙擊日期時,我希望它顯示一個包含當天事件信息的新窗口.但是,我無法將信息存儲到每個日期中.我怎樣才能使每個日期都有一個可以存儲事件的列表?
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的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!