【问题标题】:trying to freeze the labels only while moving horizontally (not while moving vertically) in tkinter GUI尝试仅在 tkinter GUI 中水平移动(而不是垂直移动)时冻结标签
【发布时间】:2021-03-25 02:30:50
【问题描述】:

有一个名为 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)你创建了canvas_s,但你没有显示它,即。 canvas_s.pack() - 所以如果你甚至滚动画布然后你可以看到它(2)你使用place()添加标签所以你不能用canvas移动它。您必须使用 create_window(label,...) 将其添加到画布

标签: python user-interface tkinter frontend


【解决方案1】:

此代码垂直滚动画布和水平滚动更大的画布。

代码混乱,所以我以不同的方式组织代码以进行排序。

首先创建滚动条(两个画布都将使用)

接下来我用画布和内框创建更大的框架。

接下来以同样的方式创建带有画布和内框的较小框架。

接下来我将一些元素添加到内部框架中 - 我在内部框架的顶部和底部添加标签。这样我会看看它是否滚动到最后。

最后我将滚动条分配给画布以移动它们。接下来,我将画布分配给滚动条以将滚动条调整为正确的大小。

它有效

只有一个问题。此时两个框架仅显示画布高度的 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()

【讨论】:

  • 非常感谢。我感谢您的帮助。然而,从上面的图像中我们可以看到,在移动垂直滚动条时,红色(画布)并没有随着滚动条移动。而我想用垂直滚动条移动红色框架(带标签),但不应该用水平滚动条移动它。我想现在很清楚了。
  • 好吧,我似乎理解错了——我在红框内移动对象(在内部画布上)——就像在更大区域的预览中一样。要移动所有红框,您必须使用create_window 将红框直接放在更大的画布上(它会在两个方向上自动移动),并且您需要创建在水平滚动时保持不变的功能 - 它应该向相反的方向移动它 - 当滚动条向左移动更大的画布时,代码必须将红色框向右移动 - 这样它看起来就像它保持原位..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多