How to implement tkinter scrollbars?

让人想犯罪 __ 提交于 2021-02-11 14:46:21

问题


I'm struggling with my code to implement horizontal and vertical scrollbars to display the values of a dataframe. I have two frames/canvas, the first for the headers, the second for the values.

So far, my code displays the dataframe but I can't finalize the scrollbars properly. Also, I would like my horizontal scrollbar to effect both canevas, so that my values and headers scroll together. But obviously the headers must not scroll with the vertical scrollbar (headers shall always remain visible).

Btw : if there's a better library than tkinter to implement a fully operational grid, with all the usual features around it, I'm interested :)

Here is my code :

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

EDIT : I made some progress. There was a mistake in the first parameter of tk.Scrollbar (canvas2 instead of frame2, two lines fixed) and I also added the last block in the code, with the canvas2 window management and bbox. It's working but I need some more time & explanations to understand it fully. Any comment on this last part of the code would be welcome.

The code is now :

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

回答1:


I finally came up with a brand new solution, with treeview. The code is not perfect but it runs and is very promising :

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


来源:https://stackoverflow.com/questions/60875343/how-to-implement-tkinter-scrollbars

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