My program consists in mouse drawing: Simultaneous reproduction of the drawn curves are done on a toplevel window. My aim is to set the vertical and horizontal scroll bars to the toplevel window.
The drawing works as I expected except I am not seeing the scrollbars as well as I am getting this error (which does not stop the program, however):
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1489, in __call__
return self.func(*args)
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1523, in yview
res = self.tk.call(self._w, 'yview', *args)
TclError: unknown option "0.0": must be moveto or scroll
The program consists of these lines:
from Tkinter import *
import numpy as np
import cv2
import Image, ImageTk
class Test:
def __init__(self, parent):
self.parent = parent
self.b1="up"
self.xold=None
self.yold=None
self.liste=[]
self.top = TopLevelWindow()
self.s=400,400,3
self.im=np.zeros(self.s,dtype=np.uint8)
cv2.imshow("hello",self.im)
def test(self):
self.drawingArea=Canvas(self.parent,width=400,height=400)
self.drawingArea.pack()
self.drawingArea.bind("<Motion>",self.motion)
self.drawingArea.bind("<ButtonPress-1>",self.b1down)
self.drawingArea.bind("<ButtonRelease-1>",self.b1up)
def b1down(self,event):
self.b1="down"
def b1up(self,event):
self.b1="up"
self.xold=None
self.yold=None
self.liste.append((self.xold,self.yold))
def motion(self,event):
if self.b1=="down":
if self.xold is not None and self.yold is not None:
event.widget.create_line(self.xold,self.yold,event.x,event.y,fill="red",width=3,smooth=TRUE)
self.top.draw_line(self.xold,self.yold,event.x,event.y)
self.xold=event.x
self.yold=event.y
self.liste.append((self.xold,self.yold))
class TopLevelWindow(Frame):
def __init__(self):
Frame.__init__(self)
self.top=Toplevel()
self.top.wm_title("Second Window")
self.canvas=Canvas(self.top,width=400,height=400)
self.canvas.grid(row=0,column=0,sticky=N+E+S+W)
self.sbarv=Scrollbar(self,orient=VERTICAL)
self.sbarh=Scrollbar(self,orient=HORIZONTAL)
self.sbarv.config(command=self.canvas.yview)
self.sbarh.config(command=self.canvas.xview)
self.canvas.config(yscrollcommand=self.canvas.yview)
self.canvas.config(xscrollcommand=self.canvas.xview)
self.sbarv.grid(row=0,column=1,sticky=N+S)
self.sbarh.grid(row=1,column=0,sticky=W+E)
self.canvas.config(scrollregion=(0,0,400,400))
def draw_line(self, xold, yold, x, y):
self.canvas.create_line(xold,yold,x,y,fill="blue",width=3,smooth=TRUE)
if __name__=="__main__":
root = Tk()
root.wm_title("Main Window")
v = Test(root)
v.test()
root.mainloop()
These lines are incorrect:
self.canvas.config(yscrollcommand=self.canvas.yview)
self.canvas.config(xscrollcommand=self.canvas.xview)
You're telling the canvas to scroll the canvas when the canvas scrolls. The yscrollcommand and xscrollcommand options typically need to call the set method of a scrollbar:
self.canvas.config(yscrollcommand=self.sbarv.set)
self.canvas.config(xscrollcommand=self.sbarh.set)
I want to share the solution I found in case someone in the future encounters this problem:
I only had encrust the two scrollbars into the same parent widget as the canvas itself. I mean:
self.sbarv=Scrollbar(self.top,orient=VERTICAL)
self.sbarh=Scrollbar(self.top,orient=HORIZONTAL)
Related
I want to do something that should be rather simple, but I'm struggling to make it work.
Basically I have 2 Tkinter windows (canvas_tk and control_tk).
In canvas_tk I want to show an image and draw a circle on top of it.
In control_tk I have an Entry to input the radius of the circle to be drawn.
In my code the critical line is at the very bottom of the code:
self.panel = tk.Label(canvas_tk, image=image)
If I make the label in the control_tk or if I dont specify the parent, it actually works fine and draws the circles in the control_tk window
However I want the circles to be drawn in the canvas_tk window
self.panel = tk.Label(image=image) # Works
self.panel = tk.Label(control_tk, image=image) # Works
self.panel = tk.Label(canvas_tk, image=image) # Fails
Here's my minimal code:
import tkinter as tk
from PIL import Image, ImageTk, ImageDraw
control_tk = tk.Tk()
canvas_tk = tk.Tk()
control_tk.geometry("300x300")
canvas_tk.geometry("900x900")
class Drawing:
def __init__(self):
# Numerical entry with a variable traced with callback to "on_change" function
self.radius_var = tk.IntVar()
self.radius_var.trace_variable("w", self.on_change)
tk.Entry(control_tk, textvariable=self.radius_var).grid()
# Initialize image and panel
self.image = Image.new('RGB', (1000, 1000))
self.panel = None
# mainloop for the two tkinter windows
control_tk.mainloop()
canvas_tk.mainloop()
def on_change(self, *args):
print("Value changed") # to check that function is being called
draw = ImageDraw.Draw(self.image)
draw.ellipse((50-self.radius_var.get(), 50-self.radius_var.get(),
50+self.radius_var.get(), 50+self.radius_var.get()),
outline='blue', width=3)
image = ImageTk.PhotoImage(self.image)
if self.panel: # update the image
self.panel.configure(image=image)
self.panel.image = image
else: # if it's the first time initialize the panel
self.panel = tk.Label(canvas_tk, image=image)
self.panel.image = image
self.panel.grid(sticky="w")
Drawing()
And the traceback error basically complains about image not existing
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 508, in get
return self._tk.getint(value)
_tkinter.TclError: expected integer but got ""
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/GIT/142-277-00_pyScuti2/test.py", line 29, in on_change
draw.ellipse((50-self.radius_var.get(), 50-self.radius_var.get(),
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 510, in get
return int(self._tk.getdouble(value))
_tkinter.TclError: expected floating-point number but got ""
Value changed
Value changed
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/GIT/142-277-00_pyScuti2/test.py", line 38, in on_change
self.panel = tk.Label(canvas_tk, image=image)
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2766, in __init__
Widget.__init__(self, master, 'label', cnf, kw)
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2299, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "pyimage1" doesn't exist
First of all, you should not use multiple Tk() instances. Second, you better not using trace() on tracking input change, use bind('<Return>', ...) to trigger drawing after user enters value and press Enter key. Below is a modified code based on yours:
import tkinter as tk
from PIL import Image, ImageTk, ImageDraw
control_tk = tk.Tk()
control_tk.geometry("300x300+800+600")
canvas_tk = tk.Toplevel() # use Toplevel instead of Tk
canvas_tk.geometry("900x900+10+10")
class Drawing:
def __init__(self):
# Numerical entry with a variable traced with callback to "on_change" function
self.radius_var = tk.IntVar()
entry = tk.Entry(control_tk, textvariable=self.radius_var)
entry.grid()
# binding Enter key on entry to trigger the drawing
entry.bind('<Return>', self.on_change)
# Initialize image and panel
self.image = Image.new('RGB', (1000, 1000))
self.panel = None
# mainloop for the main window
control_tk.mainloop()
def on_change(self, *args):
try:
radius = self.radius_var.get()
except:
print('Invalid number')
return
print("Value changed") # to check that function is being called
draw = ImageDraw.Draw(self.image)
draw.ellipse((50-radius, 50-radius, 50+radius, 50+radius),
outline='blue', width=3)
image = ImageTk.PhotoImage(self.image)
if self.panel:
self.panel.configure(image=image)
else:
self.panel = tk.Label(canvas_tk, image=image)
self.panel.grid(sticky='w')
self.panel.image = image
Drawing()
I want to change background color of complete canvas whenever a mouse hovers over it. Have this code for it. Minimal Example:
import tkinter as tk
class HoverCanvas(tk.Canvas):
def __init__(self, master, activebackground, **kw):
tk.Frame.__init__(self,master=master,**kw)
self.defaultBackground = self["background"]
self.activebackground = activebackground
self.bind("<Enter>", self.on_enter)
self.bind("<Leave>", self.on_leave)
def on_enter(self, e):
self.config(background=self.activebackground)
def on_leave(self, e):
self.config(background=self.defaultBackground)
root = tk.Tk()
root.geometry("1280x720")
canvas = HoverCanvas(root, 'red', bg='#212121', width=1280, height=720)
#canvas = tk.Canvas(root, bg='#212121', width=1280, height=720)
canvas.create_text(110, 15, fill="#304ffe", activefill='#6a1b9a', font="Times 14 bold", text="Soccer Data Scraper v1.0")
canvas.grid(row=0, column=0)
root.mainloop()
Color of canvas changes to red when mouse is pointed over it, if it's empty (see commented line).
However if I try to add a text, or any other widget on canvas, the program stops working and throws a cryptic error.
Traceback (most recent call last):
File "canvasbg.py", line 24, in <module>
canvas.create_text(110, 15, fill="#304ffe", activefill='#6a1b9a', font="Times 14 bold", text="Soccer Data Scraper v1.0")
File "C:\Program Files (x86)\Python37-32\lib\tkinter\__init__.py", line 2501, in create_text
return self._create('text', args, kw)
File "C:\Program Files (x86)\Python37-32\lib\tkinter\__init__.py", line 2477, in _create
*(args + self._options(cnf, kw))))
_tkinter.TclError: bad option "create": must be cget or configure
What is this error? Is there any way to change background color of canvas on cursor hover while also having other widgets/text in it ?
Any help appreciated. Thanks
Your class inherits from tk.Canvas
class HoverCanvas(tk.Canvas):
but you call the __init__ method of tk.Frame
tk.Frame.__init__(self,master=master,**kw)
You should call the __init__ method of tk.Canvas instead.
from tkinter import*
root = Tk()
shape = Canvas(root)
class GUI():
def __init__(self):
pass
def create_polygon(self, points, colour, posit):
try:
shape.delete(self.poly)
except:
pass
self.poly = shape.create_polygon(points, colour, posit)
self.poly.shape.grid(column=posit[0],row=posit[1])
polygon = GUI()
polygon.create_polygon([150,75,225,0,300,75,225,150],'yellow',[1,2])
I'm new to using tkinter and classes but I want to make a very simple class to create a regular polygon. The code in this program should delete any polygon previously made and then proceed to make a new polygon when the program is called but I keep getting an error that I don't understand. Also how would you go about drawing a hexagon instead?
Traceback (most recent call last):
File "//xsvr-02/Students/10SAMP_Al/HW/polygon creator.py", line 19, in <module>
polygon.create_polygon([150,75,225,0,300,75,225,150],'yellow',[1,2])
File "//xsvr-02/Students/10SAMP_Al/HW/polygon creator.py", line 15, in create_polygon
self.poly = shape.create_polygon(points, colour, posit)
File "C:\Python34\lib\tkinter\__init__.py", line 2305, in create_polygon
return self._create('polygon', args, kw)
File "C:\Python34\lib\tkinter\__init__.py", line 2287, in _create
*(args + self._options(cnf, kw))))
_tkinter.TclError: wrong # coordinates: expected an even number, got 11
It's just wrong call parametters.
If you want to change your code, this solution can help you.
Class GUI just inherits from Canvas and doesn't implement anything.
from Tkinter import*
root = Tk()
class GUI(Canvas):
'''inherits Canvas class (all Canvas methodes, attributes will be accessible)
You can add your customized methods here.
'''
def __init__(self,master,*args,**kwargs):
Canvas.__init__(self, master=master, *args, **kwargs)
polygon = GUI(root)
polygon.create_polygon([150,75,225,0,300,75,225,150], outline='gray',
fill='gray', width=2)
polygon.pack()
root.mainloop()
For more help add comments.
There is a main window with menu and the progressbar. A correspondence window with OK button opens upon menu command and the OK button starts the process (here: 3 sec. sleep).
The correspondence window is created via inheritance from a class I have not provided here (If required for answer, please let me know). The methods apply and ok override existing methods in the mother class.
Now my problem: Since the progressbar sits in the main window (class App) and progressbar(start) and progressbar(stop) in the correspondence window I somehow have to pass (start) and (stop) via the mother class tkSimpleDialog.Dialog to class App. So I thought I also override the __init__(self..) method, provide self. to progressbar.
How can I make this work?
import Tkinter, ttk, tkFileDialog, tkSimpleDialog, time, threading
class App:
def __init__(self, master, progressbar):
self.progress_line(master)
def progress_line (self, master):
self.progressbar = ttk.Progressbar(master, mode='indeterminate')
self.progressbar.place(anchor = 'ne', height = "20", width = "150", x = "175", y = "30")
class AppMenu(object):
def __init__(self, master, progressbar):
self.master = master
self.menu_bar()
def menu_bar(self):
menu_bar = Tkinter.Menu(self.master)
self.menu_bar = Tkinter.Menu(self.master)
self.master.config(menu=self.menu_bar)
self.create_menu = Tkinter.Menu(self.menu_bar, tearoff = False)
self.create_menu.add_command(label = "do", command = self.do)
self.menu_bar.add_cascade(label = "now", menu = self.create_menu)
def do(self):
do1 = Dialog(self.master, progressbar)
class Dialog(tkSimpleDialog.Dialog):
def __init__(self, parent, progressbar):
tkSimpleDialog.Dialog.__init__(self, parent, progressbar)
self.transient(parent)
self.parent = parent
self.result = None
self.progressbar = progressbar
body = Frame(self)
self.initial_focus = self.body(body)
body.pack(padx=5, pady=5)
self.buttonbox()
self.grab_set()
if not self.initial_focus:
self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.cancel)
self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50))
self.initial_focus.focus_set()
self.wait_window(self)
def ok(self, event=None):
self.withdraw()
self.start_foo_thread()
self.cancel()
def apply(self):
time.sleep(5)
def start_foo_thread(self):
global foo_thread
self.foo_thread = threading.Thread(target=self.apply)
self.foo_thread.daemon = True
self.progressbar.start()
self.foo_thread.start()
master.after(20, check_foo_thread)
def check_foo_thread(self):
if self.foo_thread.is_alive():
root.after(20, self.check_foo_thread)
else:
self.progressbar.stop()
master = Tkinter.Tk()
progressbar = None
app = App(master, progressbar)
appmenu = AppMenu(master, progressbar)
master.mainloop()
error messages:
first after clicking ok:
Exception in Tkinter callback
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1410, in __call__
File "ask-progressbar.py", line 57, in ok
self.start_foo_thread()
File "ask-progressbar.py", line 66, in start_foo_thread
self.progressbar.start()
AttributeError: Dialog2 instance has no attribute 'progressbar'
second: after closing app
Exception in Tkinter callback
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1410, in __call__
File "ask-progressbar.py", line 26, in do
do1 = Dialog2(self.master, progressbar)
File "ask-progressbar.py", line 33, in __init__
self.transient(parent)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1652, in wm_transient
TclError: can't invoke "wm" command: application has been destroyed
Below is a working version of your code. There were a number of issues I had to fix because you didn't change a number of things in the code from my answer to your other question about progressbars.
The answer to your main question here is basically that you have to pass the instance around and remember it when necessary in the various class instances involved so that their methods will have it available through theself argument when they need it. Also, the way you were trying to derive and override the tkSimpleDialog.Dialog base class methods was both over-complicated and incorrect as well.
Usually the best (and simplest) thing to do is just supply your own validate() and apply() methods since that's how it was designed to work. If you also need your own __init__() constructor, it's important to only pass parameters to the base class' method that it understands from within the one in the subclass. If you need more functionality, it can usually be provided via additional derived-class-only methods, that only it or other classes you've also created know about.
Anyway, here's what I ended-up with:
import Tkinter, ttk, tkFileDialog, tkSimpleDialog, time, threading
class App:
def __init__(self, master):
self.progress_line(master)
def progress_line(self, master):
# the value of "maximum" determines how fast progressbar moves
self._progressbar = ttk.Progressbar(master, mode='indeterminate',
maximum=4) # speed of progressbar
self._progressbar.place(anchor='ne', height="20", width="150",
x="175", y="30")
#property
def progressbar(self):
return self._progressbar # return value of private member
class AppMenu(object):
def __init__(self, master, progressbar):
self.master = master
self.menu_bar()
self.progressbar = progressbar
def menu_bar(self):
self.menu_bar = Tkinter.Menu(self.master)
self.master.config(menu=self.menu_bar)
self.create_menu = Tkinter.Menu(self.menu_bar, tearoff=False)
self.create_menu.add_command(label="do", command=self.do)
self.menu_bar.add_cascade(label="now", menu=self.create_menu)
def do(self):
Dialog(self.master, self.progressbar) # display the dialog box
class Dialog(tkSimpleDialog.Dialog):
def __init__(self, parent, progressbar):
self.progressbar = progressbar
tkSimpleDialog.Dialog.__init__(self, parent, title="Do foo?")
def apply(self):
self.start_foo_thread()
# added dialog methods...
def start_foo_thread(self):
self.foo_thread = threading.Thread(target=self.foo)
self.foo_thread.daemon = True
self.progressbar.start()
self.foo_thread.start()
master.after(20, self.check_foo_thread)
def check_foo_thread(self):
if self.foo_thread.is_alive():
master.after(20, self.check_foo_thread)
else:
self.progressbar.stop()
def foo(self): # some time-consuming function...
time.sleep(3)
master = Tkinter.Tk()
master.title("Foo runner")
app = App(master)
appmenu = AppMenu(master, app.progressbar)
master.mainloop()
Hope this helps.
Here's another, simpler, solution that doesn't require the use of threading -- so could be easier to use/adapt in your case. It calls the progressbar widget's update_idletasks() method multiple times during the time-consuming foo() function. Again, it illustrates how to pass the progressbar around to the various parts of the code that need it.
import Tkinter, ttk, tkFileDialog, tkSimpleDialog, time
class App:
def __init__(self, master):
self.progress_line(master)
def progress_line(self, master):
self._progressbar = ttk.Progressbar(master, mode='indeterminate')
self._progressbar.place(anchor='ne', height="20", width="150",
x="175", y="30")
#property
def progressbar(self):
return self._progressbar # return value of private member
class AppMenu(object):
def __init__(self, master, progressbar):
self.master = master
self.menu_bar()
self.progressbar = progressbar
def menu_bar(self):
self.menu_bar = Tkinter.Menu(self.master)
self.master.config(menu=self.menu_bar)
self.create_menu = Tkinter.Menu(self.menu_bar, tearoff=False)
self.create_menu.add_command(label="do foo", command=self.do_foo)
self.menu_bar.add_cascade(label="now", menu=self.create_menu)
def do_foo(self):
confirm = ConfirmationDialog(self.master, title="Do foo?")
self.master.update() # needed to completely remove conf dialog
if confirm.choice:
foo(self.progressbar)
class ConfirmationDialog(tkSimpleDialog.Dialog):
def __init__(self, parent, title=None):
self.choice = False
tkSimpleDialog.Dialog.__init__(self, parent, title=title)
def apply(self):
self.choice = True
def foo(progressbar):
progressbar.start()
for _ in range(50):
time.sleep(.1) # simulate some work
progressbar.step(10)
progressbar.update_idletasks()
progressbar.stop()
master = Tkinter.Tk()
master.title("Foo runner")
app = App(master)
appmenu = AppMenu(master, app.progressbar)
master.mainloop()
I'm new to python. I'm trying to open a dialog box to get a value from within a widget that does a list of other staff allready.
But getting errors and can't figure out what to do.
Here's my code:
import Tkinter,Tkconstants,tkFileDialog
from Tkinter import *
import csv
import numpy
import math
import numpy.random as nrnd
import matplotlib.pyplot as plt
import shutil
import tkMessageBox
global filesavepath
class App:
def __init__(self,master):
self.mymaster=master
frame=Frame(master)
frame.pack()
self.importbutton=Button(frame,text='Import Data',command=self.importdata)
self.importbutton.pack()
self.executebutton=Button(frame,text='Execute',command=self.popup)
self.executebutton.pack()
self.distribution_rep=Button(frame,text='Repeat Purchase Score Distribution',command=self.distrepbutton)
self.distribution_rep.pack()
self.distribution_churn=Button(frame,text='Churn Probability Distribution',command=self.distchurnbutton)
self.distribution_churn.pack()
self.exitbutton=Button(frame,text='Exit',command=self.exitapp)
self.exitbutton.pack()
self.file_opt=options={}
options['defaultextension']=''
options['filetypes']=[('allfiles','.*'),('textfiles','.txt')]
options['initialdir']='C:\\'
options['initialfile']='myfile.txt'
options['parent']=root
options['title']='Thisisatitle'
def importdata(self):
filename=tkFileDialog.askopenfilename(**self.file_opt)
filesavepath="C:/input_full.csv"
shutil.copy2(filename,filesavepath)
if filename:
return open(filename,'r')
def popup(self):
top = self.top = Tkinter.Toplevel(self)
myLabel = Tkinter.Label(top, text='Enter your username below')
myLabel.pack()
self.myEntryBox = Tkinter.Entry(top)
self.myEntryBox.pack()
mySubmitButton = Tkinter.Button(top, text='Done', command=self.execbutton)
mySubmitButton.pack()
def execbutton(self):
if self.myEntryBox.get() != "":
self.timevalue = self.myEntryBox.get()
self.top.destroy()
execfile("Repeat Purchase Algo in python v6")
tkMessageBox.showinfo("Job Done", "Probability Computation completed")
def send(self):
global timevalue
timevalue=self.myEntryBox.get()
self.top.destroy()
def distrepbutton(self):
plt.hist(prob,bins=10,normed=TRUE)
plt.xlabel('Probability')
plt.title('Histogram of Repeat Purchase Probability')
plt.show()
def distchurnbutton(self):
plt.hist(churn_prob,bins=10,normed=TRUE)
plt.ylabel('Probability')
plt.title('Histogram of Churn Probability')
plt.show()
def exitapp(self):
self.mymaster.destroy()
root=Tk()
root.title('Repeat Puchase Widget')
app=App(root)
root.mainloop()
So as may be apparent to you, I'm importing dataset with an Import button, executing some analysis in another code through a button called Execute, and then showing some graphs.
What I wanted was to open a pop up kind of window on click of "Execute" button that will input a value. But I'm getting the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:/Python27/widget_repeat_purchase_v4", line 42, in popup
top = self.top = Tkinter.Toplevel(self)
File "C:\Python27\lib\lib-tk\Tkinter.py", line 2017, in __init__
BaseWidget.__init__(self, master, 'toplevel', cnf, {}, extra)
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1965, in __init__
BaseWidget._setup(self, master, cnf)
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1943, in _setup
self.tk = master.tk
AttributeError: App instance has no attribute 'tk'
I've no idea what to do. Please help.
When you create the toplevel widget, you are passing self as the first argument. Tkinter requires that this be a parent widget. However, in your code self does not represent a widget.
In your specific case you want to pass in self.mymaster rather than self:
top = self.top = Tkinter.Toplevel(self.mymaster)
Use Tkinter.Toplevel() instead of Tkinter.Toplevel(self)