¿Cómo colocar un widget debajo de los widgets que están lado a lado usando el paquete?

Intento poner los widgets así:

introduzca la descripción de la imagen aquí

No entiendo por qué mi código no hace eso, intenté buscar ejemplos en línea pero no encontré una solución y nada de lo que intenté me acercó más al resultado solicitado.

Este es mi código hasta ahora (si tiene algún comentario sobre algo en el código, no dude en decirme porque es mi primer bash con tkinter y GUI en general):

from Tkinter import * class box(object): def __init__ (self, colour,s): self.root = root self.listbox = Listbox(self.root, fg = colour, bg = 'black') self.s = s self.place_scrollbar() self.listbox.pack(side = self.s) def place_scrollbar(self): scrollbar = Scrollbar(self.root) scrollbar.pack(side = self.s, fill = Y) self.listbox.config(yscrollcommand = scrollbar.set) scrollbar.config(command = self.listbox.yview) def write(self, contenet): self.listbox.insert(END, contenet) root = Tk() root.resizable(False, False) boxs = Frame(root) boxs.pack() box.root = boxs server = box("red", LEFT) client = box("green", RIGHT ) bf = Frame(root) bf.pack(side = BOTTOM) entry = Entry(bf,bg ='black', fg = 'white') entry.pack() root.mainloop() 

No puede hacer esto sin usar un marco adicional para contener los objetos de la box mientras sigue usando el pack , mientras mantiene la posibilidad de cambiar el tamaño.

Pero en algunos casos está más organizado: usar un marco adicional para contener los objetos de box , al inicializarlo con una opción principal.

En este momento, los widgets dentro de la clase de box son hijos del objeto root global . Lo que no es realmente una buena práctica. Así que primero pasemos y usemos un objeto padre que se usará para los widgets dentro.

Reemplazar:

 def __init__ (self, colour,s): self.root = root self.listbox = Listbox(self.root, ...) ... def place_scrollbar(self): scrollbar = Scrollbar(self.root) ... 

con:

 def __init__ (self, parent, colour,s): self.parent= parent self.listbox = Listbox(self.parent, ...) ... def place_scrollbar(self): scrollbar = Scrollbar(self.parent) ... 

Esto lo hace así que ahora necesita inicializar el objeto como se muestra a continuación:

 server = box(root, "red", LEFT) client = box(root, "green", RIGHT ) 

Ahora que podemos pasar un widget padre, creamos un marco padre para contenerlos. En realidad, ya hay un marco sin usar, los cuadros lo usamos pasándolo como padre en lugar de root :

 server = box(boxs, "red", LEFT) client = box(boxs, "green", RIGHT ) 

Ahora todo se ve bien, opcionalmente, si desea que la entrada ocupe el mayor espacio posible, actualmente agregue fill='x' como una opción para el pack de la entrada y el marco que la contiene:

 bf.pack(side = BOTTOM, fill='x') ... entry.pack(fill='x') 

Todo tu código debería verse como:

 from Tkinter import * class box(object): def __init__ (self, parent, colour,s): self.parent = parent self.listbox = Listbox(self.parent, fg = colour, bg = 'black') self.s = s self.place_scrollbar() self.listbox.pack(side = self.s) def place_scrollbar(self): scrollbar = Scrollbar(self.parent) scrollbar.pack(side = self.s, fill = Y) self.listbox.config(yscrollcommand = scrollbar.set) scrollbar.config(command = self.listbox.yview) def write(self, contenet): self.listbox.insert(END, contenet) root = Tk() root.resizable(False, False) boxs = Frame(root) boxs.pack() box.root = boxs server = box(boxs, "red", LEFT) client = box(boxs, "green", RIGHT ) bf = Frame(root) bf.pack(side = BOTTOM, fill='x') entry = Entry(bf,bg ='black', fg = 'white') entry.pack(fill='x') root.mainloop() 

O bien: use la grid lugar del pack (con la opción columnspan=2 para entrada).


Respuesta general

De manera más general, colocar un widget debajo de dos widgets que están uno al lado del otro se puede hacer mediante:

Encapsule los widgets de lado a lado con un frame y luego simplemente coloque el frame sobre el otro widget:

 try: # In order to be able to import tkinter for import tkinter as tk # either in python 2 or in python 3 except ImportError: import Tkinter as tk def main(): root = tk.Tk() side_by_side_widgets = dict() the_widget_beneath = tk.Entry(root) frame = tk.Frame(root) for name in {"side b", "y side"}: side_by_side_widgets[name] = tk.Label(frame, text=name) side_by_side_widgets[name].pack(side='left', expand=True) frame.pack(fill='x') the_widget_beneath.pack() root.mainloop() if __name__ == '__main__': main() 

Utilizando grid :

 try: # In order to be able to import tkinter for import tkinter as tk # either in python 2 or in python 3 except ImportError: import Tkinter as tk def main(): root = tk.Tk() side_by_side_widgets = dict() the_widget_beneath = tk.Entry(root) for index, value in enumerate({"side b", "y side"}): side_by_side_widgets[value] = tk.Label(root, text=value) side_by_side_widgets[value].grid(row=0, column=index) the_widget_beneath.grid(row=1, column=0, columnspan=2) root.mainloop() if __name__ == '__main__': main() 

Sin usar marcos adicionales, llamando al pack para the_widget_beneath con side='bottom' como la primera llamada del pack , como en el comentario de Bryan :

 try: # In order to be able to import tkinter for import tkinter as tk # either in python 2 or in python 3 except ImportError: import Tkinter as tk def main(): root = tk.Tk() side_by_side_widgets = dict() the_widget_beneath = tk.Entry(root) the_widget_beneath.pack(side='bottom') for name in {"side b", "y side"}: side_by_side_widgets[name] = tk.Label(root, text=name) side_by_side_widgets[name].pack(side='left', expand=True) root.mainloop() if __name__ == '__main__': main() 

Puede notar más fácilmente la confiabilidad de los objetos globales al crear un método main global, y agregar el cuerpo principal de su script allí y llamar:

 ... def main(): root = Tk() root.resizable(False, False) boxs = Frame(root) boxs.pack() box.root = boxs server = box(boxs, "red", LEFT) client = box(boxs, "green", RIGHT ) bf = Frame(root) bf.pack(side = BOTTOM, fill='x') entry = Entry(bf,bg ='black', fg = 'white') entry.pack(fill='x') root.mainloop() if __name__ == '__main__': main() 

¿Cómo colocar un widget debajo de dos widgets que están lado a lado usando el paquete?

Para un diseño muy simple como en tu diagtwig, simplemente necesitas empacar la cosa en la parte inferior primero. Eso es porque el pack usa un modelo de “cavidad”. Cada widget está organizado en una cavidad sin rellenar. Una vez que se ha colocado ese widget, se llena esa parte de la cavidad y no está disponible para ningún otro widget.

En su caso, desea que la cavidad inferior se llene con el widget de entrada, por lo que debe empaquetarlo primero. Luego, en la cavidad superior restante puede colocar los dos marcos uno al lado del otro, uno a la izquierda y otro a la derecha.

Por ejemplo:

 import Tkinter as tk root = tk.Tk() entry = tk.Entry(root) frame1 = tk.Frame(root, width=100, height=100, background="red") frame2 = tk.Frame(root, width=100, height=100, background="green") entry.pack(side="bottom", fill="x") frame1.pack(side="left", fill="both", expand=True) frame2.pack(side="right", fill="both", expand=True) root.mainloop() 

En el cuerpo de su pregunta, las cosas se complican un poco más, ya que no solo tiene tres widgets como su título sugiere, tiene varios, algunos empacados en la raíz y otros empacados en otra parte, con declaraciones de pack dispersas por todas partes.

Cuando use el paquete, es mejor agrupar los widgets en segmentos verticales u horizontales, y no mezclar la parte superior / inferior con la izquierda / derecha dentro del mismo grupo. Casi parece que estás tratando de hacer eso con tus cajas, pero entonces no lo haces, tu “caja” es en realidad dos widgets.

En pocas palabras: ser organizado. También realmente, realmente ayuda si todas las declaraciones de su pack (o place o grid ) para un padre determinado están todas en el mismo bloque de código. Cuando los dispersas alrededor, es imposible visualizarlos, e imposibles de solucionar. Además, asegúrese de que los widgets tengan los padres adecuados.