Following a suggestion that I got from Sentdex I have coded a multiple page Python/Tkinter application which among other things provides a time-moving graph on a single frame of a suite of many frames that live under tk.Tk. The coding of a moving graph was slightly complicated so I chose to define the canvas in a class: GrpCanvas(tk.Canvas).
My problem is that this program structure seems to cause the canvas object to appear on all 21 of my page-frames! How can I manage the code so that the graphcanvas=GrpCanvas(HomePage) only appears on that page? I have commented out some parent definitions to show what I have tried to do (and failed). I am using Python 3.4.4.
I show the code (cut down as much as I can to show the problem) below:
#Avoiding canvas on all pages when pages are managed using tk.Tk
import tkinter as tk
sinewave_points=[] #Generated by a sin function of time.
#class GrpCanvas(self, parent):
class GrpCanvas(tk.Canvas):
#def __init__(self, parent):
def __init__(self, parent, controller):
tk.Canvas.__init__(self, height=340, width=594, bg='white')#, x=pos_x, y=pos_y):
self.place(x=180, y=80)
def set_y_scale(self, sinewave_points):
self.scale=100 #actually calculated from a scaling algorithm (adapting to amplitude of sinewave_points)
return self.scale
def define_graph(self, scale, sinewave_points):
# create x-axis
self.horizontal=self.create_line(0, 170, 594, 170, width=2)
for i in range(13): #used to be 26
x = 20 + (i * 48)
self.x_scale=self.create_text(x, 175, font=("", 6),\
anchor='n', text='{}'.format(((12/3) * i)-24))
# y-axis
self.vertical=self.create_line(20, 330, 20, 10, width=2)
self.y_scale=self.set_y_scale(sinewave_points)
if self.y_scale == 100:
for i in range(21):
self.y = int(330 - (i * (320/20))) #In fact there is an slgorithm to scale the y-axis
#print(i, self.y)
self.y_axis=self.create_text(17, (self.y), font=("", 6), anchor='e',\
text='{}'.format(int((((200/320)*(320/20)) * i)-\
100)))
for i in range(len(sinewave_points)):
self.x, self.y = (i+20) , int(-1*self.scale*sinewave_points[i])+ 170
self.history=self.create_oval(self.x - 1, self.y - 1, self.x + 1,\
self.y + 1, width=0, fill='purple')
class Moving_Sinewave(tk.Tk):
def __init__(self, *args, **kwargs):
#Initialising Tkinter
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, 'Sinewave Moving Plotter')
tk.Tk.geometry(self, '800x480')#This is the size of the screen (in pixels)
container = tk.Frame(self)
container.pack(fill='both', expand= True)#(side="top", fill="both", expand = True)
container.grid_rowconfigure (0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (HomePage,
SystemConfigPage,
ConfigAlarmsPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
frame.configure(background= 'ivory2'),
self.show_frame(HomePage)
def show_frame(self, cont):
frame=self.frames[cont]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self, parent, controller):
self.controller=controller
tk.Frame.__init__(self, parent)
global time1, time2, time4, time5
sysconfigbutton=tk.Button(self, text= 'System\nConfiguration',
command=lambda: controller.show_frame(SystemConfigPage),
height=2, width=12)
sysconfigbutton.place(x=20, y=80)
#graphcanvas=GrpCanvas(tk.Frame) #works with: class GrpCanvas(tk.Canvas):
#def __init__(self, parent):
#graphcanvas=GrpCanvas(HomePage) #works with: class GrpCanvas(tk.Canvas):
#def __init__(self, parent):
#graphcanvas=GrpCanvas(HomePage(tk.Frame))
graphcanvas=GrpCanvas(HomePage, controller.tk)# works with: class GrpCanvas(tk.Canvas):
#def __init__(self, parent, controller):
graphcanvas.define_graph(graphcanvas.set_y_scale(sinewave_points), sinewave_points)
# This actually plots the points
class SystemConfigPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
configalarmsbutton=tk.Button(self, text= 'Configure\nAlarms',
command=lambda: controller.show_frame(ConfigAlarmsPage),
height=2, width=12)
configalarmsbutton.place(x=20, y=180)
class ConfigAlarmsPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
backbutton=tk.Button(self, text= 'Back',
command=lambda: controller.show_frame(HomePage),
height=2, width=12)
backbutton.place(x=20, y=380)
app = Moving_Sinewave()
app.mainloop()
The first argument to
GrpCanvasneeds to be the parent widget in which the canvas is to appear. In this specific case you should useself, since you want it to be in the home page and you are creating it as part of creatingHomePage:You also need to pass this argument on to the
__init__of the parent class, which you are neglecting to do. To fix that, change this:... to this:
What was happening is that because you didn't pass in the parent, the widget was using the root window as the default. And because you were using
place, and because this widget was getting created last (and thus was at the top of the stacking order) it was appearing on top of all of the pages.