python tkinter滚动Frame组件+表格框组件

本文章效果图:

要让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

制作不易,感谢阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值