•
•
•
•
What is DaniWeb IT Discussion Community?
You're currently browsing the Python section within the Software Development category of DaniWeb, a massive community of 375,170 software developers, web developers, Internet marketers, and tech gurus who are all enthusiastic about making contacts, networking, and learning from each other. In fact, there are 2,204 IT professionals currently interacting right now! Registration is free, only takes a minute and lets you enjoy all of the interactive features of the site.
Please support our Python advertiser:
Views: 2205 | Replies: 19
![]() |
•
•
Join Date: Jul 2006
Posts: 562
Reputation:
Rep Power: 4
Solved Threads: 71
Sorry Haze; I mistook "not exactly high priority" to mean "not worth investing in." 
This line
does the following:
* creates a new Text widget
* calls its .grid() method, which returns None
* then assigns it to root.input_text
So no matter what, root.input_text == None, NOT a Text widget.
Then later, when you call disable(), Surprise! 'None' doesn't have any methods.
BTW, in debugging things like this, I *always* print values of variables just to make sure that they are what I think they are...
What you really want is this:
Now with regard to the second problem,
You can probably predict why the root.button is disabled from the beginning -- when you create root.button2, you *call* disable(root.button)!
So in your code, the act of creating root.button2 causes root.button to be disabled. Definitely not what you wanted.
I would solve your problem by using classes. What you want, if I read correctly, is for a bunch of buttons to have their own special "targets" that they can disable. Yes?
So what you really want is a type of Button() with a disable function attached to it. That calls for a new class that inherits from Button:
There's a couple things that need explaining. First, the __init__ method for Button can take a lot of arguments. The **kw refers to all of the configuration arguments like width= and height=. cnf is a less commonly used way to package those configuration options into a dictionary. Rather than spell all those arguments out, I just package them up and pass them upstairs to Button.__init__.
Second, notice that this way of doing things allows you to specify a different target for each individual DisablerButton widget. I think this is what you wanted.
Can you see why a class is required to do this?
Jeff

This line
Python Syntax (Toggle Plain Text)
root.input_text = Text(root, height = 10, width = 25).grid(row = 1, column = 1, sticky = N+S+E+W)
does the following:
* creates a new Text widget
* calls its .grid() method, which returns None
* then assigns it to root.input_text
So no matter what, root.input_text == None, NOT a Text widget.
Then later, when you call disable(), Surprise! 'None' doesn't have any methods.
BTW, in debugging things like this, I *always* print values of variables just to make sure that they are what I think they are...
What you really want is this:
Python Syntax (Toggle Plain Text)
root.input_text = Text(root, height = 10, width = 25) root.input_text.grid(row = 1, column = 1, sticky = N+S+E+W)
Now with regard to the second problem,
Python Syntax (Toggle Plain Text)
def disable(widget): widget["state"] = DISABLED root.button2 = Button(root, text="Disable the Radiobutton", command=disable(root.button))
You can probably predict why the root.button is disabled from the beginning -- when you create root.button2, you *call* disable(root.button)!
So in your code, the act of creating root.button2 causes root.button to be disabled. Definitely not what you wanted.
I would solve your problem by using classes. What you want, if I read correctly, is for a bunch of buttons to have their own special "targets" that they can disable. Yes?
So what you really want is a type of Button() with a disable function attached to it. That calls for a new class that inherits from Button:
Python Syntax (Toggle Plain Text)
from Tkinter import * class DisablerButton(Button): def __init__(self, master, target, cnf={}, **kw): Button.__init__(self, master, cnf, **kw) self.target = target self['command'] = self.disable def disable(self): self.target["state"] = DISABLED mainw = Tk() mainw.b1 = Button(mainw, height=5,width=10, text="My Button") mainw.b2 = DisablerButton(mainw, mainw.b1, height=5, width=10, text="Press Me!") mainw.b3 = DisablerButton(mainw, mainw.b2, height=5,width=10, text="Me Too!") mainw.b1.grid() mainw.b2.grid() mainw.b3.grid() mainw.mainloop()
There's a couple things that need explaining. First, the __init__ method for Button can take a lot of arguments. The **kw refers to all of the configuration arguments like width= and height=. cnf is a less commonly used way to package those configuration options into a dictionary. Rather than spell all those arguments out, I just package them up and pass them upstairs to Button.__init__.
Second, notice that this way of doing things allows you to specify a different target for each individual DisablerButton widget. I think this is what you wanted.
Can you see why a class is required to do this?
Jeff
•
•
Join Date: Nov 2006
Posts: 23
Reputation:
Rep Power: 2
Solved Threads: 0
ok i understand the first problem now. The second problem i also understand (a bit) but for your example you used a button and what i was planning to use it with was a radiobutton so i tried it.
Obviously this doesnt work because i havent put enough in the .add_abler_radiobutton part. but i dont know exactly what to put in because the creation of this radiobutton was a lot more complicated compared to the creation of a button.
Also another question, why does the disable function have to be indented so that its created along with the class? and why is self.disable not disable(self)? and what exactly does the "button.__init__" line do.
sorry if this is to many questions i just dont like using code when i have no idea what said code actully does.
from Tkinter import *
class abler_radiobutton(Radiobutton):
def __init__(self, master, target, cnf={}, **kw):
Radiobutton.__init__(self, master, cnf, **kw)
self.target = target
self['command'] = self.disable
def disable(self):
self.disable_target['state'] = DISABLED
root = Tk()
root.input_text = Text(root, height = 10, width = 25)
root.input_text.grid(row = 1, column = 1, sticky = N+S+E+W)
root.mainbar_menu = Menu(root)
root.input_menu = Menu(root.mainbar_menu)
root.mainbar_menu.add_cascade(label='Input Options', menu = root.input_menu)
root.input_menu.add_abler_radiobutton(label='Input From File')
root.config(menu=root.mainbar_menu)
root.mainloop()Obviously this doesnt work because i havent put enough in the .add_abler_radiobutton part. but i dont know exactly what to put in because the creation of this radiobutton was a lot more complicated compared to the creation of a button.
Also another question, why does the disable function have to be indented so that its created along with the class? and why is self.disable not disable(self)? and what exactly does the "button.__init__" line do.
sorry if this is to many questions i just dont like using code when i have no idea what said code actully does.
•
•
Join Date: Nov 2006
Posts: 23
Reputation:
Rep Power: 2
Solved Threads: 0
ok i understand the first problem now. The second problem i also understand (a bit) but for your example you used a button and what i was planning to use it with was a radiobutton so i tried it.
Obviously this doesnt work because i havent put enough in the .add_abler_radiobutton part. but i dont know exactly what to put in because the creation of this radiobutton was a lot more complicated compared to the creation of a button.
Also another question, why does the disable function have to be indented so that its created along with the class? and why is self.disable not disable(self)? and what exactly does the "button.__init__" line do.
sorry if this is to many questions i just dont like using code when i have no idea what said code actully does.
from Tkinter import *
class abler_radiobutton(Radiobutton):
def __init__(self, master, target, cnf={}, **kw):
Radiobutton.__init__(self, master, cnf, **kw)
self.target = target
self['command'] = self.disable
def disable(self):
self.disable_target['state'] = DISABLED
root = Tk()
root.input_text = Text(root, height = 10, width = 25)
root.input_text.grid(row = 1, column = 1, sticky = N+S+E+W)
root.mainbar_menu = Menu(root)
root.input_menu = Menu(root.mainbar_menu)
root.mainbar_menu.add_cascade(label='Input Options', menu = root.input_menu)
root.input_menu.add_abler_radiobutton(label='Input From File')
root.config(menu=root.mainbar_menu)
root.mainloop()Obviously this doesnt work because i havent put enough in the .add_abler_radiobutton part. but i dont know exactly what to put in because the creation of this radiobutton was a lot more complicated compared to the creation of a button.
Also another question, why does the disable function have to be indented so that its created along with the class? and why is self.disable not disable(self)? and what exactly does the "button.__init__" line do.
sorry if this is to many questions i just dont like using code when i have no idea what said code actully does.
•
•
Join Date: Jul 2006
Posts: 562
Reputation:
Rep Power: 4
Solved Threads: 71
No, it's perfectly fine to insist on complete clarity. That's what good coding is all about.
The disable function needs to be a part of the class because you want it to be something that only DisablerButtons can do. AND, you want each DisablerButton to have its own copy of disable(), so that it can disable its own target.
If you made disable() a public function, outside the class scope, then there would be no easy way to tell disable which target to disable.
But since each DisablerButton has its own copy of the disable() method, the problem is solved: disable operates on self.target.
The reason for the syntax
self.disable
instead of
disable(self)
is that a method is always written in terms of its parent. Try this:
'hi there'.reverse()
Semantically, Python turns 'self.method(arg1, arg2)'
into 'method(self,arg1,arg2)'. But the distinction is made syntactically between the parent (self) and the other arguments so that humans can read it more clearly.
The Button.__init__() line is needed because DisablerButton inherits its properties and methods from Button. Normally, there's a lot that happens behind the scenes when a Button widget is created. All of this occurs in the __init__ method of Button. So DisablerButton calls Button.__init__ to make sure that all of those things happen, like construction of the widget, attachment to mainw, things like that that you don't want to worry about.
Bottom line: it's usually a good idea for children to call the parent's __init__ method.
Hope it helps, and I'll think about the radiobutton problem later.
Jeff
The disable function needs to be a part of the class because you want it to be something that only DisablerButtons can do. AND, you want each DisablerButton to have its own copy of disable(), so that it can disable its own target.
If you made disable() a public function, outside the class scope, then there would be no easy way to tell disable which target to disable.
But since each DisablerButton has its own copy of the disable() method, the problem is solved: disable operates on self.target.
The reason for the syntax
self.disable
instead of
disable(self)
is that a method is always written in terms of its parent. Try this:
'hi there'.reverse()
Semantically, Python turns 'self.method(arg1, arg2)'
into 'method(self,arg1,arg2)'. But the distinction is made syntactically between the parent (self) and the other arguments so that humans can read it more clearly.
The Button.__init__() line is needed because DisablerButton inherits its properties and methods from Button. Normally, there's a lot that happens behind the scenes when a Button widget is created. All of this occurs in the __init__ method of Button. So DisablerButton calls Button.__init__ to make sure that all of those things happen, like construction of the widget, attachment to mainw, things like that that you don't want to worry about.
Bottom line: it's usually a good idea for children to call the parent's __init__ method.
Hope it helps, and I'll think about the radiobutton problem later.
Jeff
•
•
Join Date: Jul 2006
Posts: 562
Reputation:
Rep Power: 4
Solved Threads: 71
This is a first draft of what you might want. The radiobutton has a 'command' feature that allows you to supply a callback when it is activated, so I eliminated the need for a separate class. The only problem with this so far is that you can't supply a target, but I know how to fix that. See if you understand this first and whether it's along the lines of what you are trying for:
Python Syntax (Toggle Plain Text)
from Tkinter import * def disable(): print "disabling" root.button['state'] = DISABLED def enable(): print "enabling" root.button['state'] = ACTIVE def button_com(): print "hi" root = Tk() root.input_text = Text(root, height = 10, width = 25) root.input_text.grid(row = 1, column = 1, sticky = N+S+E+W) root.mainbar_menu = Menu(root) root.input_menu = Menu(root.mainbar_menu) root.mainbar_menu.add_cascade(label='Input Options', menu = root.input_menu) root.button = Button(root, text="Swill", command = button_com) root.button.grid() root.input_menu.add_radiobutton(label='Input From File', command=disable) root.input_menu.add_radiobutton(label='Input from Pipe', command=enable) root.input_menu.add_radiobutton(label='Input from Stream', command=enable) root.config(menu=root.mainbar_menu) root.mainloop()
Last edited by jrcagle : Sep 11th, 2007 at 9:49 pm.
•
•
Join Date: Jul 2006
Posts: 562
Reputation:
Rep Power: 4
Solved Threads: 71
I think this'll work for you, if the above was heading in the right direction:
It needs some explanation...
The function 'disable_factory' creates a new function to disable the target every time it is called. That new function is then returned.
At creation of the radiobutton, Tkinter *calls* the disable_factory(root.button). disable_factory then returns a function f that can disable root.button. It is that function f that becomes the command for the radiobutton.
Here's the timeline:
Likewise for enable_factory()
Does that make sense?
Note: doing it all within a class is conceptually cleaner. But because of the limitations of the Menu widget -- it can only add certain prespecified widgets, like the radiobutton -- we had to go this route.
Jeff
Python Syntax (Toggle Plain Text)
from Tkinter import * def disable_factory(target): def f(): target['state'] = DISABLED return f def enable_factory(target): def f(): target['state'] = ACTIVE return f def button_com(): print "hi" root = Tk() root.input_text = Text(root, height = 10, width = 25) root.input_text.grid(row = 1, column = 1, sticky = N+S+E+W) root.mainbar_menu = Menu(root) root.input_menu = Menu(root.mainbar_menu) root.mainbar_menu.add_cascade(label='Input Options', menu = root.input_menu) root.button = Button(root, text="Swill", command = button_com) root.button.grid() root.input_menu.add_radiobutton(label='Input From File', command=disable_factory(root.button)) root.input_menu.add_radiobutton(label='Input from Pipe', command=enable_factory(root.button)) root.input_menu.add_radiobutton(label='Input from Stream', command=enable_factory(root.button)) root.config(menu=root.mainbar_menu) root.mainloop()
It needs some explanation...
The function 'disable_factory' creates a new function to disable the target every time it is called. That new function is then returned.
At creation of the radiobutton, Tkinter *calls* the disable_factory(root.button). disable_factory then returns a function f that can disable root.button. It is that function f that becomes the command for the radiobutton.
Here's the timeline:
•
•
•
•
Originally Posted by timeline
Widget Creation Time:
disable_factory(root.button) --> f = "root.button['state'] = DISABLED"
.add_radiobutton(..., command = f)
Widget RunTime:
user clicks radiobutton --> f is called --> Swill button disabled.
Does that make sense?
Note: doing it all within a class is conceptually cleaner. But because of the limitations of the Menu widget -- it can only add certain prespecified widgets, like the radiobutton -- we had to go this route.
Jeff
![]() |
•
•
•
•
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
•
•
•
•
•
•
•
•
DaniWeb Python Marketplace
- Windows GUI - problem with dialog box (C++)
- Python GUI (Python)
- Python GUI build: Logic Complications and Mistakes (Python)
- A subtle python cgi problem (Python)
- Problem with find (Python)
- starting Python (Python)
- Java GUI problem... contents of JFrame is invisible... (Java)
- My Irritating Error - Help (Python)
- basic java GUI problem (Java)
Other Threads in the Python Forum
- Previous Thread: Moola Gold Rush Solver
- Next Thread: How do I declare a class member function in another class?


Linear Mode