Как заморозить панель при изменении размера окна, имеющего фреймы в python, используя tkinter и pack?

Это мой первый пост на stackru. Я наконец отправляю сообщения, потому что я не могу найти это нигде и искал почти 4 часа, но я застрял.

Вот мой пример кода:

import tkinter as tk
from tkinter import *
root = tk.Tk()
root.geometry("600x100+200+200")
leftverticalFrame = Frame(root)
leftverticalFrame.pack(side=LEFT)
middleverticlFrame = Frame(root)
middleverticlFrame.pack(expand=TRUE)
rightverticalFrame = Frame(root)
rightverticalFrame.pack(side=RIGHT)

right = tk.Label(rightverticalFrame, text="Right Vertical Status Frame", bg="yellow")
right.pack(side=tk.RIGHT, fill=BOTH)

left = tk.Label(leftverticalFrame, text = "Left Vertical Navigation Frame", bg="orange")
left.pack(side=tk.LEFT, fill=BOTH)

bottom = tk.Label(middleverticlFrame, text="Middle Vertical Frame", bg="blue")
bottom.pack(side=tk.BOTTOM, expand=True, fill=tk.BOTH)

root.mainloop()

Что я делаю, так это просто пытаюсь расположить кадры по отдельности в корне, потому что они будут использовать разные менеджеры. Левая рамка работает точно так, как я хочу, как и средняя рамка. Проблема с рамкой справа.

Обратите внимание: когда вы изменяете размер окна, делая его более узким, правая рамка попадает на "территорию средней рамки". Теперь странно то, что средний кадр не повторяет того же поведения, когда дело доходит до границы левого кадра. Я хочу, чтобы правильный кадр вел себя так же, как средний кадр. По сути, я пытаюсь сделать левый и правый довольно статичным, но средний кадр более динамичным. Может кто-нибудь сказать мне, что я делаю не так, пожалуйста?

1 ответ

Решение

Важно помнить о pack это то, что side Атрибут не относится к стороне окна, он относится к стороне оставшегося доступного пространства. Причины порядка, в котором вы упаковываете вещи, и стороны, в которую вы их упаковываете, имеют большое значение, потому что каждый раз, когда вы упаковываете что-то, вы меняете местоположение и количество оставшегося свободного места.

В этом случае проблема заключается в том, что вы не указали side атрибут для среднего кадра, поэтому по умолчанию "top" (как в "верхней части оставшегося пространства", а не "верхней части окна"). Поскольку слева уже есть что-то, это помещает его в верхнюю часть оставшегося пространства справа. Затем, когда вы помещаете следующий элемент справа, он справа, но ниже того, что вверху.

Есть как минимум пара способов решить эту проблему. Первый состоит в том, чтобы сначала упаковать левую и правую стороны, а затем упаковать середину. В этом случае не имеет значения, с какой стороны вы положите средний кадр:

leftverticalFrame.pack(side=LEFT)
rightverticalFrame.pack(side=RIGHT)
middleverticlFrame.pack(expand=TRUE, side=TOP)

Второе решение состоит в том, чтобы оставить их в исходном порядке, но упаковать среднюю рамку слева или справа вместо верхней:

leftverticalFrame.pack(side=LEFT)
middleverticlFrame.pack(expand=TRUE, side=LEFT)
rightverticalFrame.pack(side=RIGHT)

Эти два варианта изначально будут выглядеть одинаковыми или, возможно, почти идентичными, в зависимости от того, что еще может быть в кадрах или в окне. Тем не менее, поведение отличается, когда вы начинаете делать окно слишком маленьким, чтобы уместить все кадры.

В таком случае tkinter должен в конечном итоге начать уменьшать размер виджета. Он делает это в обратном порядке, в котором они были упакованы (читай: последний, который должен быть упакован, является первым, который был сжат). Это означает, что если вы хотите, чтобы левый и правый фиксировались как можно больше, вы должны упаковать среднюю часть последней.


Совет от профессионала: он облегчает чтение и поддержку вашего кода, если вы сгруппируете весь код макета вместе. Рассмотрим этот код:

f1 = Frame(...)
f1.pack(...)
f2 = Frame(...)
f2.pack(...)

Я думаю, что со временем вы обнаружите, что ваш код легче читать и поддерживать, если вы напишите его так:

f1 = Frame(...)
f2 = Frame(...)
...
f1.pack(...)
f2.pack(...)
...

Я думаю, что это делает код намного проще для визуализации, поскольку весь макет для данного родительского окна находится в одном месте, а не разбросан по всему коду.

Другие вопросы по тегам