S
Saul Spatz
To the good people on comp.lang.python:
I have the following Tkinter class (python 2.7.3):
from Tkinter import *
class ScrolledCanvas(Frame):
def __init__(self, master, width, height, bg, cursor):
Frame.__init__(self, master)
self.__nonzero__ = lambda: True
canv = self.canvas = Canvas(self, bg=bg, relief=SUNKEN)
# self.__getattr__ = lambda x, name: getattr(self.canvas, name)
canv.config(width=width, height=height) # display area size
canv.config(scrollregion=(0, 0, width, height)) # canvas size corners
canv.config(highlightthickness=0) # no pixels to border
ybar = Scrollbar(self)
ybar.config(command=canv.yview) # xlink sbar and canv
canv.config(yscrollcommand=ybar.set) # move one moves other
xbar = Scrollbar(self)
xbar.config(command=canv.xview) # xlink sbar and canv
canv.config(xscrollcommand=xbar.set) # move one moves other
canv.grid(row = 0, column = 0, sticky = 'news')
ybar.grid(row = 0, column = 1, sticky = 'ns')
xbar.grid(row = 1, column = 0, sticky = 'ew')
self.rowconfigure(0, weight = 1)
self.columnconfigure(0, weight = 1)
self.create_text(20, 20, text = 'Did it!', fill = 'red')
def __getattr__(self, name):
return getattr(self.canvas, name)
root = Tk()
app = ScrolledCanvas(root, 400, 300, 'white', 'hand2')
app.pack()
root.mainloop()
I just added the __getattr__ method, and the program crashed in the Canvas constructor. There is apparently a call to self.__nonzero__ somewhere in Tkinter.py, and since the constructor hasn't exited yet, sel.fcanvas isn't defined yet, so __getattr__ recurses indefinitely.
I fixed this as you see, by defining self.__nonzero__ before the call to the constructor. Now, I have two questions:
1. I originally defined self.__nonzero__ = lambda x: True, on the assumption that when self.__nonzero__ was called, the interpreter would pass self as an argument. Wrong. No arguments were passed. Why is this?
2. I find this solution rather unsatisfactory, since there's a rather obscure line of code here. I tried eliminating the def of __gertattr__ and the definition of self.__nonzero__ and adding this line after the constructor:
self.__getattr__= lambda name: getattr(self.canvas, name)
This get through the constructor all right, but crashes with the message that a ScrolledCanvas object has no create_text attribute. (I've tried passing two arguments to the lambda, but it makes no difference.)
I don't understand what's going on at all. Can't I dynamically define __getattr__? How should I go about it? By the way, another thing that didn't work was calling the method delegate instead of __getattr__. Then after the constructor call, I wrote
self.__getattr__ = self.delegate. This crashed as before on self.create_text.
I just tried a little experiment with __add__ and had no success, so I guess my problem is with overloaded operators in general.
I'd really appreciate an explanation, or a pointer to relevant documentation.
I have the following Tkinter class (python 2.7.3):
from Tkinter import *
class ScrolledCanvas(Frame):
def __init__(self, master, width, height, bg, cursor):
Frame.__init__(self, master)
self.__nonzero__ = lambda: True
canv = self.canvas = Canvas(self, bg=bg, relief=SUNKEN)
# self.__getattr__ = lambda x, name: getattr(self.canvas, name)
canv.config(width=width, height=height) # display area size
canv.config(scrollregion=(0, 0, width, height)) # canvas size corners
canv.config(highlightthickness=0) # no pixels to border
ybar = Scrollbar(self)
ybar.config(command=canv.yview) # xlink sbar and canv
canv.config(yscrollcommand=ybar.set) # move one moves other
xbar = Scrollbar(self)
xbar.config(command=canv.xview) # xlink sbar and canv
canv.config(xscrollcommand=xbar.set) # move one moves other
canv.grid(row = 0, column = 0, sticky = 'news')
ybar.grid(row = 0, column = 1, sticky = 'ns')
xbar.grid(row = 1, column = 0, sticky = 'ew')
self.rowconfigure(0, weight = 1)
self.columnconfigure(0, weight = 1)
self.create_text(20, 20, text = 'Did it!', fill = 'red')
def __getattr__(self, name):
return getattr(self.canvas, name)
root = Tk()
app = ScrolledCanvas(root, 400, 300, 'white', 'hand2')
app.pack()
root.mainloop()
I just added the __getattr__ method, and the program crashed in the Canvas constructor. There is apparently a call to self.__nonzero__ somewhere in Tkinter.py, and since the constructor hasn't exited yet, sel.fcanvas isn't defined yet, so __getattr__ recurses indefinitely.
I fixed this as you see, by defining self.__nonzero__ before the call to the constructor. Now, I have two questions:
1. I originally defined self.__nonzero__ = lambda x: True, on the assumption that when self.__nonzero__ was called, the interpreter would pass self as an argument. Wrong. No arguments were passed. Why is this?
2. I find this solution rather unsatisfactory, since there's a rather obscure line of code here. I tried eliminating the def of __gertattr__ and the definition of self.__nonzero__ and adding this line after the constructor:
self.__getattr__= lambda name: getattr(self.canvas, name)
This get through the constructor all right, but crashes with the message that a ScrolledCanvas object has no create_text attribute. (I've tried passing two arguments to the lambda, but it makes no difference.)
I don't understand what's going on at all. Can't I dynamically define __getattr__? How should I go about it? By the way, another thing that didn't work was calling the method delegate instead of __getattr__. Then after the constructor call, I wrote
self.__getattr__ = self.delegate. This crashed as before on self.create_text.
I just tried a little experiment with __add__ and had no success, so I guess my problem is with overloaded operators in general.
I'd really appreciate an explanation, or a pointer to relevant documentation.