本文章效果图:
要让Frame滚动,最好的办法就是使用Canvas+Frame,下面给出一个封装好的ScrollFrame类:
class ScrollFrame(tk.Frame):
def __init__(self,master,width = 100,height = 100,**kw):
self.frame = tk.Frame(master,**kw)
self.width = width
self.height = height
self.is_use_mwsl = False
if self.is_use_mwsl:
self.mwsl = self.get_wheel_scroll_lines()
self.canvas = tk.Canvas(self.frame) # 创建画布
self.canvas.grid()
self.scrolly=tk.Scrollbar(self.frame,orient="vertical",command=self.canvas.yview) #创建滚动条
self.scrolly.grid(row = 0,column = 1,sticky = "ns")
self.canvas.configure(yscrollcommand=self.scrolly.set)
super().__init__(self.canvas) # 在画布上创建frame
self.canvas.create_window((0,0),window=self,anchor='nw') # 要用create_window才能跟随画布滚动
self.bind("<Configure>",self.updCanvas)
self.canvas.grid(row = 0,column = 0,sticky = "nwse")
self.rowconfigure(0,weight = 1)
self.columnconfigure(0,weight = 1)
self.canvas.bind("<MouseWheel>",self.wheelBind)
def syncColor(self,event = None):
self.canvas.config(bg = self.cget("bg"))
def get_wheel_scroll_lines(self):
SPI_GETWHEELSCROLLLINES = 0x0068
user32 = ctypes.windll.user32
buf = wintypes.INT()
result = user32.SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, ctypes.byref(buf), 0)
if result:
return buf.value
else:
raise Exception("Failed to get wheel scroll lines")
def wheelBind(self,event):
if not self.is_use_mwsl:
self.canvas.yview_scroll(-event.delta // 120, "units")
else:
self.canvas.yview_scroll(-event.delta // 120 * self.mwsl, "units")
def updCanvas(self,event):
self.canvas.config(bg = self.cget("bg"))
self.canvas.configure(scrollregion=self.canvas.bbox("all"),width = self.width,height = self.height)
self.update()
def add(self,mod,**kw):
mod.grid(**kw)
def grid(self,**kw):
tk.Grid.grid_configure(self.frame,**kw)
使用示例:
scf = ScrollFrame(win,width = 600,height = 500,bd = 1,relief = "sunken")
scf.grid(sticky = "nesw")
for i in [tk.Button(scf,text = i) for i in range(100)]:
scf.add(i,sticky = "we")
scf.add(i,sticky = "we")
scf.add(i,sticky = "we")
展示:
(标题栏颜色是因为gif渲染的时候导致的,本来是白的,如果要自定义标题栏请看上次的文章Python tkinter自定义标题栏-示例-CSDN博客)
通过继承这个ScrollFrame,还可以实现以下操作:
class Chart(ScrollFrame):
def __init__(self,master,title = [],value = [],bg = "white",fg = "black",font = ("",10),linesNum = True,**kw):
super().__init__(master,**kw)
self.title = title
self.value = value
self.linesNum = linesNum
self.bg = bg
self.fg = fg
self.font = font
self.config(bg = self.bg)
self.buttonStyle = ttk.Style()
self.labelStyle = ttk.Style()
self.buttonStyle.configure("My.TButton",bg = bg,fg = fg)
self.labelStyle.configure("My.TLabel",bg = bg,fg = fg)
if self.title:
self.draw()
def draw(self):
normallinecolumn = 0
if self.linesNum:
for i in range(len(self.value)):
self.add(tk.Label(self,text = i + 1,bg = self.bg,fg = self.fg,font = (*self.font,"bold")),row = i * 2 + 3,column = 0)
normallinecolumn = 1
for i in range(len(self.title)):
self.add(tk.Label(self,text = self.title[i],bg = self.bg,fg = self.fg,font = (*self.font,"bold")),row = 0,column = i * 2 + normallinecolumn * 3)
self.add(ttk.Separator(self,orient = tk.VERTICAL),row = 0,column = i * 2 + 1 + normallinecolumn * 3,sticky = "ns",rowspan = len(self.value) * 2 + normallinecolumn * 3)
self.add(ttk.Separator(self,orient = tk.HORIZONTAL),row = 1,column = 0,columnspan = len(self.title) * 2 + normallinecolumn * 3,sticky = "we")
self.add(ttk.Separator(self,orient = tk.HORIZONTAL),row = 2,column = 0,columnspan = len(self.title) * 2 + normallinecolumn * 3,sticky = "we")
if self.linesNum:
self.add(ttk.Separator(self,orient = tk.VERTICAL),row = 0,column = 1,rowspan = len(self.value) * 2 + normallinecolumn * 3,sticky = "ns")
self.add(ttk.Separator(self,orient = tk.VERTICAL),row = 0,column = 2,rowspan = len(self.value) * 2 + normallinecolumn * 3,sticky = "ns")
for i in range(len(self.value)):
for o in range(len(self.value[i])):
self.add(tk.Label(self,text = self.value[i][o],bg = self.bg,fg = self.fg,font = self.font),row = i * 2 + 3,column = o * 2 + normallinecolumn * 3)
self.add(ttk.Separator(self,orient = tk.HORIZONTAL),row = i * 2 + 4,column = 0,columnspan = len(self.title) * 2 + normallinecolumn * 3,sticky = "we")
cht = Chart(win,bg = "white",fg = "blue",title = random.sample(list(range(0,100)),k = 10),value = [random.sample(list(range(0,100)),k = 10) for _ in range(0,100)],
width = 500,height = 300)
cht.grid(row = 1,column = 0,sticky = "nsew")
运行效果:
现在还有个问题就是表格框滚动鼠标滚轮的时候到最上面可能会滚动不上去,要往下一下再重新向上滚动才可以恢复。还有就是数据太多导致的窗口卡顿
备注:本文需要导入的库:
import tkinter as tk from tkinter import ttk import random import ctypes from ctypes import wintypes
制作不易,感谢阅读!