【问题标题】:Freezing the header in a grid with a scrollbar in Tkinter在 Tkinter 中使用滚动条冻结网格中的标题
【发布时间】:2015-12-04 23:56:30
【问题描述】:

所以我最终决定构建一个 GUI,但我陷入了困境,我在互联网上找不到任何东西。
我想要完成的基本上是 Excel 中的“冻结窗格”选项。 我按照this 指南构建了一个可滚动的标签网格。但是我希望在滚动时保留初始网格的标题。 我曾想过制作一个单独的网格并将标题放入其中,但除了bbox 中的(0,0,0,0) 之外我什么也做不了(正确放置它们,因为标题可能很短,而条目可能很长!) .

作为bbox 的替代方案,我曾想过用
title+' '*(len(longest_entry)-len(title)) 之类的东西“扩展”标题,但如果条目列表很大,而且如果我的条目列表可能看起来不那么漂亮,那似乎效率很低由于字符大小不同,条目类似于||||||WWWWWW
在这种情况下,你能帮我处理bbox 吗? (我应该在什么地方使用它?)
或者给我完全不同的想法来做什么?
非常感谢!

很抱歉使用了已弃用的标签,但我找不到合适的标签

【问题讨论】:

  • 对不起,我的语法和拼写不足:D
  • 我想你想要一个固定的列标签行。 x, y, dx, dy = frame.bbox(row=0, column=i) 为您提供第 i 列的像素宽度 dx。由于您无法将标签的像素宽度设置为匹配,我会尝试这样做:将标题标签放在单独的画布上,其宽度是使用 Canvas.create_window 的 dxes 的总和。如果标题标签对于它的列来说太大了,你会得到重叠,但你可以通过将标题标签也放在滚动网格中来防止这种情况发生,因此列宽会考虑标题。

标签: header python tkinter header scrollbar


【解决方案1】:

这是我正在为我的任务列表工作的 GUI,它具有很好的优先级和描述。输入框和标题位于不同的画布上,因此标题不会滚动,输入框会滚动。我无法将标题与条目对齐。短期修复是使用恰好对齐的不同字体。我仍然不知道为什么显式设置宽度不起作用。

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()
#-----------------------------------------------------------------------------

【讨论】:

  • 一个回答说你还没有真正解决这个问题,除了短期黑客之外,应该是一个评论。
  • 我不同意您的意见。我认为这是一个合理的答案。我的答案有效,我已经在一个工具中使用它近三年了。这可能不是最好的答案,但它是一个答案,更好的答案会被投票。如果人们只是浏览了这个问题并看到没有答案,他们可能不会费心去阅读 cmets。然后他们会错过一些可能有用的东西。有时,您的时间或预算已用完,不得不采用不太完美的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-27
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
相关资源
最近更新 更多