¿Cómo empaquetar un widget tkinter debajo de un widget existente que se ha empaquetado en el lado izquierdo?

Estoy intentando escribir una GUI básica de Tkinter que tenga un widget de Text en la parte superior, luego un widget de Button alineado a la izquierda debajo, luego otro widget de Text debajo del botón. El problema que tengo es que, después de empaquetar el widget Button a la izquierda, cuando voy a empaquetar el segundo widget Text , lo coloca al lado del botón a la derecha, en lugar de debajo del botón. Esto sucede independientemente de lo que establezca el argumento side para el segundo widget de Text Aquí hay un simple fragmento de código que demuestra este comportamiento:

 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() 

Entonces, ¿cómo hago para configurar el segundo widget de Text modo que aparezca debajo del botón, en lugar de a la derecha de este?

En general, hay dos soluciones a los problemas de diseño:

  1. cambiar a utilizar la red. Se vuelve realmente fácil hacer diseños como lo que estás tratando de lograr. Grid puede resolver probablemente el 95% de todos los problemas de diseño (es increíble cuando lo piensas, Tk hace con un administrador lo que la mayoría de los kits de herramientas necesitan para hacer media docena).

  2. utilizar múltiples marcos. Si algunos widgets deben astackrse de arriba a abajo y algunos de izquierda a derecha, no siempre se puede obtener lo que se quiere, empaquetando todo en un solo cuadro. Use un marco para las partes de arriba a abajo del diseño y marcos adicionales para el contenido de izquierda a derecha.

Además, tenga en cuenta que los widgets no tienen que ser hijos del widget en el que están empaquetados / reticulados. Puede usar el parámetro “en” para colocar los widgets en algún otro contenedor que no sea su padre.

Por ejemplo, en su ejemplo específico, puede crear tres cuadros, superior, medio, inferior. Empaque estos de arriba a abajo en su ventana de nivel superior. Luego puede empaquetar el primer widget de texto en la parte superior, el botón o los botones horizontalmente en el medio y el otro widget de texto en la parte inferior.

La ventaja de este enfoque es que hace que sea mucho más fácil cambiar el diseño en el futuro (lo que, según mi experiencia, siempre ocurre en algún momento). No tiene que volver a ser padre de ninguno de sus widgets, solo empaquete / coloque / cuadre en algún otro contenedor.

En su breve ejemplo, no hay mucha diferencia, pero para aplicaciones complejas, esta estrategia puede salvar vidas.

Mi mejor consejo es este: el diseño no es una idea de último momento. Haga un poco de planificación, tal vez incluso dedique cinco minutos a dibujar en un papel cuadriculado. Primero, decida las principales regiones de su aplicación y use un marco o algún otro contenedor para cada una (ventana panorámica, cuaderno, etc.). Una vez que tenga esos, haga el mismo enfoque de dividir y conquistar para cada sección. Esto le permite usar diferentes tipos de diseño para diferentes secciones de su aplicación. Las barras de herramientas obtienen diseño horizontal, los formularios pueden obtener diseño vertical, etc.

Inicialmente, no entendía cómo funcionaba el embalaje y no me di cuenta de que todo el lado izquierdo estaba siendo “reclamado” cuando hice x.pack(side=LEFT) . Lo que encontré después de leer esto y la respuesta de Alex aquí es que no estaba realmente después de haber empacado x en el lado izquierdo, sino que estaba anclado a la izquierda, usando anchor=W (W para West) en lugar de side=LEFT . Mi fragmento de código revisado que hace lo que buscaba se parece a esto:

 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() 

De esta manera, x ya no está “reclamando” el lado izquierdo, simplemente está alineado a la izquierda (o al Oeste) dentro de su bloque de espacio.

El empaque ocurre en el orden en que se llaman los métodos .pack, de modo que una vez que x haya “reclamado” el lado izquierdo, ya está, ocupará la parte izquierda de su padre y todo lo demás dentro de su padre estará a su derecha. Necesita un marco para “mediar”, por ejemplo …

 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() 

(Cambió Textos a Botones para obtener una visibilidad más inmediata del diseño solamente: el Tkinter en esta Mac no muestra los Textos con claridad hasta que tienen enfoque, pero los Botones son bastante claros ;-).

Hágalo de la misma manera que WebView utiliza los conjuntos de widgets de canvas mosaico internos (que son muy similares a Tk). El truco es que el segundo objeto de marco con nombre idéntico funciona como un nivel de bloque flotante (en línea: bloque;) para todo lo que se coloca después de él y todo lo que se llama “fr” ya comenzará automáticamente dentro de él.

Puede hacer que muchos hagan esto con los widgets alineados TOP y simplemente agregue otro Frame con el mismo nombre en el que desea romper entre side = LEFT’s. Trabaja después de Bottom también.

 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.