【问题标题】:How to implement tkinter scrollbars?如何实现 tkinter 滚动条?
【发布时间】:2020-07-07 13:30:57
【问题描述】:

我正在努力使用我的代码来实现水平和垂直滚动条来显示数据框的值。我有两个框架/画布,第一个用于标题,第二个用于值。

到目前为止,我的代码显示了数据框,但我无法正确完成滚动条。 另外,我希望我的水平滚动条同时影响画布,以便我的值和标题一起滚动。但显然标题不能随垂直滚动条滚动(标题应始终保持可见)。

顺便说一句:如果有比 tkinter 更好的库来实现完全可操作的网格,并且具有所有常用功能,我很感兴趣 :)

这是我的代码:

import tkinter as tk
import pandas as pd

df = pd.DataFrame(columns=["header_"+str(i+1) for i in range(10)],
                  data=[["value_"+str(j*10+i+1) for i in range(10)] for j in range(10)])

root = tk.Tk()
root.geometry("1000x500+300+300")

label = tk.Label(root, text="My Label")
label.grid(row=0, column=0, padx=2, sticky=tk.NW)

frame1 = tk.Frame(root)
frame1.grid(row=1, column=0, sticky=tk.NW)

frame2 = tk.Frame(root)
frame2.grid(row=2, column=0, sticky=tk.NW)

canvas1 = tk.Canvas(frame1)
canvas1.grid(row=0, column=0)

canvas2 = tk.Canvas(frame2)
canvas2.grid(row=0, column=0)

# Headers in canvas1
for i in range(df.shape[1]):
    label = tk.Label(canvas1, padx=7, pady=7, borderwidth=1, relief=tk.SOLID, width=10, height=2, text=df.columns[i])
    label.grid(row=0, column=i, sticky='news')

# Values in canvas2
for i in range(df.shape[0]):
    for j in range(df.shape[1]):
        label = tk.Label(canvas2, padx=7, pady=7, borderwidth=1, relief=tk.SOLID, width=10, height=2, text=df.iloc[i, j])
        label.grid(row=i, column=j, sticky='news')

# Create a horizontal scrollbar linked to canvas2
hsbar = tk.Scrollbar(canvas2, orient=tk.HORIZONTAL, command=canvas2.xview)
hsbar.grid(row=1, column=0, sticky=tk.EW)
canvas2.configure(xscrollcommand=hsbar.set)

# Create a vertical scrollbar linked to canvas2
vsbar = tk.Scrollbar(canvas2, orient=tk.VERTICAL, command=canvas2.yview)
vsbar.grid(row=0, column=1, sticky=tk.NS)
canvas2.configure(yscrollcommand=vsbar.set)

root.mainloop()

编辑:我取得了一些进展。 tk.Scrollbar的第一个参数有错误(canvas2而不是frame2,两行固定)我还在代码中添加了最后一个块,带有canvas2窗口管理和bbox。它正在工作,但我需要更多时间和解释才能完全理解它。欢迎对代码的最后一部分发表任何评论。

代码现在是:

import tkinter as tk
import pandas as pd

df = pd.DataFrame(columns=["header_"+str(i+1) for i in range(10)],
                  data=[["value_"+str(j*10+i+1) for i in range(10)] for j in range(10)])

root = tk.Tk()
root.geometry("1000x500+300+300")
root.title("Scrollable Canvas")

label = tk.Label(root, text="My Label")
label.grid(row=0, column=0, padx=2, sticky=tk.NW)

frame1 = tk.Frame(root)
frame1.grid(row=1, column=0, sticky=tk.NW)

canvas1 = tk.Canvas(frame1)
canvas1.grid(row=0, column=0)

# Headers in canvas1
for i in range(df.shape[1]):
    label = tk.Label(canvas1, padx=7, pady=7, borderwidth=1, relief=tk.SOLID, width=10, height=2, text=df.columns[i])
    label.grid(row=0, column=i, sticky='news')

# Create a frame for the canvas2 and scrollbars
frame2 = tk.Frame(root)
frame2.grid(row=2, column=0, sticky=tk.NW)

# Add a canvas2 in that frame
canvas2 = tk.Canvas(frame2)
canvas2.grid(row=0, column=0)

# Create a vertical scrollbar linked to canvas2
vsbar = tk.Scrollbar(frame2, orient=tk.VERTICAL, command=canvas2.yview)
vsbar.grid(row=0, column=1, sticky=tk.NS)
canvas2.configure(yscrollcommand=vsbar.set)

# Create a horizontal scrollbar linked to canvas2
hsbar = tk.Scrollbar(frame2, orient=tk.HORIZONTAL, command=canvas2.xview)
hsbar.grid(row=1, column=0, sticky=tk.EW)
canvas2.configure(xscrollcommand=hsbar.set)

# Create a frame on canvas2 to contain the labels
labels_frame = tk.Frame(canvas2)

# Add the labels to this frame
for i in range(df.shape[0]):
    for j in range(df.shape[1]):
        label = tk.Label(labels_frame, padx=7, pady=7, borderwidth=1, relief=tk.SOLID, width=10, height=2, text=df.iloc[i, j])
        label.grid(row=i, column=j, sticky='news')

# Create canvas2 window to hold the label_frame
canvas2.create_window((0,0), window=labels_frame, anchor=tk.NW)

labels_frame.update_idletasks()  # Needed to make bbox info available
bbox = canvas2.bbox(tk.ALL)  # Get bounding box of canvas2
w, h = bbox[2]-bbox[1], bbox[3]-bbox[1]
canvas2.configure(scrollregion=bbox, width=min(800, w), height=min(400, h))

root.mainloop()

【问题讨论】:

标签: python python-3.x dataframe tkinter scrollbar


【解决方案1】:

我终于想出了一个全新的解决方案,即树形视图。代码并不完美,但它可以运行并且非常有前途:

import tkinter as tk
import pandas as pd

df = pd.DataFrame(columns=["header_"+str(i+1) for i in range(20)],
                  data=[["value_"+str(j*20+i+1) for i in range(20)] for j in range(100)])

win = tk.Tk()
win.geometry("1000x500+300+300")

frame = tk.Frame()
frame.pack(fill='both', expand=True)

# Create a Treeview with dual Scrollbars
tree = tk.ttk.Treeview(frame, show="headings", columns=df.columns)
hsb = tk.Scrollbar(frame, orient="horizontal", command=tree.xview)
vsb = tk.Scrollbar(frame, orient="vertical", command=tree.yview)
tree.configure(xscrollcommand=hsb.set, yscrollcommand=vsb.set)
tree.grid(column=0, row=0, sticky=tk.NSEW)
vsb.grid(column=1, row=0, sticky=tk.NS)
hsb.grid(column=0, row=1, sticky=tk.EW)
frame.grid_columnconfigure(0, weight=1)
frame.grid_rowconfigure(0, weight=1)

for i, header in enumerate(df.columns):
    tree.column(i, width=100, anchor='center')
    tree.heading(i, text=header)
for row in range(df.shape[0]):
    tree.insert('', 'end', values=list(df.iloc[row]))

win.mainloop()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-05
    • 2018-04-25
    • 1970-01-01
    • 1970-01-01
    • 2015-04-03
    • 2016-07-07
    • 2011-02-26
    相关资源
    最近更新 更多