【问题标题】:Event Calendar overwriting weeks事件日历覆盖周
【发布时间】:2026-01-28 01:45:02
【问题描述】:

我正在尝试制作一个日历,让您可以查看何时有活动。活动是从约会.txt 中读取的

约会.txt的示例内容

Sally Banks,11/3/2020,2:45
Sally Banks,20/3/2020,2:45
Sally Banks,21/3/2020,2:45

如您所见,约会的姓名、日期和时间都已存储。我已经唯一标识了用户,所以我现在要做的就是显示他们的事件。

预期输出

如果它代表的日期有与之关联的约会,我希望输出的日历有一个红色按钮。例如

实际输出

使用此代码,我非常接近让它工作:

for w, week in enumerate(self.cal.monthdayscalendar(y, m), 2):
    #If appointment on
    for dayInt,monthInt,yearInt in appointments:
        #Is their an appointment this week?
        appWeek = False

        #There is an appointment this week
        if (int(dayInt) in week) and int(monthInt)==m and int(yearInt) ==y:
            appWeek=True
            bookedDays.append(int(dayInt))
            print(bookedDays)
            for d, day in enumerate(week):
                if day in bookedDays:
                    b = tk.Button(self.parent, width=1, bg="red", text=day,
                                  command=lambda day=day: self.selection(day, calendar.day_name[(day) % 7]))
                    self.wid.append(b)
                    b.grid(row=w, column=d)
                else :
                    # print(calendar.day_name[day])
                    b = tk.Button(self.parent, width=1,bg=self.COLOR_OF_DAY_BUTTONS, text=day,
                                    command=lambda day=day: self.selection(day, calendar.day_name[(day) % 7]))
                    self.wid.append(b)
                    b.grid(row=w, column=d)
        #There is an appointment this week, so avoid placing buttons
        elif appWeek == True:
            #Avoid unnecessary re changing of buttons
            pass
        #No appointment so make this line lightblue.
        else:
            #No appointment this week
            for w, week in enumerate(self.cal.monthdayscalendar(y, m), 2):
                for d, day in enumerate(week):
                    if day:
                        # print(calendar.day_name[day])
                        b = tk.Button(self.parent, width=1, bg=self.COLOR_OF_DAY_BUTTONS, text=day,
                              command=lambda day=day: self.selection(day, calendar.day_name[(day) % 7]))
                        self.wid.append(b)
                        b.grid(row=w, column=d)
    # Reset bookedDays in order to allow for multiple appointments on the same day
    bookedDays=[]

我得到这个输出,一个没有红色按钮的空白日历

但是,如果我使用 elif 和 else 语句,例如这样:

for w, week in enumerate(self.cal.monthdayscalendar(y, m), 2):
    #If appointment on
    for dayInt,monthInt,yearInt in appointments:
        #Appointment this week
        appWeek = False
        if (int(dayInt) in week) and int(monthInt)==m and int(yearInt) ==y:
            appWeek=True
            bookedDays.append(int(dayInt))
            print(bookedDays)
            for d, day in enumerate(week):
                if day in bookedDays:
                    b = tk.Button(self.parent, width=1, bg="red", text=day,
                                  command=lambda day=day: self.selection(day, calendar.day_name[(day) % 7]))
                    self.wid.append(b)
                    b.grid(row=w, column=d)
                else :
                    # print(calendar.day_name[day])
                    b = tk.Button(self.parent, width=1,bg=self.COLOR_OF_DAY_BUTTONS, text=day,
                                    command=lambda day=day: self.selection(day, calendar.day_name[(day) % 7]))
                    self.wid.append(b)
                    b.grid(row=w, column=d)
        """
        elif appWeek == True:
            #Avoid unnecessary re changing of buttons
            pass
        else:
            #No appointment this week
            for w, week in enumerate(self.cal.monthdayscalendar(y, m), 2):
                for d, day in enumerate(week):
                    if day:
                        # print(calendar.day_name[day])
                        b = tk.Button(self.parent, width=1, bg=self.COLOR_OF_DAY_BUTTONS, text=day,
                              command=lambda day=day: self.selection(day, calendar.day_name[(day) % 7]))
                        self.wid.append(b)
                        b.grid(row=w, column=d)
    # Reset bookedDays in order to allow for multiple appointments on the same day
    bookedDays=[]
    """

我得到这个输出:

正如您在此输出中看到的那样,我在有约会的几周内得到了正确的行,但我没有得到任何没有约会的星期。更改月份会导致没有新的日子(没有按钮)。

我不确定如何继续。我认为问题在于日历会覆盖一周中的每一天。如果您需要完整的类文件,我很乐意也给您。

整个类文件 有人向我要了整个类文件,所以在这里

import calendar
import datetime
import sys
import csv

# imports correct version of tkinter based on python version
if sys.version[0] == '2':
    import Tkinter as tk
else:
    import tkinter as tk


class CalendarView:
    # Instantiation
    def __init__(self, parent, values):
        self.values = values
        print(values)
        self.parent = parent
        self.cal = calendar.TextCalendar(calendar.SUNDAY)
        self.year = datetime.date.today().year
        self.month = datetime.date.today().month
        self.wid = []
        self.day_selected = 1
        self.month_selected = self.month
        self.year_selected = self.year
        self.day_name = ''
        self.COLOR_OF_CALENDAR_ARROWS = "lightblue"
        self.COLOR_OF_CALENDAR_LABEL = "lightblue"
        self.COLOR_OF_DAY_BUTTONS = "lightblue"

        self.setup(self.year, self.month)

    # Resets the buttons
    def clear(self):
        for w in self.wid[:]:
            w.grid_forget()
            # w.destroy()
            self.wid.remove(w)

    # Moves to previous month/year on calendar
    def go_prev(self):
        if self.month > 1:
            self.month -= 1
        else:
            self.month = 12
            self.year -= 1
        # self.selected = (self.month, self.year)
        self.clear()
        self.setup(self.year, self.month)

    # Moves to next month/year on calendar
    def go_next(self):
        if self.month < 12:
            self.month += 1
        else:
            self.month = 1
            self.year += 1

        # self.selected = (self.month, self.year)
        self.clear()
        self.setup(self.year, self.month)

    # Called on date button press
    def selection(self, day, name):
        self.day_selected = day
        self.month_selected = self.month
        self.year_selected = self.year
        self.day_name = name

        # Obtaining data
        self.values['day_selected'] = day
        self.values['month_selected'] = self.month
        self.values['year_selected'] = self.year
        self.values['day_name'] = name
        self.values['month_name'] = calendar.month_name[self.month_selected]

        self.clear()
        self.setup(self.year, self.month)

    def setup(self, y, m):
        # Tkinter creation
        left = tk.Button(self.parent, text='<', command=self.go_prev,bg=self.COLOR_OF_CALENDAR_ARROWS)
        self.wid.append(left)
        left.grid(row=0, column=1)

        header = tk.Label(self.parent, height=2,bg=self.COLOR_OF_CALENDAR_LABEL, text='{}   {}'.format(calendar.month_abbr[m], str(y)))
        self.wid.append(header)
        header.grid(row=0, column=2, columnspan=3)

        right = tk.Button(self.parent, text='>', command=self.go_next,bg=self.COLOR_OF_CALENDAR_ARROWS)
        self.wid.append(right)
        right.grid(row=0, column=5)

        days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
        for num, name in enumerate(days):
            t = tk.Label(self.parent, text=name[:3],bg=self.COLOR_OF_CALENDAR_LABEL)
            self.wid.append(t)
            t.grid(row=1, column=num)
        #Read Appointments
        appointments=[]
        bookedDays=[]
        with open("appointments.txt", 'r') as appFile:
            reader = csv.reader(appFile)
            for row in reader:
                # removes empty list from loop
                if len(row) > 0:
                    #Check for appointments made by this user
                    if row[0] in self.values:
                        print("yep")
                        #Parse the date into day,month,year
                        dayInt,monthInt,yearInt = row[1].split("/")
                        appointments.append([dayInt,monthInt,yearInt])

        for w, week in enumerate(self.cal.monthdayscalendar(y, m), 2):
            #If appointment on
            for dayInt,monthInt,yearInt in appointments:
                #Appointment this week
                appWeek = False
                if (int(dayInt) in week) and int(monthInt)==m and int(yearInt) ==y:
                    appWeek=True
                    bookedDays.append(int(dayInt))
                    print(bookedDays)
                    for d, day in enumerate(week):
                        if day in bookedDays:
                            b = tk.Button(self.parent, width=1, bg="red", text=day,
                                          command=lambda day=day: self.selection(day, calendar.day_name[(day) % 7]))
                            self.wid.append(b)
                            b.grid(row=w, column=d)
                        else :
                            # print(calendar.day_name[day])
                            b = tk.Button(self.parent, width=1,bg=self.COLOR_OF_DAY_BUTTONS, text=day,
                                            command=lambda day=day: self.selection(day, calendar.day_name[(day) % 7]))
                            self.wid.append(b)
                            b.grid(row=w, column=d)
                """
                elif appWeek == True:
                    #Avoid unnecessary re changing of buttons
                    pass
                else:
                    #No appointment this week
                    for w, week in enumerate(self.cal.monthdayscalendar(y, m), 2):
                        for d, day in enumerate(week):
                            if day:
                                # print(calendar.day_name[day])
                                b = tk.Button(self.parent, width=1, bg=self.COLOR_OF_DAY_BUTTONS, text=day,
                                      command=lambda day=day: self.selection(day, calendar.day_name[(day) % 7]))
                                self.wid.append(b)
                                b.grid(row=w, column=d)
            # Reset bookedDays in order to allow for multiple appointments on the same day
            bookedDays=[]
            """


        sel = tk.Label(self.parent, height=2,bg=self.COLOR_OF_CALENDAR_LABEL, text='{} {} {} {}'.format(
            self.day_name, calendar.month_name[self.month_selected], self.day_selected, self.year_selected))
        self.wid.append(sel)
        sel.grid(row=8, column=0, columnspan=7)

    # Quit out of the calendar and terminate tkinter instance.
    def kill_and_save(self):
        self.parent.destroy()

【问题讨论】:

    标签: python tkinter logic


    【解决方案1】:

    如果我的理解是正确的,appointments 是一个元组列表:

    [(11, 3, 2020), (20, 3, 2020), (21, 3, 2020)]
    

    所以我建议检查每个日历日是否在如下约会中:

    import tkinter as tk
    import calendar
    
    class CalendarApp(tk.Frame):
        def __init__(self, parent):
            super().__init__(parent)
            self.parent = parent
            self.cal = calendar.Calendar(calendar.SUNDAY)
            self.COLOR_OF_DAY_BUTTONS = '#abcdef'
            self.show_calendar(2020, 3)
    
        def selection(self, day, day_name):
            pass
    
        def show_calendar(self, y, m):
            appointments = [
                (11, 3, 2020),
                (20, 3, 2020),
                (21, 3, 2020),
            ]
            for w, week in enumerate(self.cal.monthdayscalendar(y, m), 2):
                for d, day in enumerate(week):
                    if day:
                        # determine the color of current calendar day
                        color = 'red' if (day, m, y) in appointments else self.COLOR_OF_DAY_BUTTONS
                        btn = tk.Button(self.parent, text=day, bg=color,
                                        command=lambda day=day: self.selection(day, calendar.day_name[day%7]))
                        btn.grid(row=w, column=d, sticky='nsew')
    
    root = tk.Tk()
    app = CalendarApp(root)
    root.mainloop()
    

    更新:将解决方案修改为可运行的示例,输出如下:

    【讨论】:

    • 您建议的解决方案导致没有红色按钮出现,并且一些日历日被重复。
    • 我已将我的解决方案更新为一个最小的可运行示例。我不知道你为什么说没有显示红色按钮
    • 感谢上传示例