Tkinter Grid: как размещать виджетов, чтобы они не склеивались

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

В своих исследованиях я нашел предложения использовать липкие, padx и pady варианты. Но независимо от того, какие аргументы я передаю .grid (), я не могу создать пространство между моими виджетами. Я понимаю, что независимо от количества столбцов и строк между двумя виджетами, если указанные строки / столбцы пустые, то, как если бы они не существовали, а виджеты отображались вместе.

Используя метод .grid (), как я могу размещать виджеты так, чтобы они не склеивались?

Вот мой код:

#!/usr/bin/python from Tkinter import * class MyApp: def __init__(self, parent): self.myParent = parent self.main_container = Frame(parent) self.main_container.grid(row=0, rowspan=2, column=0, columnspan=4) self.top_frame = Frame(self.main_container) self.top_frame.grid(row=0, column=0, columnspan=4) self.top_left = Frame(self.top_frame) self.top_left.grid(row=0, column=0, columnspan=2) self.top_right = Frame(self.top_frame) self.top_right.grid(row=0, column=2, columnspan=2) self.bottom_frame = Frame(self.main_container) self.bottom_frame.grid(row=2, column=0, columnspan=4) self.top_left_label = Label(self.top_left, text="Top Left") self.top_left_label.grid(row=0, column=0, sticky='W', padx=2, pady=2) self.top_right_label = Label(self.top_right, text="Top Right") self.top_right_label.grid(row=0, column=4, sticky='E', padx=2, pady=2) self.text_box = Text(self.bottom_frame, height=5, width=40) self.text_box.grid(row=0, column=0) root = Tk() root.title("Test UI") myapp = MyApp(root) root.mainloop() 

~ ~ Обновить ~ ~

Я попробовал следующее, но это не сработало:

  self.top_left = Frame(self.top_frame) self.top_left.grid(row=0, column=0, columnspan=2) for c in range(2): self.top_left.columnconfigure(c, weight=2) self.top_right = Frame(self.top_frame) self.top_right.grid(row=0, column=2, columnspan=2) for c in range(2): self.top_right.columnconfigure(c, weight=2) 

  • log4cplus: ERROR в python при вызове диалога tkinter file
  • Python tkinter создает кнопки для аргументов командной строки для прохождения цикла
  • tkinter.TclError: изображения "pyimage3" не существует
  • Как создать прозрачные виджеты с помощью Tkinter?
  • Сценарий Threaded Tkinter падает при создании второго виджета Toplevel
  • Переопределение кнопки кнопки Tkinter «X» (кнопка, закрывающая окно)
  • Функция масштабирования не выводит число в переменную?
  • Пытается запустить скрипт python от ubuntu crontab
  • 5 Solutions collect form web for “Tkinter Grid: как размещать виджетов, чтобы они не склеивались”

    Вам нужно использовать 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 немного проще в использовании, так как вам не нужно беспокоиться о весах строк и столбцов.

    Если вы добавите bg = "red" в конструкторы top_left и top_right , вы увидите, как Frames застревают по центру, даже используя sticky опцию. Если они не будут содержать ничего, кроме одного виджета, я рекомендую не использовать их.

     #!/usr/bin/python from Tkinter import * class MyApp: def __init__(self, parent): self.top_left_label = Label(parent, text="Top Left") self.top_left_label.grid(row=0, column=0, padx=2, pady=2, sticky=N+S+W) self.top_right_label = Label(parent, text="Top Right") self.top_right_label.grid(row=0, column=1, padx=2, pady=2, sticky=N+S+E) self.text_box = Text(parent, height=5, width=40) self.text_box.grid(row=1, column=0, columnspan=2) root = Tk() root.title("Test UI") myapp = MyApp(root) root.mainloop() 

    Вот простой способ сделать это:

    • Сначала создайте свой gui на бумаге или используя любой инструмент, который работает для вас
    • Использовать менеджер компоновки сетки
    • Везде, где вы хотите создать пустое пространство, используйте свойство layoutpan или rowspan макета, в сочетании с липкими атрибутами columnpan или rowspan, позволяя назначить несколько элементов сетки компоненту gui, а свойство sticky позволит вам заставить этот элемент придерживаться одна сторона (ы) и оставить пустое пространство с другой стороны (сторон)

    Лучше поздно, чем никогда 😉

    «Сетка сетки» Tkinter хочет собрать все вместе. Вот почему вы не можете пропускать ячейки. Вы должны указать ширину и затем привязать текст. Я добавил цвет, чтобы показать ячейки. Я положил bd в рамку. Затем мне пришлось дать ширину ячейкам слева и справа, чтобы сетка придавала им вес. Затем привяжите текст «Запад» или «Восток». Я не уверен, почему мне пришлось добавить дополнительные 2 пробела для каждой ячейки, но я решил, что это проблема с шрифтом.

    Я считаю, что Rodas чище и проще, но я старался оставаться в пределах параметров, о которых вы спрашиваете.

    Пакет проще и быстрее для мелочей.

     from tkinter import * class MyApp: def __init__(self, parent): self.myParent = parent self.main_container = Frame(parent, bg="green") self.main_container.grid() self.top_frame = Frame(self.main_container) self.top_frame.grid() self.top_left = Frame(self.top_frame, bd=2) self.top_left.grid(row=0, column=0) self.top_right = Frame(self.top_frame, bd=2) self.top_right.grid(row=0, column=2) self.top_left_label = Label(self.top_left, bd=2, bg="red", text="Top Left", width=22, anchor=W) self.top_left_label.grid(row=0, column=0) self.top_right_label = Label(self.top_right, bd=2, bg="blue", text="Top Right", width=22, anchor=E) self.top_right_label.grid(row=0, column=0) self.bottom_frame = Frame(self.main_container, bd=2) self.bottom_frame.grid(row=2, column=0) self.text_box = Text(self.bottom_frame, width=40, height=5) self.text_box.grid(row=0, column=0) root = Tk() root.title("Test UI") myapp = MyApp(root) root.mainloop() 

    Если вам необходим полный контроль над размещением вашего компонента gui, попробуйте разместить макет; очень управляемый подход состоит в том, чтобы организовать ваши компоненты в нескольких кадрах, каждый с сеткой или макетом пакета, а затем организовать все эти фреймы с использованием макета места.

    Python - лучший язык программирования в мире.