Как упаковать виджет tkinter под существующим виджетом, упакованным слева?

StackOverflow https://stackoverflow.com/questions/1485408

  •  18-09-2019
  •  | 
  •  

Вопрос

Я пытаюсь написать базовый графический интерфейс Tkinter с Text виджет вверху, затем Button виджет выровнен по левому краю под ним, затем еще один Text виджет под кнопкой.Проблема, с которой я столкнулся, заключается в том, что после упаковки Button виджет слева, когда я потом пойду паковать второй Text виджет, он помещает его рядом с кнопкой справа, а не под кнопкой.Это происходит независимо от того, что я установил side аргумент для второго Text виджет Вот простой фрагмент кода, демонстрирующий такое поведение:

from Tkinter import *

root = Tk()

w = Text(root)
w.pack()

x = Button(root, text="Hi there!")
x.pack(side=LEFT)

y = Text(root)
y.pack(side=BOTTOM)

root.mainloop()

Итак, как мне настроить второй Text виджет, чтобы он отображался под кнопкой, а не справа от нее?

Это было полезно?

Решение

Обычно существует два решения проблем с компоновкой:

  1. переключиться на использование сетки.Становится очень легко создавать макеты, подобные тем, которые вы пытаетесь выполнить.Grid может решить, вероятно, 95% всех проблем с макетом (это удивительно, если подумать — Tk делает с одним менеджером то, для чего большинству наборов инструментов требуется полдюжины!)

  2. используйте несколько кадров.Если некоторые виджеты необходимо расположить сверху вниз, а некоторые — слева направо, вы не всегда сможете получить то, что хотите, упаковав все в один кадр.Используйте один кадр для частей макета сверху вниз и дополнительные кадры для содержимого слева направо.

Также помните, что виджеты не обязательно должны быть дочерними элементами виджета, в который они упакованы/построены в сетку.Вы можете использовать параметр «in», чтобы поместить виджеты в другой контейнер, отличный от их родительского.

Например, в вашем конкретном примере вы можете создать три кадра: верхний, средний и нижний.Упакуйте их сверху вниз в окно верхнего уровня.Затем вы можете упаковать первый текстовый виджет вверху, кнопку или кнопки горизонтально посередине, а другой текстовый виджет внизу.

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

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

Мой лучший совет таков:макет не является второстепенной мыслью.Подумайте немного, возможно, даже потратьте пять минут на рисование на миллиметровой бумаге.Сначала определитесь с основными областями вашего приложения и используйте для каждой из них фрейм или какой-либо другой контейнер (панельное окно, блокнот и т. д.).Как только они у вас появятся, примените один и тот же подход «разделяй и властвуй» для каждого раздела.Это позволяет вам использовать разные типы макета для разных разделов вашего приложения.Панели инструментов имеют горизонтальное расположение, формы могут иметь вертикальное расположение и т. д.

Другие советы

Сначала я неправильно понимал, как работает упаковка, и не осознавал, что вся левая сторона была «заявлена», когда я это сделал. x.pack(side=LEFT).Что я нашел после прочтения этот и ответ Алекса заключается в том, что на самом деле я не был после того, как x вообще упаковать с левой стороны, а скорее иметь ее поставленный на якорь влево, используя anchor=W (W для Запада) вместо side=LEFT.Мой исправленный фрагмент кода, который делает то, что мне нужно, выглядит следующим образом:

from Tkinter import *

root = Tk()

w = Text(root)
w.pack()

x = Button(root, text="Hi there!")
x.pack(anchor=W)

y = Text(root)
y.pack(side=BOTTOM)

root.mainloop()

Сюда x больше не «претендует» на левую сторону, он просто выровнен по левому краю (или западу) внутри своего блока пространства.

Упаковка происходит в том порядке, в котором вызываются методы .pack, поэтому, как только x «заберет» левую часть, все — он займет левую часть своего родителя, а все остальное внутри его родителя окажется справа от него.Вам нужен фрейм для «посредничества», например....:

from Tkinter import *

root = Tk()

w = Button(root, text="Mysterious W")
w.pack()

f = Frame(root)
x = Button(f, text="Hi there!")
x.pack()

y = Button(f, text="I be Y")
y.pack(side=BOTTOM)

f.pack(side=LEFT)

root.mainloop()

(Тексты изменены на кнопки только для более непосредственной видимости макета - Tkinter на этом Mac не отображает тексты четко, пока они не находятся в фокусе, но кнопки довольно четкие ;-).

Сделайте это так же, как WebView, используя внутренние элементы наборов виджетов Mosaic Canvas (которые очень похожи на Tk).Хитрость в том, что второй объект Frame с идентичным именем работает как Float уровня блока (inline:block;) для всего, что находится после него, и все, что вызывает «fr», уже автоматически начинается внутри него.

Вы можете сделать это для многих виджетов, выровненных по TOP, и просто добавить еще один кадр с идентичным именем, в котором вы хотите разбить Side=LEFT.Работает и после Bottom.

fr=Frame(root)
fr.pack(fill=X, side=TOP)

block1=Label(fr)
block1.pack(side=LEFT)

block2=Label(fr)
block2.pack(side=LEFT)

block3=Button(fr)
block3.pack(side=LEFT)

# NAME IT THE SAME ID NAME AS THE FIRST MAIN FRAME...
fr=Frame(root)
fr.pack(fill=X, side=TOP)

# These NOW jump into the second Frame breaking the side=LEFT in new Frame
block4=Label(fr) 
block4.pack(side=LEFT)

block5=Label(fr)
block5.pack(side=LEFT)

# AND THEY CONTINUE GOING side=LEFT AFTERWARDS.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top