python - 尝试仅在 tkinter GUI 中水平移动(而不是垂直移动)时冻结标签
问题描述
有一个名为 top_wl 的主窗口。并在其中创建了 frame_wl。我有一组在 frame_wl(位于 canvas_wl 上)中创建的标签,并且我正在主窗口(top_wl)中创建另一个小框架(fram_s),它位于单独的画布(canvas_s)上。在 canvas_s 中创建了另一个框架(名为 frame_s1)。我在 fram_s(小框架)上创建了一个标签。单独为 canvas_wl 设置了一个水平滚动条。我在单个垂直滚动条上设置了 canvas_wl 和 canvas_s(命名为:scroll_bar_v)。这背后的想法是冻结小框架中的标签,同时水平移动它与垂直滚动条一起移动的位置。现在的问题是小框架(fram_s)上的标签在垂直和水平移动时都被冻结了。有人可以帮我解决问题吗?或者请告诉我哪里出错了?
top_wl = tk.Tk()# tk.Tk()
top_wl.title("Work Shop Layout")
fram_wl =tk.Frame(top_wl,width=1500,height=5000,bg = 'khaki1',relief= SUNKEN)
# Creating small frame
fram_s = tk.Frame(top_wl,width = 300,height = 500,bg = 'sky blue')
fram_s.place( x = 15, y = 90)
canvas_s = tk.Canvas(fram_s)
frame_s1 = tk.Frame(canvas_s)
l_12 = tk.Label(fram_s, text = 'Hello There',bd = 2, width = 30,bg = 'white',font = ('Arial',10,'bold'),relief = "solid")
l_12. place(x = 10, y = 30)
# finished samll frame
canvas_wl = tk.Canvas(fram_wl,width=1500,height=4000,bg = 'lime green')
# top frame portion
scroll_bar_v = tk.Scrollbar(fram_wl,orient='vertical')
scroll_bar_v.config(command = canvas_wl.yview )
scroll_bar_h = Scrollbar(fram_wl,orient='horizontal')
scroll_bar_h.config(command = canvas_wl.xview)
scroll_bar_h.pack( side = BOTTOM, fill = X )
t1 = tk.Label(fram_wl)#, text = "Hello There: Number_1",width = 50,height = 100,bg = 'Sky blue',font = ('Arial',10,'bold'),relief = "sunken") #(x = 710, y = 50)
scroll_bar_v.pack( side = RIGHT, fill = Y )
t1.pack(side = RIGHT)
scrollable_frame_wl = tk.Frame(canvas_wl,bg = 'moccasin')#, bg = 'cyan2')
canvas_wl.create_window(0, 0, window=scrollable_frame_wl, anchor='nw')
left_wl = tk.Frame(scrollable_frame_wl, borderwidth=2, height = 5000,width = 10000,relief="sunken") #
left_wl. pack(side = 'left',padx=10, pady=10)
left_wl.pack_propagate(0)
scrollable_frame_wl.update()
canvas_s.configure(yscrollcommand = scroll_bar_h.set,scrollregion = canvas_s.bbox("all"))
canvas_s.create_window((0,0),window =frame_s1, anchor = 'nw' )
canvas_wl.configure(xscrollcommand= scroll_bar_h.set,yscrollcommand= scroll_bar_v.set,scrollregion=canvas_wl.bbox("all"))
canvas_wl.pack(fill = 'both')
fram_wl.pack()
top_wl.mainloop()
解决方案
此代码垂直滚动画布和水平滚动更大的画布。
代码很混乱,所以我以不同的方式组织代码以进行排序。
首先创建滚动条(两个画布都将使用)
接下来我用画布和内框创建更大的框架。
接下来以同样的方式,我用画布和内框创建较小的框架。
接下来,我将一些元素添加到内部框架中 - 我在内部框架的顶部和底部都添加了标签。这样我会看看它是否滚动到最后。
最后,我将滚动条分配给画布以移动它们。接下来,我将画布分配给滚动条以将滚动条调整为正确的大小。
它有效
只有一个问题。此时两个框架仅显示画布高度的 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()
推荐阅读
- gnuplot - gnuplot 的“步骤”样式不接受可变颜色
- mysql - MYSQL - 如何选择具有特定值的行,但仅当它出现一次?
- ios - 在 AVMutableComposition 视频中的多个视频上应用 scaleTimeRange 时遇到问题
- ubuntu - Nginx 位置匹配以 favicon.ico 结尾的所有内容
- python - 尝试使用文本库创建一个连接 4 游戏,然后稍后实现 GUI
- python - Python将图像文件夹lat和lon获取到df
- node.js - 如何处理nodeJS / express中的promise错误
- javascript - 不能在回调中调用 React Hook “useState”。使用 useMediaQuery 响应式 JS 媒体查询
- spring - Spring MVC 项目结构
- android - 当我滑动时,我的应用程序正在调用所有 TabBarView 内容