Ответ 1
Вам нужно использовать grid_columnconfigure
, чтобы дать столбцам средний вес. С большим весом, чем другие столбцы, они будут расширяться и сокращаться, чтобы заполнить любое дополнительное пространство, которое у вас есть. Однако в вашем случае нет необходимости использовать сетку. Все в вашем графическом интерфейсе выровнено по определенным сторонам, для которых pack
является более естественным.
Я покажу, как использовать пакет и сетку, начиная с пакета, так как это проще всего. Даже если вы настаиваете на использовании grid
, прочитайте следующий раздел, чтобы понять, как разбить одну большую проблему с макетом на многие мелкие проблемы с макетом.
Разделить и победить
Лучший способ сделать макет в Tkinter - "разделить и победить". Начните с самых внешних виджетов и получите их точно так, как вы хотите. Затем решайте каждый из них за раз.
В вашем случае у вас есть один внешний вид - основной контейнер. Поскольку это единственный виджет в окне, пакет - это самый простой способ заставить его заполнить весь контейнер. Вы также можете использовать сетку, но для этого требуется небольшая дополнительная работа:
self.main_container = Frame(parent. background="bisque")
self.main_container.pack(side="top", fill="both", expand=True)
Это помогает временно выделять цвета ваших кадров, чтобы вы могли визуализировать их по мере развития. Добавьте только указанный выше код в __init__
, запустите приложение, а затем измените размер окна, чтобы увидеть, что основной фрейм правильно растет и сжимается.
Затем у вас есть два кадра - top_frame и bottom_frame. По их именам и судя по тому, как вы пытались использовать сетку, я предполагаю, что они должны заполнить GUI в направлении x. Кроме того, я предполагаю, что верхний кадр - это своего рода панель инструментов, а нижний фрейм - настоящая "главная" часть вашего графического интерфейса. Таким образом, пусть нижний виджет занимает все лишнее пространство.
Так как они сложены друг на друга, pack
снова является естественным выбором. Добавьте следующий код - и только следующий код - чтобы убедиться, что эти области занимают части окна, которые вы ожидаете, и что они имеют правильное поведение изменения размера.
self.top_frame = Frame(self.main_container, background="green")
self.bottom_frame = Frame(self.main_container, background="yellow")
self.top_frame.pack(side="top", fill="x", expand=False)
self.bottom_frame.pack(side="bottom", fill="both", expand=True)
Далее идут рамки для ярлыков. Опять же, они занимают пространство вдоль краев их контейнера, поэтому pack
имеет наибольший смысл. И снова добавьте только следующий бит кода, запустите свою программу и убедитесь, что все по-прежнему правильно изменяются и заполняют правильные части окна:
self.top_left = Frame(self.top_frame, background="pink")
self.top_right = Frame(self.top_frame, background="blue")
self.top_left.pack(side="left", fill="x", expand=True)
self.top_right.pack(side="right", fill="x", expand=True)
Затем у вас есть ваши "угловые" метки. Опять же, поскольку контейнер представляет собой только один ряд виджетов, pack
упрощает работу. Поскольку вам нужны метки в углах, мы будем устанавливать атрибут sticky
немного по-другому для каждого:
self.top_left_label = Label(self.top_left, text="Top Left")
self.top_right_label = Label(self.top_right, text="Top Right")
self.top_left_label.pack(side="left")
self.top_right_label.pack(side="right")
Наконец, у вас есть текстовый виджет. Он заполняет всю нижнюю рамку, поэтому еще раз pack
наш друг:
self.text_box = Text(self.bottom_frame, height=5, width=40, background="gray")
self.text_box.pack(side="top", fill="both", expand=True)
пакет или сетка?
Вы использовали сетку для своего исходного кода и спросили, как ее исправить. Почему я использовал пакет для своих примеров?
Когда вы используете pack
, все параметры конфигурации могут быть завершены за один раз. С помощью grid
вместе с размещением виджетов в своих контейнерах вы также должны позаботиться о том, чтобы ваши разные столбцы и строки "вес", чтобы они правильно изменяли размер. Когда вы просто складываете виджеты друг на друга или выравниваете их по строке, pack
гораздо проще в использовании.
В моих графических интерфейсах я почти всегда использую комбинацию grid
и pack
. Они оба сильны и преуспевают в разных вещах. Единственное, что нужно запомнить - , и это важно - это то, что вы не можете использовать их в одном родителе. Используя ваш код в качестве примера, вы не можете использовать pack
для кадра top_left и grid
для кадра top_right, так как оба они имеют один и тот же родительский элемент. Однако вы можете смешивать их в одном приложении.
Еще раз, используя сетку
Хорошо, возможно, вы действительно хотите использовать grid
: возможно, это школьное задание, или, может быть, вы просто хотите сосредоточиться на одном менеджере геометрии за раз. Это здорово. Вот как я это сделаю. Опять же, вы должны разделить и победить:
Начните с основного кадра. Замените одно выражение, в котором мы упаковываем основной контейнер со следующими строками. Обратите внимание, что мы должны настроить строки и столбцы для родителя, а не для созданного нами фрейма.
self.main_container.grid(row=0, column=0, sticky="nsew")
self.myParent.grid_rowconfigure(0, weight=1)
self.myParent.grid_columnconfigure(0, weight=1)
Хорошо, теперь для верхнего и нижнего фреймов. Удалите pack
и добавьте следующие строки. У вас все еще есть только один столбец, но на этот раз есть пара строк. Обратите внимание, какая строка имеет вес 1:
self.top_frame.grid(row=0, column=0, sticky="ew")
self.bottom_frame.grid(row=1, column=0,sticky="nsew")
self.main_container.grid_rowconfigure(1, weight=1)
self.main_container.grid_columnconfigure(0, weight=1)
Угловые рамы - наконец, контейнер с более чем одним столбцом! Позвольте создать третий столбец посередине, чтобы занять всю слабину. Замените операторы pack
следующим образом, обращая пристальное внимание на то, что дано "вес":
self.top_left.grid(row=0, column=0, sticky="w")
self.top_right.grid(row=0, column=2, sticky="e")
self.top_frame.grid_columnconfigure(1, weight=1)
Далее, метки в их кадрах. Поскольку мы не нуждаемся в их расширении, мы можем сохранить вес по умолчанию равным нулю. Вы можете счесть странным, что обе метки находятся в нулевом столбце. Помните, что они находятся у разных родителей, и они являются единственными виджетами в их родителях, поэтому в каждой из них есть только один столбец:
self.top_left_label.grid(row=0, column=0, sticky="w")
self.top_right_label.grid(row=0, column=0, sticky="e")
Наконец, у нас есть текстовый виджет, который является единственным виджетами в нижнем фрейме. Замените заключительные операторы pack
следующим образом:
self.text_box.grid(row=0, column=0, sticky="nsew")
self.bottom_frame.grid_rowconfigure(0, weight=1)
self.bottom_frame.grid_columnconfigure(0, weight=1)
Заключение
Разметка виджета проста, но вы должны быть систематически об этом. Подумайте, что вы делаете, организуйте свои виджеты в группы, а затем занимайтесь группами по одному. Когда вы это сделаете, должно стать очевидным, какой менеджер геометрии вы должны использовать.
Как вы можете видеть, grid
требует еще несколько строк кода, но это правильный выбор, когда у вас действительно есть сетка. В вашем случае вы уже разделили свой графический интерфейс на разделы, и поэтому, хотя конечный результат был сеткой, каждая секция была либо упакована сверху, либо под другим, либо левым или правым краем. В этих случаях pack
немного проще в использовании, так как вам не нужно беспокоиться о весах строк и столбцов.