попытка заморозить метки только при перемещении по горизонтали (не при перемещении по вертикали) в графическом интерфейсе tkinter

#python #user-interface #tkinter #frontend

#python #пользовательский интерфейс #tkinter #интерфейс

Вопрос:

введите описание изображения здесьСуществует главное окно с именем top_wl. И в нем создается frame_wl. У меня есть набор меток, которые создаются в frame_wl (который находится на canvas_wl), а также я создаю еще один небольшой фрейм (fram_s) в главном окне (top_wl), который находится на отдельном холсте (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. Я не понял, можете ли вы перефразировать. Кроме того, добавьте изображение для пояснения. Мне трудно отслеживать все переменные в вашем вопросе.

2. Надеюсь, теперь все ясно.

3. Я вижу беспорядок в вашем коде, и, возможно, из-за этого я обнаружил две ошибки — (1) вы создаете canvas_s , но не отображаете его ie. canvas_s.pack() — так что, если вы даже прокручиваете холст, вы можете это увидеть (2). вы добавляете метку, используя place() , чтобы вы не могли ее перемещать canvas . Вам нужно будет добавить его в canvas с помощью create_window(label,...)

Ответ №1:

Этот код прокручивает по вертикали как холст, так и по горизонтали только больший холст.

В коде был беспорядок, поэтому я организовал код по-другому, чтобы сделать некоторый порядок.

Сначала создайте полосы прокрутки (которые будут использоваться обоими холстами)

Затем я создаю большую рамку с холстом и внутренней рамкой.

Далее таким же образом я создаю меньшую рамку с холстом и внутренней рамкой.

Затем я добавляю некоторые элементы во внутренние фреймы — как в верхней, так и в нижней части внутреннего фрейма. Таким образом, я увижу, прокручивается ли он до конца.

И, наконец, я назначаю полосы прокрутки canvas для их перемещения. Затем я назначаю canvas полосам прокрутки, чтобы изменить размер полос прокрутки до нужного размера.

И это работает

Есть только одна проблема. На данный момент оба фрейма отображают только 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()
 

введите описание изображения здесь

Комментарии:

1. Большое спасибо. Я ценю вашу помощь. Однако из приведенных выше изображений мы видим, что при перемещении вертикальной полосы прокрутки красный цвет (холст) не перемещается вместе с полосой прокрутки. В то время как я хочу переместить рамку красного цвета (с метками) с помощью вертикальной полосы прокрутки, но ее не следует перемещать с помощью горизонтальной полосы прокрутки. Я думаю, теперь это ясно.

2. ну, кажется, я понимаю это неправильно — я перемещаю объект внутри красной рамки (на внутреннем холсте) — как в предварительном просмотре для большей области. Чтобы переместить всю красную рамку, вам нужно будет поместить красную рамку непосредственно на холст большего размера create_window (и она автоматически переместит ее в обоих направлениях), и вам нужно будет создать функцию, которая сохраняет ее неизменной при прокрутке по горизонтали — она должна перемещать ее в противоположном направлении — когда полоса прокрутки перемещает холст большего размера втогда оставленный код должен был бы переместить красную рамку вправо — и таким образом это выглядело бы так, как будто оно остается на месте..