User Name Password Register
DaniWeb IT Discussion Community
All
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
Reply
Join Date: Nov 2006
Posts: 23
Reputation: Haze is an unknown quantity at this point 
Rep Power: 2
Solved Threads: 0
Haze Haze is offline Offline
Newbie Poster

Re: Python GUI Problem

  #11  
Sep 5th, 2007
bump, anyone know or im i missing the point completely? and even if you dont know is there anywhere else i could post this so i could get a response? thanks.
Reply With Quote  
Join Date: Jul 2006
Posts: 562
Reputation: jrcagle is on a distinguished road 
Rep Power: 4
Solved Threads: 71
jrcagle jrcagle is offline Offline
Posting Pro

Re: Python GUI Problem

  #12  
Sep 5th, 2007
Sorry Haze; I mistook "not exactly high priority" to mean "not worth investing in."

This line

  1. 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:

  1. root.input_text = Text(root, height = 10, width = 25)
  2. root.input_text.grid(row = 1, column = 1, sticky = N+S+E+W)

Now with regard to the second problem,

  1. def disable(widget):
  2. widget["state"] = DISABLED
  3.  
  4. 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:

  1. from Tkinter import *
  2.  
  3. class DisablerButton(Button):
  4.  
  5. def __init__(self, master, target, cnf={}, **kw):
  6. Button.__init__(self, master, cnf, **kw)
  7. self.target = target
  8. self['command'] = self.disable
  9.  
  10. def disable(self):
  11. self.target["state"] = DISABLED
  12.  
  13. mainw = Tk()
  14. mainw.b1 = Button(mainw, height=5,width=10, text="My Button")
  15. mainw.b2 = DisablerButton(mainw, mainw.b1, height=5, width=10, text="Press Me!")
  16. mainw.b3 = DisablerButton(mainw, mainw.b2, height=5,width=10, text="Me Too!")
  17. mainw.b1.grid()
  18. mainw.b2.grid()
  19. mainw.b3.grid()
  20. 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
Reply With Quote  
Join Date: Nov 2006
Posts: 23
Reputation: Haze is an unknown quantity at this point 
Rep Power: 2
Solved Threads: 0
Haze Haze is offline Offline
Newbie Poster

Re: Python GUI Problem

  #13  
Sep 6th, 2007
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.

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.
Reply With Quote  
Join Date: Nov 2006
Posts: 23
Reputation: Haze is an unknown quantity at this point 
Rep Power: 2
Solved Threads: 0
Haze Haze is offline Offline
Newbie Poster

Re: Python GUI Problem

  #14  
Sep 6th, 2007
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.

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.
Reply With Quote  
Join Date: Jul 2006
Posts: 562
Reputation: jrcagle is on a distinguished road 
Rep Power: 4
Solved Threads: 71
jrcagle jrcagle is offline Offline
Posting Pro

Re: Python GUI Problem

  #15  
Sep 7th, 2007
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
Reply With Quote  
Join Date: Nov 2006
Posts: 23
Reputation: Haze is an unknown quantity at this point 
Rep Power: 2
Solved Threads: 0
Haze Haze is offline Offline
Newbie Poster

Re: Python GUI Problem

  #16  
Sep 7th, 2007
thanks for clarifying that, i will try to figure out the radiobutton thing aswel and sorry about the double post, i was having trouble with this website yesterday i kept getting database errors.
Reply With Quote  
Join Date: Nov 2006
Posts: 23
Reputation: Haze is an unknown quantity at this point 
Rep Power: 2
Solved Threads: 0
Haze Haze is offline Offline
Newbie Poster

Re: Python GUI Problem

  #17  
Sep 10th, 2007
just making sure my "i will try to figure out the radiobutton thing aswel" isnt being mistook for "dont bother posting"
Reply With Quote  
Join Date: Jul 2006
Posts: 562
Reputation: jrcagle is on a distinguished road 
Rep Power: 4
Solved Threads: 71
jrcagle jrcagle is offline Offline
Posting Pro

Re: Python GUI Problem

  #18  
Sep 10th, 2007
Duly bumped up.
Reply With Quote  
Join Date: Jul 2006
Posts: 562
Reputation: jrcagle is on a distinguished road 
Rep Power: 4
Solved Threads: 71
jrcagle jrcagle is offline Offline
Posting Pro

Re: Python GUI Problem

  #19  
Sep 11th, 2007
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:

  1. from Tkinter import *
  2.  
  3. def disable():
  4. print "disabling"
  5. root.button['state'] = DISABLED
  6.  
  7. def enable():
  8. print "enabling"
  9. root.button['state'] = ACTIVE
  10.  
  11. def button_com():
  12. print "hi"
  13.  
  14. root = Tk()
  15. root.input_text = Text(root, height = 10, width = 25)
  16. root.input_text.grid(row = 1, column = 1, sticky = N+S+E+W)
  17. root.mainbar_menu = Menu(root)
  18. root.input_menu = Menu(root.mainbar_menu)
  19. root.mainbar_menu.add_cascade(label='Input Options', menu = root.input_menu)
  20. root.button = Button(root, text="Swill", command = button_com)
  21. root.button.grid()
  22. root.input_menu.add_radiobutton(label='Input From File', command=disable)
  23. root.input_menu.add_radiobutton(label='Input from Pipe', command=enable)
  24. root.input_menu.add_radiobutton(label='Input from Stream', command=enable)
  25. root.config(menu=root.mainbar_menu)
  26. root.mainloop()
Last edited by jrcagle : Sep 11th, 2007 at 9:49 pm.
Reply With Quote  
Join Date: Jul 2006
Posts: 562
Reputation: jrcagle is on a distinguished road 
Rep Power: 4
Solved Threads: 71
jrcagle jrcagle is offline Offline
Posting Pro

Re: Python GUI Problem

  #20  
Sep 11th, 2007
I think this'll work for you, if the above was heading in the right direction:

  1. from Tkinter import *
  2.  
  3. def disable_factory(target):
  4. def f():
  5. target['state'] = DISABLED
  6. return f
  7.  
  8. def enable_factory(target):
  9. def f():
  10. target['state'] = ACTIVE
  11. return f
  12.  
  13. def button_com():
  14. print "hi"
  15.  
  16. root = Tk()
  17. root.input_text = Text(root, height = 10, width = 25)
  18. root.input_text.grid(row = 1, column = 1, sticky = N+S+E+W)
  19. root.mainbar_menu = Menu(root)
  20. root.input_menu = Menu(root.mainbar_menu)
  21. root.mainbar_menu.add_cascade(label='Input Options', menu = root.input_menu)
  22. root.button = Button(root, text="Swill", command = button_com)
  23. root.button.grid()
  24. root.input_menu.add_radiobutton(label='Input From File',
  25. command=disable_factory(root.button))
  26. root.input_menu.add_radiobutton(label='Input from Pipe',
  27. command=enable_factory(root.button))
  28. root.input_menu.add_radiobutton(label='Input from Stream',
  29. command=enable_factory(root.button))
  30. root.config(menu=root.mainbar_menu)
  31. 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.
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
Reply With Quote  
Reply

Only community members can participate in forum threads. You must register or log in to contribute.

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)

 

DaniWeb Python Marketplace
Thread Tools Display Modes

Similar Threads
Other Threads in the Python Forum

All times are GMT -4. The time now is 11:53 pm.
Forum system based on vBulletin Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
©2003 - 2008 DaniWeb® LLC