此代码垂直滚动画布和水平滚动更大的画布。
代码混乱,所以我以不同的方式组织代码以进行排序。
首先创建滚动条(两个画布都将使用)
接下来我用画布和内框创建更大的框架。
接下来以同样的方式创建带有画布和内框的较小框架。
接下来我将一些元素添加到内部框架中 - 我在内部框架的顶部和底部添加标签。这样我会看看它是否滚动到最后。
最后我将滚动条分配给画布以移动它们。接下来,我将画布分配给滚动条以将滚动条调整为正确的大小。
它有效
只有一个问题。此时两个框架仅显示画布高度的 1/3 - 因此垂直滚动条需要显示具有相同大小(1/3 高度)的滑块 - 但是当您调整窗口大小时,更大的框架显示更多画布,滚动条也显示更长的滑块但是较小的框架仍然显示 1/3 的画布,它需要更小的滑块 - 这会产生冲突。它将在短时间内显示较长的滑块(对于较大的帧)和下一个较长的滑块以较长时间(对于较短的帧)。向下滚动时调整大小也会产生问题 - 首先它会在较大的框架中显示底部标签,但它仍然需要鼠标移动才能在较小的框架中显示底部标签。
我没有看到这个冲突的好的解决方案 - 最终你将不得不调整较小的框架以显示相同的画布比例。
import tkinter as tk
top_wl = tk.Tk()
top_wl.title("Work Shop Layout")
# --- scrolls outside big frame (directly in window) ---
scroll_bar_v = tk.Scrollbar(top_wl, orient='vertical')
scroll_bar_v.pack(side='right', fill='y')
scroll_bar_h = tk.Scrollbar(top_wl, orient='horizontal')
scroll_bar_h.pack(side='bottom', fill='x')
# --- big frame (directly in window) ---
# external frame
fram_wl = tk.Frame(top_wl, width=500, height=500, bg='khaki1', relief='sunken')
fram_wl.pack(side='right', expand=True, fill='both')
fram_wl.pack_propagate(False) # don't resize external frame to canvas size
# inne canvas with size bigger then external frame
canvas_wl = tk.Canvas(fram_wl, width=1500, height=1500, bg='lime green')
canvas_wl.pack(fill='both')
# inner frame with size bigger then frame (scrollbars will use this size to scroll it)
scrollable_frame_wl = tk.Frame(canvas_wl, width=1500, height=1500, bg='moccasin')#, bg = 'cyan2')
canvas_wl.create_window(0, 0, window=scrollable_frame_wl, anchor='nw')
# --- small frame (inside big frame so it doesn't hide scrollbars when window is smaller) ---
# external frame
#fram_s = tk.Frame(top_wl, width=300, height=300, bg='sky blue') # when it is directly in top_wl then it may hide scrollbars when window is smaller
fram_s = tk.Frame(fram_wl, width=300, height=300, bg='sky blue')
fram_s.place(x=0, y=100)
fram_s.pack_propagate(False) # don't resize external frame to canvas size
# inne canvas with size bigger then external frame
canvas_s = tk.Canvas(fram_s, width=900, height=900, bg='blue')
canvas_s.pack()
# inner frame with size bigger then frame (scrollbars will use this size to scroll it)
scrollable_frame_s = tk.Frame(canvas_s, width=900, height=900, bg='red')#, bg = 'cyan2')
canvas_s.create_window(0, 0, window=scrollable_frame_s, anchor='nw')
# ---
# add to inner frame in frame WL
label_wl_1 = tk.Label(scrollable_frame_wl, text='WL-Frame Top', bd=2, width=30, bg='white', font=('Arial', 10, 'bold'), relief="solid")
label_wl_1.place(x=10, y=30)
label_wl_2 = tk.Label(scrollable_frame_wl, text='WL-Frame Bottom', bd=2, width=30, bg='white', font=('Arial', 10, 'bold'), relief="solid")
label_wl_2.place(x=10, y=1500-30)
#label_wl_1.pack()
# add to inner frame in frame S
label_s_1 = tk.Label(scrollable_frame_s, text='S-Frame Top', bd=2, width=30, bg='white', font=('Arial', 10, 'bold'), relief="solid")
label_s_1.place(x=10, y=30)
label_s_2 = tk.Label(scrollable_frame_s, text='S-Frame Bottom', bd=2, width=30, bg='white', font=('Arial', 10, 'bold'), relief="solid")
label_s_2.place(x=10, y=900-30)
#label_s_1.pack()
# --- set scrollbars to move canvas ---
# to scroll vertically both canvas
def scroll_two_canvas(*args):
#print(args)
canvas_s.yview(*args)
canvas_wl.yview(*args)
scroll_bar_v.config(command=scroll_two_canvas) # it has to scroll two canvas
# to scroll horizontally one one canvas
scroll_bar_h.config(command=canvas_wl.xview) # it scroll only one canvas
# --- set canvas to resize scrollbars ---
# to update scrollbars when canvas is moved
canvas_wl.configure(xscrollcommand=scroll_bar_h.set)
canvas_wl.configure(yscrollcommand=scroll_bar_v.set)
# do't use it because it will conflict with previous
#canvas_s.configure(yscrollcommand=scroll_bar_v.set)
# get current size of element on canvas - if elements on canvas may change size (inner frame can change size) then you may need `bind('<Configure>')`
canvas_wl.configure(scrollregion=canvas_wl.bbox("all"))
canvas_s.configure(scrollregion=canvas_s.bbox("all"))
#def update_config(event):
# print(event)
# canvas_wl.configure(scrollregion=canvas_wl.bbox("all"))
# canvas_s.configure(scrollregion=canvas_s.bbox("all"))
#top_wl.bind('<Configure>', update_config)
# ---
top_wl.mainloop()
编辑:
当大框架改变高度时调整小框架大小的代码。这样,两个框架显示相同百分比的画布高度,滚动条效果更好。
import tkinter as tk
top_wl = tk.Tk()
top_wl.title("Work Shop Layout")
# --- scrolls outside big frame (directly in window) ---
scroll_bar_v = tk.Scrollbar(top_wl, orient='vertical')
scroll_bar_v.pack(side='right', fill='y')
scroll_bar_h = tk.Scrollbar(top_wl, orient='horizontal')
scroll_bar_h.pack(side='bottom', fill='x')
# --- big frame (directly in window) ---
# external frame
fram_wl = tk.Frame(top_wl, width=500, height=500, bg='khaki1', relief='sunken')
fram_wl.pack(side='right', expand=True, fill='both')
fram_wl.pack_propagate(False) # don't resize external frame to canvas size
# inne canvas with size bigger then external frame
canvas_wl = tk.Canvas(fram_wl, width=1500, height=1500, bg='lime green')
canvas_wl.pack(fill='both')
# inner frame with size bigger then frame (scrollbars will use this size to scroll it)
scrollable_frame_wl = tk.Frame(canvas_wl, width=1500, height=1500, bg='moccasin')#, bg = 'cyan2')
canvas_wl.create_window(0, 0, window=scrollable_frame_wl, anchor='nw')
# --- small frame (inside big frame so it doesn't hide scrollbars when window is smaller) ---
# external frame
#fram_s = tk.Frame(top_wl, width=300, height=300, bg='sky blue') # when it is directly in top_wl then it may hide scrollbars when window is smaller
fram_s = tk.Frame(fram_wl, width=300, height=300, bg='sky blue')
fram_s.place(x=0, y=100)
fram_s.pack_propagate(False) # don't resize external frame to canvas size
# inne canvas with size bigger then external frame
canvas_s = tk.Canvas(fram_s, width=900, height=900, bg='blue')
canvas_s.pack()
# inner frame with size bigger then frame (scrollbars will use this size to scroll it)
scrollable_frame_s = tk.Frame(canvas_s, width=900, height=900, bg='red')#, bg = 'cyan2')
canvas_s.create_window(0, 0, window=scrollable_frame_s, anchor='nw')
# ---
# add to inner frame in frame WL
label_wl_1 = tk.Label(scrollable_frame_wl, text='WL-Frame Top', bd=2, width=30, bg='white', font=('Arial', 10, 'bold'), relief="solid")
label_wl_1.place(x=10, y=30)
label_wl_2 = tk.Label(scrollable_frame_wl, text='WL-Frame Bottom', bd=2, width=30, bg='white', font=('Arial', 10, 'bold'), relief="solid")
label_wl_2.place(x=10, y=1500-30)
#label_wl_1.pack()
# add to inner frame in frame S
label_s_1 = tk.Label(scrollable_frame_s, text='S-Frame Top', bd=2, width=30, bg='white', font=('Arial', 10, 'bold'), relief="solid")
label_s_1.place(x=10, y=30)
label_s_2 = tk.Label(scrollable_frame_s, text='S-Frame Bottom', bd=2, width=30, bg='white', font=('Arial', 10, 'bold'), relief="solid")
label_s_2.place(x=10, y=900-30)
#label_s_1.pack()
# --- set scrollbars to move canvas ---
# to scroll both canvas
def scroll_two_canvas(*args):
#print(args)
canvas_s.yview(*args)
canvas_wl.yview(*args)
scroll_bar_v.config(command=scroll_two_canvas) # it has to scroll two canvas
scroll_bar_h.config(command=canvas_wl.xview) # it scroll only one canvas
# --- set canvas to resize scrollbars ---
# to update scrollbars when canvas is moved
canvas_wl.configure(xscrollcommand=scroll_bar_h.set)
canvas_wl.configure(yscrollcommand=scroll_bar_v.set)
# do't use it because it will conflict with previous
#canvas_s.configure(yscrollcommand=scroll_bar_v.set)
# get current size of element on canvas - if elements on canvas may change size (inner frame can change size) then you may need `bind('<Configure>')`
canvas_wl.configure(scrollregion=canvas_wl.bbox("all"))
canvas_s.configure(scrollregion=canvas_s.bbox("all"))
# --- resize smaller frame when bigger frame changes height
# to keep current height and compare with new height when resize, and to calculate scale used to resize smaller framer
frame_wl_height = fram_wl['height']
def update_config(event):
global frame_wl_height
if event.widget == fram_wl: #'.':
scale = event.height/frame_wl_height
frame_wl_height = event.height
fram_s['height'] = fram_s['height'] * scale
#canvas_wl.configure(scrollregion=canvas_wl.bbox("all"))
#canvas_s.configure(scrollregion=canvas_s.bbox("all"))
top_wl.bind('<Configure>', update_config)
# ---
top_wl.mainloop()