You can't do this without using an additional frame to contain the box objects while still using pack, while still maintaining resizability.
But it is more organized in some cases to: use an additional frame to contain your box objects, by initializing it with a parent option.
Right now the widgets inside the box class are children to global root object. Which isn't really a good practice. So let's first pass and use a parent object to be used for widgets inside.
Replace:
def __init__ (self, colour,s):
self.root = root
self.listbox = Listbox(self.root, ...)
...
def place_scrollbar(self):
scrollbar = Scrollbar(self.root)
...
with:
def __init__ (self, parent, colour,s):
self.parent= parent
self.listbox = Listbox(self.parent, ...)
...
def place_scrollbar(self):
scrollbar = Scrollbar(self.parent)
...
This makes it so that you now need to initialize the object like the following:
server = box(root, "red", LEFT)
client = box(root, "green", RIGHT )
Now that we can pass a parent widget, let's create a parent frame to contain them. Actually, there's an un-used frame already, boxs let's use that by passing it as the parent as opposed to root:
server = box(boxs, "red", LEFT)
client = box(boxs, "green", RIGHT )
Now everything looks fine, optionally if you want to make it so that entry occupies as much left space as possible currently add fill='x' as an option to the pack of both the entry and the frame that contains it:
bf.pack(side = BOTTOM, fill='x')
...
entry.pack(fill='x')
Your whole code should look like:
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()
Or: use grid instead of pack (with columnspan=2 option for entry).
General Answer
More generally putting a widget beneath two widgets that are side-by-side can be done by:
Encapsulating the side-by-side widgets with a frame, and then simply putting the frame above the other 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()
Using 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()
Without using additional frames, by calling pack for the_widget_beneath with side='bottom' as the first pack call, as in Bryan's comment:
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()
You can more easily notice reliability to global objects by creating a global main method, and add main-body of your script there and call:
...
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()