Freezing the header in a grid with a scrollbar in Tkinter

别来无恙 提交于 2019-12-12 04:14:55

问题


So I finally decided to build a GUI, but I'm stuck bad, and I can't find anything on the internet.
What I'm trying to acomplish is basically the "freeze panes" option from Excel. I have build a scrollable grid of labels following this guide. But I want the header of the initial grid to stay when I scroll. I have thought of making a separate grid and place the header in it, but I can't anything other than (0,0,0,0) from bbox (to place them right, because the header might be short while the entries might be long!).

As an alternative to bbox I have thought of "expanding" the titles with something like
title+' '*(len(longest_entry)-len(title)), but that seems highly inefficient if the entry list is huge and probably won't look as pretty if my entry is something like |||||| or WWWWWW due to different size of the characters.
Can you help me with bbox in this case? (what should I use it on?)
Or give me totally different ideas of what to do?
Many thanks in advance!

Sorry for using the deprecated tag header, but I couldn't find an appropiate tag


回答1:


This is a GUI I'm working on for my tasks list with priority and description that works pretty well. The entry boxes and headers are on separate canvases so that the header will not scroll and the entry boxes will. I had trouble aligning the headers with the entries. The short term fix was to use different fonts that happen to align. I still don't know why explicitly setting widths did not work.

import Tkinter as Tk
from Tkinter import StringVar
#-----------------------------------------------------------------------------
# Scroll entry boxes with mouse wheel
#     canvas1, frame1
#
# Header row is on a separate canvas and will not scroll with entry boxes.
#     canvas2, frame2
#
# Could not align header and entries unless different fonts were used.
# Play with variable "font_choice" to see how it works
#-----------------------------------------------------------------------------
# define fonts and other preliminary things

font_choice = 1
if(font_choice == 1): # using same font sizes does not align well
    Label_Font = "Arial 10"
    Entry_Font = "Arial 10"
if(font_choice == 2): # using different font sizes not exactly aligned, but close
    Label_Font = "Arial 9 bold" 
    Entry_Font = "Arial 10"
if(font_choice == 3): # this does not align well
    Label_Font = "Helvetica 10"
    Entry_Font = "Helvetica 10"
if(font_choice == 4): # this aligns pretty well (surprisingly)
    Label_Font = "Helvetica 14"
    Entry_Font = "Helvetica 14"

width_priority = 10
width_time_estimate = 15
width_description_1 = 90

Labels = ["Priority", "Time Est. (mins)", "Description 1"]

Widths = [width_priority, width_time_estimate, width_description_1]

Label_Colors = ["misty rose", "lavender", "lightcoral"]

list_length = 25

canvas_width = 1300
header_height = 25
#------------------------------------------------------------------------------
def populate1(framex):
    global entrys_1
    global entrys_2
    global entrys_3

    label_flag = 0 # 1 or 2 are options, 0 is off

    ijk_col = 0
    if(label_flag == 1):
        Tk.Label(framex, text=Labels[ijk_col]).grid(row=0, column=ijk_col)
    if(label_flag== 2):
        xy1 = Tk.Label(framex, text=Labels[ijk_col], font=Label_Font)
        xy1.grid(row=0, column=ijk_col)
        xy1.config(width=Widths[ijk_col], borderwidth="1", background=Label_Colors[ijk_col])
    entrys_1 = []
    variables_1 = []
    ii = 0
    for row in range(list_length):
        rowx = row + 1
        variables_1.append(StringVar())
        entrys_1.append(Tk.Entry(framex, textvariable=variables_1[ii], font=Entry_Font))
        entrys_1[-1].config(width=Widths[ijk_col], borderwidth="1")
        entrys_1[-1].grid(row=rowx, column=ijk_col)
        entrys_1[-1].config(fg="black", bg=Label_Colors[ijk_col])
        entrys_1[-1].delete(0, Tk.END)
        entrys_1[-1].insert(0, "Placeholder")
        ii += 1

    ijk_col = 1
    if(label_flag == 1):
        Tk.Label(framex, text=Labels[ijk_col]).grid(row=0, column=ijk_col)
    if(label_flag== 2):
        xy2 = Tk.Label(framex, text=Labels[ijk_col], font=Label_Font)
        xy2.grid(row=0, column=ijk_col)
        xy2.config(width=Widths[ijk_col], borderwidth="1", background=Label_Colors[ijk_col])
    entrys_2 = []
    variables_2 = []
    ii = 0
    for row in range(list_length):
        rowx = row + 1
        variables_2.append(StringVar())
        entrys_2.append(Tk.Entry(framex, textvariable=variables_2[ii], font=Entry_Font))
        entrys_2[-1].config(width=Widths[ijk_col], borderwidth="1")
        entrys_2[-1].grid(row=rowx, column=ijk_col)
        entrys_2[-1].config(fg="black", bg=Label_Colors[ijk_col])
        entrys_2[-1].delete(0, Tk.END)
        entrys_2[-1].insert(0, "Placeholder")
        ii += 1

    ijk_col = 2
    if(label_flag == 1):
        Tk.Label(framex, text=Labels[ijk_col]).grid(row=0, column=ijk_col)
    if(label_flag== 2):
        xy3 = Tk.Label(framex, text=Labels[ijk_col], font=Label_Font)
        xy3.grid(row=0, column=ijk_col)
        xy3.config(width=Widths[ijk_col], borderwidth="1", background=Label_Colors[ijk_col])
    entrys_3 = []
    variables_3 = []
    ii = 0
    for row in range(list_length):
        rowx = row + 1
        variables_3.append(StringVar())
        entrys_3.append(Tk.Entry(framex, textvariable=variables_3[ii], font=Entry_Font))
        entrys_3[-1].config(width=Widths[ijk_col], borderwidth="1")
        entrys_3[-1].grid(row=rowx, column=ijk_col)
        entrys_3[-1].config(fg="black", bg=Label_Colors[ijk_col])
        entrys_3[-1].delete(0, Tk.END)
        entrys_3[-1].insert(0, "Placeholder")
        ii += 1

def onFrameConfigure(canvas):
    '''Reset the scroll region to encompass the inner frame'''
    canvas.configure(scrollregion=canvas.bbox("all"))
#-----------------------------------------------------------------------------
root = Tk.Tk()
root.title("StackOverflow_Label_Entry_Align")
#---------------------------------
# set up canvas that scrolls for entries, header on separate canvas that does not scroll

canvas1 = Tk.Canvas(root, borderwidth=0, background="#ffffff", height=400, width=canvas_width)
frame1 = Tk.Frame(canvas1, background="#ffffff")

xscrollbar = Tk.Scrollbar(root, orient=Tk.HORIZONTAL, command=canvas1.xview)
yscrollbar = Tk.Scrollbar(root, orient=Tk.VERTICAL, command=canvas1.yview)

yscrollbar.pack(side=Tk.RIGHT, fill=Tk.Y)
xscrollbar.pack(side=Tk.BOTTOM, fill=Tk.X)

canvas1.configure(xscrollcommand=xscrollbar.set)
canvas1.configure(yscrollcommand=yscrollbar.set)

canvas1.pack(side="bottom", fill="both", expand=True)
canvas1.create_window((4,4), window=frame1, anchor="nw")

frame1.bind("<Configure>", lambda event, canvas=canvas1: onFrameConfigure(canvas))

def _on_mousewheel(event):
    canvas1.yview_scroll(-1*(event.delta/120), "units")
canvas1.configure(yscrollincrement='20') # adjust sensitivity
canvas1.bind_all("<MouseWheel>", _on_mousewheel) # Oakley has a post on this

canvas1.focus_set() # key to making canvas bind to left, right keys
#-----------------------------------------------------------------------------
# set up separate canvas for header row that will not scroll

canvas2 = Tk.Canvas(root, borderwidth=0, background="#ffffff", height=header_height, width=canvas_width)
frame2 = Tk.Frame(canvas2, background="#ffffff")

canvas2.pack(side="top", fill="both", expand=True)
canvas2.create_window((0,0), window=frame2, anchor="nw", height=header_height)

x1 = Tk.Label(frame2, text=Labels[0], font=Label_Font)
x1.grid(row=0, column=0)
x1.config(width=Widths[0], borderwidth="1", background=Label_Colors[0])

x2 = Tk.Label(frame2, text=Labels[1], font=Label_Font)
x2.grid(row=0, column=1)
x2.config(width=Widths[1], borderwidth="1", background=Label_Colors[1])

x3 = Tk.Label(frame2, text=Labels[2], font=Label_Font)
x3.grid(row=0, column=2)
x3.config(width=Widths[2], borderwidth="1", background=Label_Colors[2])
#-----------------------------------------------------------------------------
populate1(frame1) # add entry boxes
#-----------------------------------------------------------------------------
root.mainloop()
#-----------------------------------------------------------------------------


来源:https://stackoverflow.com/questions/34099466/freezing-the-header-in-a-grid-with-a-scrollbar-in-tkinter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!