【问题标题】:Tkinter Non Y scroll header for XY scroll region用于 XY 滚动区域的 Tkinter 非 Y 滚动标题
【发布时间】:2020-08-19 12:18:48
【问题描述】:

我正在寻找一种方法来为可以在 X 方向上滚动但不能在 Y 方向上滚动的表格保留静态标题,同时喜欢可以在 X 和 Y 上滚动的表格。(就像电子表格一样,其中列字母始终可见,或者当您冻结谷歌表格中的一行时)。

对于数据 cols = ["", ""] (list) 和 rows = [{"":"", "":""}, {"":"", "":""}](字典列表)

代码:

    def table_scroll_Y(self, *args):
        self.table_title.yview
        self.table_data.yview
    def build_table(self, cols, data):
        for child in self.tablebase.winfo_children(): # Clear existing table
            child.pack_forget()
            child.destroy()
        colour1 = "#EEEEEE" # sets title colour
        rheight = 1 # sets row height
        rowsize = []

        #Note: self.tku.cFrame(**kwrds) =  Frame(*args) and frame.pack(*args)
        layout1=self.tku.cFrame(self.tablebase, side=LEFT,  fill=BOTH, expand=1, bg="white") #split between table area and scroll bar for fixed Y scroll
        self.Vscroll = Scrollbar(self.tablebase, orient="vertical")
        self.Vscroll.pack(side=RIGHT, fill=Y)
        layout2 = self.tku.cFrame(layout1, side=TOP, fill=BOTH, expand=1, bg="white") #split between table and bottom scroll for fixed X scroll
        self.Hscroll = Scrollbar(layout1, orient="horizontal")
        self.Hscroll.pack(side=BOTTOM, fill=X)

        self.table_title = Canvas(layout2, bg="red", highlightthickness=0, height=10) #X scroll area for Column titles
        self.table_data = Canvas(layout2, bg="blue", highlightthickness=0, yscrollcommand=self.Vscroll.set, xscrollcommand=self.Hscroll.set) # XY scroll area for table data
        self.Vscroll.config(command = self.table_scroll_Y) #configures command for Y on both scroll areas
        self.Hscroll.config(command = self.table_data.xview) #configure command for X on data scroll region

        #crate frames to hold all the widgets
        title_frame = Frame(self.table_title, bg="orange")
        title_frame.pack(padx=15, pady=15, fill=BOTH, expand=1)
        data_frame = Frame(self.table_data, bg="purple")
        data_frame.pack(padx=15, pady=15, fill=BOTH, expand=1)
        
        #create windows and pack widgets
        self.table_title.pack(side=TOP, fill=X, padx=5, pady=5)
        self.table_data.pack(side=TOP, fill=BOTH, expand=1, padx=5, pady=5)
        self.table_title.create_window(0,0, window=title_frame)
        self.table_data.create_window(0,0, window=data_frame)
        self.table_title.config(scrollregion=self.table_title.bbox("all"))
        self.table_data.config(scrollregion=self.table_data.bbox("all"))
        self.table_title.yview_moveto(0) 
        self.table_data.yview_moveto(0)
        self.table_data.xview_moveto(0)

        #Build table column headers
        row = self.tku.cFrame(title_frame, fill=X, borderwidth=1, relief="ridge", highlightbackground="black")
        for item in cols:
            Label(row, text=item, width=len(item)+1, borderwidth=2, relief="groove", heigh=rheight, bg=colour1).pack(side=LEFT, fill=X, expand=1)
            rowsize.append(len(item)+1)

        #Build table data
        i = 0
        for datarow in data:
            row = self.tku.cFrame(data_frame, fill=X, borderwidth=1, relief="ridge", highlightbackground="black")
            for key, value in datarow.items():
                Label(row, text=value, width=rowsize[i], borderwidth=2, relief="groove", heigh=rheight, bg="white").pack(side=LEFT, fill=X, expand=1)
                if i <= len(rowsize):
                    i = 0
                else:
                    i+=1

在我的代码中,滚动条位于正确的位置,但小部件似乎向左偏移了很远,并且偏离了它们所内置框架的顶部(self.tablebase 是一个标准框架,用于保存所有表格内容)。

【问题讨论】:

    标签: python-3.x tkinter tkinter-canvas


    【解决方案1】:

    所以我设法将滚动条重新绑定到它们各自的区域,将 command=canvas.xview 替换为一个完整的 lambda 函数,该函数将它绑定到两个 cavas 对象并将它们一起滚动。

        def table_scroll_X(self, *args): # args = ('moveto', 0-1) and can be used with xview_moveto(pos) command
            self.table_title.xview_moveto(args[1])
            self.table_data.xview_moveto(args[1])
        def build_table(self, cols, data):
            # Clear existing widget so we have a fresh start (used for updating to a new table)
            for child in self.tablebase.winfo_children(): 
                child.pack_forget()
                child.destroy()
            ##---
            colour1 = "#EEEEEE" # sets title colour to a light gray colour
            rheight = 1 # sets row height
            rowsize = [] # used to keep row sizes uniform
            
            #Note: self.tku.cFrame(**kwrds) ==  'frame = Frame(*args)' and 'frame.pack(*args)' with 'return frame', used to make crating common widgets a little quicker.
            
            #split between table area and scroll bar for fixed Y scroll (Prevents scrolling the scrollbar off screen)
            layout1=self.tku.cFrame(self.tablebase, side=LEFT,  fill=BOTH, expand=1, bg="white") 
            self.Vscroll = Scrollbar(self.tablebase, orient="vertical")
            self.Vscroll.pack(side=RIGHT, fill=Y)
            #split between table area and scroll bar for fixed X scroll
            layout2 = self.tku.cFrame(layout1, side=TOP, fill=BOTH, expand=1, bg="white")
            self.Hscroll = Scrollbar(layout1, orient="horizontal")
            self.Hscroll.pack(side=BOTTOM, fill=X)
            
            #create the Canvas objects that can be scrolled
            self.table_title = Canvas(layout2, bg="white", highlightthickness=0, height=25) #X scroll area for Column titles
            self.table_data = Canvas(layout2, bg="white", highlightthickness=0, yscrollcommand=self.Vscroll.set, xscrollcommand=self.Hscroll.set) # X/Y scroll area for table data
            self.Vscroll.config(command = self.table_data.yview) #configures command for Y only on the data (up/down)
            self.Hscroll.config(command = self.table_scroll_X) #configure command for X on data scroll region (left/right)
            
            #crate frames to hold all the widgets
            title_frame = Frame(self.table_title, bg="white")
            title_frame.pack(padx=15, pady=15, fill=BOTH, expand=1)
            data_frame = Frame(self.table_data, bg="white")
            data_frame.pack(padx=15, pady=15, fill=BOTH, expand=1)
            
            #create windows and pack widgets
            self.table_title.pack(side=TOP, fill=X, padx=0, pady=0)
            self.table_data.pack(side=TOP, fill=BOTH, expand=1, padx=0, pady=0)
            title_frame.bind("<Configure>",lambda e: self.table_title.configure(scrollregion=self.table_title.bbox("all")))
            data_frame.bind("<Configure>",lambda e: self.table_data.configure(scrollregion=self.table_data.bbox("all")))
            self.table_title.create_window(0,0, window=title_frame)
            self.table_data.create_window(0,0, window=data_frame)
    
            #Build table column headers
            row = self.tku.cFrame(title_frame, fill=X, borderwidth=1, relief="ridge", highlightbackground="black", side=LEFT)
            i = 0
            for item in cols:
                rowsize.append(math.ceil(len(item)*1.7)) # allows for some text size discrepencys.
                Label(row, text=item, font='TkFixedFont', width=rowsize[i], borderwidth=2, relief="groove", heigh=rheight, bg=colour1).pack(side=LEFT)
                if i <= len(rowsize):
                    i=0
                else:
                    i+=1
            #Build table data
            print(rowsize)
            i = 0
            for datarow in data:
                row = self.tku.cFrame(data_frame, fill=X, borderwidth=1, relief="ridge", highlightbackground="black")
                for key, value in datarow.items():
                    Label(row, text=value, font='TkFixedFont', width=rowsize[i], borderwidth=2, relief="groove", heigh=rheight, bg="white").pack(side=LEFT)
                    if i <= len(rowsize):
                        i=0
                    else:
                        i+=1
            #update the interface to apply sizing and move all scrollbars to 0,0
            self.root.update()
            self.root.update_idletasks()
            self.table_title.yview_moveto(0) 
            self.table_data.yview_moveto(0)
            self.table_title.xview_moveto(0)
            self.table_data.xview_moveto(0)
    

    如果您只想冻结单行或列或两者,这可以重新实现为让滚动条控制多个画布对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多