我正在尝试创建具有以下属性/功能的自定义日历(Tkinter小部件):
它看起来像这样:
(图像注释:左侧的RED列将是单独的框架小部件。我只是包括在草图中以显示日历中行的用途)
为了能够在构建日历后与单元格进行交互,我计划将每个小部件对象存储在一个名为self.cells
的数组中。
此外,由于我希望它无限地追溯到过去和将来,因此在初始化时,日历滚动条将位于中间。
我的进度(代码)
import tkinter as tk
import datetime
CELL_SIZE = (100, 50)
FIRST_ROW_HEIGHT = 20
class Cell(tk.Canvas):
def __init__(self, root,
width = CELL_SIZE[0],
height = CELL_SIZE[1],
highlightthickness = 1,
background = 'white',
highlightbackground = 'black',
highlightcolor = 'red',
*args, **kwargs):
tk.Canvas.__init__(self, root,
width = width,
height = height,
background = background,
highlightthickness = highlightthickness,
highlightbackground = highlightbackground,
highlightcolor = highlightcolor,
*args, **kwargs)
class Calendar(tk.Frame):
def __init__(self, root, rows=0, *args, **kwargs):
tk.Frame.__init__(self, root, *args, **kwargs)
# create the canvas and frame
self.calendar_canvas = tk.Canvas(self)
self.calendar_frame = tk.Frame(self.calendar_canvas)
self.calendar_canvas.create_window((4,4), window=self.calendar_frame, anchor="nw", tags="self.calendar_frame")
self.calendar_canvas.pack(side="top", fill="both", expand=True)
# building scrollbar
self.scrollbar = tk.Scrollbar(self, orient='horizontal', command=self.calendar_canvas.xview)
self.scrollbar.pack(side="bottom", fill="x")
# hooking up scrollbar
self.calendar_canvas.configure(xscrollcommand=self.scrollbar.set)
self.calendar_frame.bind("<Configure>", self.onFrameConfigure)
# variables
self.rows = rows
self.cells = []
def onFrameConfigure(self, event):
self.calendar_canvas.configure(scrollregion=self.calendar_canvas.bbox("all"))
def set(self, day=0):
today = datetime.date.today()
for i in range(day):
self.cells.append([])
# create first row (indicating the date)
cell = Cell(self.calendar_frame, height=FIRST_ROW_HEIGHT)
cell.grid(row=0, column=i)
# add the date label into the first row
cell.create_text(
CELL_SIZE[0]/2,
FIRST_ROW_HEIGHT/2,
text = (today + datetime.timedelta(days=i)).strftime('%d/%m/%y'))
for c in range(self.rows):
cell = Cell(self.calendar_frame)
cell.grid(row=c+1, column=i)
self.cells[i].append(cell)
Calendar
是我开发中的自定义日历小部件。由于this answer(来自@Ethan Field)的帮助,我设法用滚动条连接了这种类似于电子表格的结构,这也是我的起点(基本代码)。
当前,Calendar
小部件能够通过Calendar.set()
函数创建 n 天(从今天开始)。
您可以使用以下代码尝试小部件:
root = tk.Tk()
calendar = Calendar(root, rows=3)
calendar.set(day=10)
calendar.pack(fill='both', expand=True)
root.mainloop()
如何实现无限滚动效果?我不知道如何使它工作。
addFuture()
函数# under class Calendar:
def addFuture(self, day=0):
today = datetime.date.today()
for i in range(day):
index = i + self.lastColumn
self.cells.append([])
# create first row (indicating the date)
cell = Cell(self.calendar_frame, height=FIRST_ROW_HEIGHT)
cell.grid(row=0, column=index)
# add the date label into the first row
cell.create_text(
CELL_SIZE[0]/2,
FIRST_ROW_HEIGHT/2,
text = (today + datetime.timedelta(days=index)).strftime('[%a] %d/%m/%y'))
for c in range(self.rows):
cell = Cell(self.calendar_frame)
cell.grid(row=c+1, column=index)
self.cells[i].append(cell)
self.lastColumn = self.lastColumn + day
此addFuture()
函数只是稍作修改的set()
函数。 addFuture()
可以被多次调用,并且每次将day
天增加到日历中。只需将滚动条连接起来即可。但是,我应该如何addPast()
?
每当用户拖动滚动条时,就会调用onFrameConfigure
命令,因此我添加了if self.scrollbar.get()[1] > 0.9:
语句,以检查滚动条的x轴是否越来越靠近最右边的 结束。如果是这样,它将执行添加更多天数的功能,并且滚动条以某种方式会自动重新调整比例(我不知道为什么为什么,但是可以使用)。
def onFrameConfigure(self, event):
self.calendar_canvas.configure(scrollregion=self.calendar_canvas.bbox("all"))
if self.scrollbar.get()[1] > 0.9:
self.addFuture(day=10)
因此,我的窗口可以无限滚动到未来。现在,我的问题是如何使其无限滚动到过去(又名左侧)?。
我可以使用以下语句if self.scrollbar.get()[1] < 0.1:
来检测滚动条在左侧附近。但是,我需要的是某种self.addPast()
命令,其功能与self.addFuture()
命令相同,但是(顾名思义)在左边增加了几天。
答案 0 :(得分:1)
您要执行的操作是确保画布始终具有足够的列以向右或向左滚动整个屏幕。首先要做的是从那么多列开始。如果您希望每列为100像素,并且画布本身为400像素,则总共需要包含1200像素的列:左侧4列,可见4列和右侧4列。
接下来,为滚动条创建一个代理-一个自定义命令,每当拖动滚动条时就会调用它。它应该做的第一件事是调用画布的xview
方法来进行实际的滚动。然后,在画布滚动之后,您需要计算是否需要在右侧或左侧添加更多列以始终保持缓冲区。
在右侧或左侧添加任何新列后,您需要重新计算画布的scrollregion
。当您这样做时,tkinter将自动调整滚动条滑块的位置和大小。