Postioning Widget in Tkinter Python
Question:
I was recently introduced to tkinter, and I’m attempting to write a application for 2d plotter. I am trying to position my buttons using the .pack method and I have write the code and stuck when try to position the text display and the graph figure. Here’s the current code output for my application:
enter image description here
This is the intended view/positioning output for my application:
enter image description here
Why does it happen and how can I position it using .pack method?
This is the code (I have changed it so it easy to run it without image):
from tkinter import *
from tkinter import Tk, Frame, Menu
from tkinter.filedialog import *
from tkinter.scrolledtext import ScrolledText
from tkinter import ttk, filedialog
import tkinter.messagebox
import tkinter as tk
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg #, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import time
import turtle
import os
import sys
import logging
import ruamel.yaml
class MenuBar(tk.Menu):
def __init__(self, parent):
tk.Menu.__init__(self, parent)
fileMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="File", underline=0, menu=fileMenu)
fileMenu.add_command(label="Upload File", command=self.browseFile)
fileMenu.add_command(label="Exit", underline=1, command=self.quit)
settingMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="Settings", underline=0, menu=settingMenu)
settingMenu.add_command(label="Machine Variable") #,command=self.browseFile)
aboutMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="About", underline=0, menu=aboutMenu)
#aboutMenu.add_command(label="Machine Variable")
def browseFile(self):
tmp = filedialog.askopenfilename(initialdir = "./", title = "select gcode file", filetypes = (("gcode files", "*.gcode"), ("gc files", "*.gc"), ("nc files", "*.nc"), ("all files", "*.*")))
selectedfile = tmp
gcodefile = open (selectedfile, 'r')
gcodefileread = gcodefile.readlines()
fileDisplayText.insert(END, gcodefileread)
gcodefile.close()
gcode = extractGcode(selectedfile)
self.diagramFrame.plot(gcode)
def quit(self):
sys.exit(0)
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Plotter Interface")
menubar = MenuBar(self)
self.config(menu=menubar)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
topLeftFrame = tk.Frame(container, relief='solid', bd=1)
topLeftFrame.pack(side=LEFT, anchor=NW, padx=0, pady=0)
bottomRightFrame = tk.Frame(container, relief='solid', bd=1)
bottomRightFrame.pack(side=RIGHT, anchor=NE, padx=0, pady=0)
#def update():
#zero=0
#one=zero+1
#print(one)
homebutton = tk.Button(topLeftFrame, height=50, width=50, command=None)
homebutton.grid(row=0, column=0, padx=0, pady=0)
playbutton = tk.Button(topLeftFrame, height=50, width=50, command=None)
playbutton.grid(row=0, column=1, padx=0, pady=0)
pausebutton = tk.Button(topLeftFrame, height=50, width=50, command=None)
pausebutton.grid(row=0, column=2, padx=0, pady=0)
stopbutton = tk.Button(topLeftFrame, height=50, width=50, command=None)
stopbutton.grid(row=0, column=3, padx=0, pady=0)
updownbutton = tk.Button(topLeftFrame, height=50, width=50, command=None)
updownbutton.grid(row=0, column=4, padx=0, pady=0)
nextbutton = tk.Button(bottomRightFrame, height=50, width=50, command=None)
nextbutton.grid(row=0, column=1, padx=0, pady=0)
prevbutton = tk.Button(bottomRightFrame, height=50, width=50, command=None)
prevbutton.grid(row=0, column=0, padx=0, pady=0)
self.diagramFrame = DiagramFrame(container)
self.diagramFrame.pack(side=BOTTOM,fill='both',expand=True)
class DiagramFrame(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="Drawing Plotter view", font=("Verdana", 12))
label.pack(side=TOP, anchor=E, pady=0,padx=0)
label2 = tk.Label(self, text="Gcode view", font=("Verdana", 12))
label2.pack(side=TOP, anchor=W, pady=0,padx=0)
self.f = Figure(figsize=(8,8), dpi=100)
self.a = self.f.add_subplot(111)
self.a.plot(0, 0, 'r')
self.a.plot(0, 0, 'g')
self.a.axis("equal")
self.a.grid(color='grey', linestyle='-', linewidth=0.5)
#self.a.legend(["XY", "UV"])
self.fileDisplayText = Text(self, width=27, height=13.6, font=(9))
self.fileDisplayText.pack(side=LEFT, anchor=SW,padx=0, pady=0)
self.canvas = FigureCanvasTkAgg(self.f, self)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=RIGHT, fill=BOTH, expand=True)
Answers:
I think problem is because you put all in one container with LEFT
, RIGHT
and BOTTOM
and you expect
+---------------------+
| TOP(1),TOP(2) |
+----------+----------+
| LEFT | RIGHT |
+----------+----------+
| BOTTOM(1),BOTTOM(2) |
+---------------------+
but it works in different way
+------+------+-----------+-------+-------+
| | | TOP(1) | | |
| | +-----------+ | |
| | | TOP(2) | | |
| LEFT | LEFT +-----------+ RIGHT | RIGHT |
| (1) | (2) | BOTTOM(2) | (2) | (1) |
| | +-----------+ | |
| | | BOTTOM(1) | | |
+------+------+-----------+-------+-------+
You should use nested Frames
- one frame only for
buttons
on left
and right
,
- one frame only with
graph
and text
on left
and right
.
- and these frames should be inside another frame at
top
and bottom
- and
graph
should be as another frame with label
at top
and with plot
at bottom
. (And the same with text
)
+-FRAME or TK or TOPLEVEL-----------------------------------+
| |
| +-FRAME.pack(TOP)-------------------------------------+ |
| | | |
| | Buttons.pack(LEFT) Buttons.pack(RIGHT) | |
| | | |
| +-----------------------------------------------------+ |
| |
| +-FRAME.pack(BOTTOM)----------------------------------+ |
| | | |
| | +-FRAME.pack(LEFT)----+ +-FRAME.pack(RIGHT)----+ | |
| | | | | | | |
| | | Label.pack(TOP) | | Label.pack(TOP) | | |
| | | | | | | |
| | | Text.pack(BOTTOM) | | Graph.pack(BOTTOM) | | |
| | | | | | | |
| | +---------------------+ +----------------------+ | |
| | | |
| +-----------------------------------------------------+ |
| |
+-----------------------------------------------------------+
Something like this:
from tkinter import *
from tkinter import Tk, Frame, Menu
from tkinter.filedialog import *
from tkinter.scrolledtext import ScrolledText
from tkinter import ttk, filedialog
import tkinter.messagebox
import tkinter as tk
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg #, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import time
import turtle
import os
import sys
import logging
#import ruamel.yaml
class MenuBar(tk.Menu):
def __init__(self, parent):
super().__init__(parent)
fileMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="File", underline=0, menu=fileMenu)
fileMenu.add_command(label="Upload File", command=self.browseFile)
fileMenu.add_command(label="Exit", underline=1, command=self.quit)
settingMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="Settings", underline=0, menu=settingMenu)
settingMenu.add_command(label="Machine Variable") #,command=self.browseFile)
aboutMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="About", underline=0, menu=aboutMenu)
#aboutMenu.add_command(label="Machine Variable")
def browseFile(self):
tmp = filedialog.askopenfilename(initialdir="./", title="select gcode file", filetypes=(("gcode files", "*.gcode"), ("gc files", "*.gc"), ("nc files", "*.nc"), ("all files", "*.*")))
selectedfile = tmp
gcodefile = open(selectedfile, 'r')
gcodefileread = gcodefile.readlines()
fileDisplayText.insert(END, gcodefileread)
gcodefile.close()
gcode = extractGcode(selectedfile)
self.diagramFrame.plot(gcode)
def quit(self):
sys.exit(0)
class App(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
tk.Tk.wm_title(self, "Plotter Interface")
menubar = MenuBar(self)
self.config(menu=menubar)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
top_frame = tk.Frame(container)
top_frame.pack(fill='x', expand=True)
topLeftFrame = tk.Frame(top_frame, relief='solid', bd=1)
topLeftFrame.pack(side=LEFT, anchor=NW, padx=0, pady=0)
bottomRightFrame = tk.Frame(top_frame, relief='solid', bd=1)
bottomRightFrame.pack(side=RIGHT, anchor=NE, padx=0, pady=0)
#def update():
#zero=0
#one=zero+1
#print(one)
homebutton = tk.Button(topLeftFrame, command=None)
homebutton.grid(row=0, column=0, padx=0, pady=0)
playbutton = tk.Button(topLeftFrame, command=None)
playbutton.grid(row=0, column=1, padx=0, pady=0)
pausebutton = tk.Button(topLeftFrame, command=None)
pausebutton.grid(row=0, column=2, padx=0, pady=0)
stopbutton = tk.Button(topLeftFrame, command=None)
stopbutton.grid(row=0, column=3, padx=0, pady=0)
updownbutton = tk.Button(topLeftFrame, command=None)
updownbutton.grid(row=0, column=4, padx=0, pady=0)
nextbutton = tk.Button(bottomRightFrame, command=None)
nextbutton.grid(row=0, column=1, padx=0, pady=0)
prevbutton = tk.Button(bottomRightFrame, command=None)
prevbutton.grid(row=0, column=0, padx=0, pady=0)
bottom_frame = tk.Frame(container)
bottom_frame.pack()
self.diagramFrame = DiagramFrame(bottom_frame)
self.diagramFrame.pack(side=BOTTOM,fill='both',expand=True)
class DiagramFrame(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
frame_right = tk.Frame(self)
frame_right.pack(side=RIGHT, fill='both', expand=True)
label1 = tk.Label(frame_right, text="Drawing Plotter view", anchor='w', padx=15, pady=5)
label1.pack(side=TOP, fill='x', expand=True)
self.f = Figure(figsize=(8,8), dpi=100)
self.a = self.f.add_subplot(111)
self.a.plot(0, 0, 'r')
self.a.plot(0, 0, 'g')
self.a.axis("equal")
self.a.grid(color='grey', linestyle='-', linewidth=0.5)
#self.a.legend(["XY", "UV"])
self.canvas = FigureCanvasTkAgg(self.f, frame_right)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=BOTTOM, fill='both', expand=True)
# --------------------------
frame_left = tk.Frame(self)
frame_left.pack(side=LEFT, fill=BOTH, expand=True)
label2 = tk.Label(frame_left, text="Gcode view", anchor='w', padx=15, pady=5)
label2.pack(side=TOP, fill='x')
self.fileDisplayText = Text(frame_left, width=27, font=(9))
self.fileDisplayText.pack(side=BOTTOM, fill='both', expand=True)
app = App()
app.mainloop()
I was recently introduced to tkinter, and I’m attempting to write a application for 2d plotter. I am trying to position my buttons using the .pack method and I have write the code and stuck when try to position the text display and the graph figure. Here’s the current code output for my application:
enter image description here
This is the intended view/positioning output for my application:
enter image description here
Why does it happen and how can I position it using .pack method?
This is the code (I have changed it so it easy to run it without image):
from tkinter import *
from tkinter import Tk, Frame, Menu
from tkinter.filedialog import *
from tkinter.scrolledtext import ScrolledText
from tkinter import ttk, filedialog
import tkinter.messagebox
import tkinter as tk
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg #, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import time
import turtle
import os
import sys
import logging
import ruamel.yaml
class MenuBar(tk.Menu):
def __init__(self, parent):
tk.Menu.__init__(self, parent)
fileMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="File", underline=0, menu=fileMenu)
fileMenu.add_command(label="Upload File", command=self.browseFile)
fileMenu.add_command(label="Exit", underline=1, command=self.quit)
settingMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="Settings", underline=0, menu=settingMenu)
settingMenu.add_command(label="Machine Variable") #,command=self.browseFile)
aboutMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="About", underline=0, menu=aboutMenu)
#aboutMenu.add_command(label="Machine Variable")
def browseFile(self):
tmp = filedialog.askopenfilename(initialdir = "./", title = "select gcode file", filetypes = (("gcode files", "*.gcode"), ("gc files", "*.gc"), ("nc files", "*.nc"), ("all files", "*.*")))
selectedfile = tmp
gcodefile = open (selectedfile, 'r')
gcodefileread = gcodefile.readlines()
fileDisplayText.insert(END, gcodefileread)
gcodefile.close()
gcode = extractGcode(selectedfile)
self.diagramFrame.plot(gcode)
def quit(self):
sys.exit(0)
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Plotter Interface")
menubar = MenuBar(self)
self.config(menu=menubar)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
topLeftFrame = tk.Frame(container, relief='solid', bd=1)
topLeftFrame.pack(side=LEFT, anchor=NW, padx=0, pady=0)
bottomRightFrame = tk.Frame(container, relief='solid', bd=1)
bottomRightFrame.pack(side=RIGHT, anchor=NE, padx=0, pady=0)
#def update():
#zero=0
#one=zero+1
#print(one)
homebutton = tk.Button(topLeftFrame, height=50, width=50, command=None)
homebutton.grid(row=0, column=0, padx=0, pady=0)
playbutton = tk.Button(topLeftFrame, height=50, width=50, command=None)
playbutton.grid(row=0, column=1, padx=0, pady=0)
pausebutton = tk.Button(topLeftFrame, height=50, width=50, command=None)
pausebutton.grid(row=0, column=2, padx=0, pady=0)
stopbutton = tk.Button(topLeftFrame, height=50, width=50, command=None)
stopbutton.grid(row=0, column=3, padx=0, pady=0)
updownbutton = tk.Button(topLeftFrame, height=50, width=50, command=None)
updownbutton.grid(row=0, column=4, padx=0, pady=0)
nextbutton = tk.Button(bottomRightFrame, height=50, width=50, command=None)
nextbutton.grid(row=0, column=1, padx=0, pady=0)
prevbutton = tk.Button(bottomRightFrame, height=50, width=50, command=None)
prevbutton.grid(row=0, column=0, padx=0, pady=0)
self.diagramFrame = DiagramFrame(container)
self.diagramFrame.pack(side=BOTTOM,fill='both',expand=True)
class DiagramFrame(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="Drawing Plotter view", font=("Verdana", 12))
label.pack(side=TOP, anchor=E, pady=0,padx=0)
label2 = tk.Label(self, text="Gcode view", font=("Verdana", 12))
label2.pack(side=TOP, anchor=W, pady=0,padx=0)
self.f = Figure(figsize=(8,8), dpi=100)
self.a = self.f.add_subplot(111)
self.a.plot(0, 0, 'r')
self.a.plot(0, 0, 'g')
self.a.axis("equal")
self.a.grid(color='grey', linestyle='-', linewidth=0.5)
#self.a.legend(["XY", "UV"])
self.fileDisplayText = Text(self, width=27, height=13.6, font=(9))
self.fileDisplayText.pack(side=LEFT, anchor=SW,padx=0, pady=0)
self.canvas = FigureCanvasTkAgg(self.f, self)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=RIGHT, fill=BOTH, expand=True)
I think problem is because you put all in one container with LEFT
, RIGHT
and BOTTOM
and you expect
+---------------------+
| TOP(1),TOP(2) |
+----------+----------+
| LEFT | RIGHT |
+----------+----------+
| BOTTOM(1),BOTTOM(2) |
+---------------------+
but it works in different way
+------+------+-----------+-------+-------+
| | | TOP(1) | | |
| | +-----------+ | |
| | | TOP(2) | | |
| LEFT | LEFT +-----------+ RIGHT | RIGHT |
| (1) | (2) | BOTTOM(2) | (2) | (1) |
| | +-----------+ | |
| | | BOTTOM(1) | | |
+------+------+-----------+-------+-------+
You should use nested Frames
- one frame only for
buttons
onleft
andright
, - one frame only with
graph
andtext
onleft
andright
. - and these frames should be inside another frame at
top
andbottom
- and
graph
should be as another frame withlabel
attop
and withplot
atbottom
. (And the same withtext
)
+-FRAME or TK or TOPLEVEL-----------------------------------+
| |
| +-FRAME.pack(TOP)-------------------------------------+ |
| | | |
| | Buttons.pack(LEFT) Buttons.pack(RIGHT) | |
| | | |
| +-----------------------------------------------------+ |
| |
| +-FRAME.pack(BOTTOM)----------------------------------+ |
| | | |
| | +-FRAME.pack(LEFT)----+ +-FRAME.pack(RIGHT)----+ | |
| | | | | | | |
| | | Label.pack(TOP) | | Label.pack(TOP) | | |
| | | | | | | |
| | | Text.pack(BOTTOM) | | Graph.pack(BOTTOM) | | |
| | | | | | | |
| | +---------------------+ +----------------------+ | |
| | | |
| +-----------------------------------------------------+ |
| |
+-----------------------------------------------------------+
Something like this:
from tkinter import *
from tkinter import Tk, Frame, Menu
from tkinter.filedialog import *
from tkinter.scrolledtext import ScrolledText
from tkinter import ttk, filedialog
import tkinter.messagebox
import tkinter as tk
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg #, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import time
import turtle
import os
import sys
import logging
#import ruamel.yaml
class MenuBar(tk.Menu):
def __init__(self, parent):
super().__init__(parent)
fileMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="File", underline=0, menu=fileMenu)
fileMenu.add_command(label="Upload File", command=self.browseFile)
fileMenu.add_command(label="Exit", underline=1, command=self.quit)
settingMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="Settings", underline=0, menu=settingMenu)
settingMenu.add_command(label="Machine Variable") #,command=self.browseFile)
aboutMenu = tk.Menu(self, tearoff=False)
self.add_cascade(label="About", underline=0, menu=aboutMenu)
#aboutMenu.add_command(label="Machine Variable")
def browseFile(self):
tmp = filedialog.askopenfilename(initialdir="./", title="select gcode file", filetypes=(("gcode files", "*.gcode"), ("gc files", "*.gc"), ("nc files", "*.nc"), ("all files", "*.*")))
selectedfile = tmp
gcodefile = open(selectedfile, 'r')
gcodefileread = gcodefile.readlines()
fileDisplayText.insert(END, gcodefileread)
gcodefile.close()
gcode = extractGcode(selectedfile)
self.diagramFrame.plot(gcode)
def quit(self):
sys.exit(0)
class App(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
tk.Tk.wm_title(self, "Plotter Interface")
menubar = MenuBar(self)
self.config(menu=menubar)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
top_frame = tk.Frame(container)
top_frame.pack(fill='x', expand=True)
topLeftFrame = tk.Frame(top_frame, relief='solid', bd=1)
topLeftFrame.pack(side=LEFT, anchor=NW, padx=0, pady=0)
bottomRightFrame = tk.Frame(top_frame, relief='solid', bd=1)
bottomRightFrame.pack(side=RIGHT, anchor=NE, padx=0, pady=0)
#def update():
#zero=0
#one=zero+1
#print(one)
homebutton = tk.Button(topLeftFrame, command=None)
homebutton.grid(row=0, column=0, padx=0, pady=0)
playbutton = tk.Button(topLeftFrame, command=None)
playbutton.grid(row=0, column=1, padx=0, pady=0)
pausebutton = tk.Button(topLeftFrame, command=None)
pausebutton.grid(row=0, column=2, padx=0, pady=0)
stopbutton = tk.Button(topLeftFrame, command=None)
stopbutton.grid(row=0, column=3, padx=0, pady=0)
updownbutton = tk.Button(topLeftFrame, command=None)
updownbutton.grid(row=0, column=4, padx=0, pady=0)
nextbutton = tk.Button(bottomRightFrame, command=None)
nextbutton.grid(row=0, column=1, padx=0, pady=0)
prevbutton = tk.Button(bottomRightFrame, command=None)
prevbutton.grid(row=0, column=0, padx=0, pady=0)
bottom_frame = tk.Frame(container)
bottom_frame.pack()
self.diagramFrame = DiagramFrame(bottom_frame)
self.diagramFrame.pack(side=BOTTOM,fill='both',expand=True)
class DiagramFrame(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
frame_right = tk.Frame(self)
frame_right.pack(side=RIGHT, fill='both', expand=True)
label1 = tk.Label(frame_right, text="Drawing Plotter view", anchor='w', padx=15, pady=5)
label1.pack(side=TOP, fill='x', expand=True)
self.f = Figure(figsize=(8,8), dpi=100)
self.a = self.f.add_subplot(111)
self.a.plot(0, 0, 'r')
self.a.plot(0, 0, 'g')
self.a.axis("equal")
self.a.grid(color='grey', linestyle='-', linewidth=0.5)
#self.a.legend(["XY", "UV"])
self.canvas = FigureCanvasTkAgg(self.f, frame_right)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=BOTTOM, fill='both', expand=True)
# --------------------------
frame_left = tk.Frame(self)
frame_left.pack(side=LEFT, fill=BOTH, expand=True)
label2 = tk.Label(frame_left, text="Gcode view", anchor='w', padx=15, pady=5)
label2.pack(side=TOP, fill='x')
self.fileDisplayText = Text(frame_left, width=27, font=(9))
self.fileDisplayText.pack(side=BOTTOM, fill='both', expand=True)
app = App()
app.mainloop()