LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-13-2009, 01:50 PM   #1
deathalele
Member
 
Registered: May 2008
Location: deep dark north wales
Distribution: Zenwalk
Posts: 162

Rep: Reputation: 30
python, tkinter, command is executed when program is run not when button clicked


Quote:
from Tkinter import *

class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.grid()
self.createWidgets()

def createWidgets(self):
def hello_world(cnvs):
id = cnvs.create_line(10, 10, 90, 10)

self.cnvs = Canvas (bg='red', height=100, width=100)
self.cnvs.grid(row=4, column=1, sticky=N)

self.newbtn = Button ( self, text="Draw Line", command=hello_world(self.cnvs))
self.newbtn.grid(row=3, column=1)


app = Application()
app.master.title("Sample application")
app.mainloop()
when i run this program the line is draw in the canvas as soon as the program is run, not when the button is clicked. Also when i click the button nothing happens,

help please

thanks in advance
 
Old 06-14-2009, 03:40 AM   #2
pgpython
Member
 
Registered: Dec 2005
Location: Sheffield, UK
Distribution: Gentoo
Posts: 142

Rep: Reputation: 32
First of all your indentation makes it difficult to see which commands belongs to which methods. I am going to assume that the indentation in your program is mostly correct or it wouldnt run. Without seeing the correct indentation you have used. I would say that the command to draw the line isn't indented propely.
 
Old 06-15-2009, 05:02 AM   #3
deathalele
Member
 
Registered: May 2008
Location: deep dark north wales
Distribution: Zenwalk
Posts: 162

Original Poster
Rep: Reputation: 30
sorry i was using tabs for indentation which got lost when i posted,

here it is using spaces

Code:
from Tkinter import *

class Application(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.grid()
        self.createWidgets()

    def createWidgets(self):
        def hello_world(cnvs):
            id = cnvs.create_line(10, 10, 90, 10)

        self.cnvs = Canvas (bg='red', height=100, width=100)
        self.cnvs.grid(row=4, column=1, sticky=N)

        self.newbtn = Button ( self, text="Draw Line", command=hello_world(self.cnvs))

        self.newbtn.grid(row=3, column=1)


app = Application()
app.master.title("Sample application")
app.mainloop()
I'm pretty sure it's not indentation but i could be wrong
 
Old 06-15-2009, 06:26 AM   #4
pgpython
Member
 
Registered: Dec 2005
Location: Sheffield, UK
Distribution: Gentoo
Posts: 142

Rep: Reputation: 32
Ok I see your problem here and you need to regoranise you code.

First of all you have a function inside a function. This isn't a good thing to do in python unless you need a closure which you don't. You could do any of the following to improve it:

a) You could move hello_world outside the Application class
b) make hello_world a method of the Application class
c) Create a new class for the Canvas and make hello_world a method of that
d) Get rid of hello_world entirely and use lambda instead

Any of which would be better and which you chose depends on how and where you want the function to be called.

Your going to have to do this this anyway because what you have told python here:

Code:
self.newbtn = Button ( self, text="Draw Line", command=hello_world(self.cnvs))
is create a new Button called self.newbutn with the parameter of self, the value of the text "Draw Line" and the value of command to be whatever hello_world(self.cnvs) evaluates as which is None. Which is not what you wanted. What you wanted to say is:

Code:
self.newbtn = Button ( self, text="Draw Line", command=hello_world)
Note you cannot pass self.cnvs to the command because what You are passing is a function object to be called later. Hence why you need to reorganise the code a bit.

Last edited by pgpython; 06-15-2009 at 06:27 AM.
 
Old 06-15-2009, 02:12 PM   #5
deathalele
Member
 
Registered: May 2008
Location: deep dark north wales
Distribution: Zenwalk
Posts: 162

Original Poster
Rep: Reputation: 30
Code:
from Tkinter import *


class Application(Frame):
        def __init__(self, master=None):
                Frame.__init__(self, master)
                self.grid()
                self.createWidgets()

        def createWidgets(self):

                self.cnvs =  Canvas (bg='red', height=100, width=100)
                self.cnvs.grid(row=4, column=1, sticky=N)
                self.newbtn = Button ( self, text="Draw Line", command=hello_world)
                self.newbtn.grid(row=3, column=1)

def hello_world():
        print 'HELLO WORLD'



app = Application()
app.master.title("Sample application")
app.mainloop()
I've got this to work, where it prints HELLO WORLD into stdout but how would i pass arguments to the function which is what i need now

thanks
 
Old 06-15-2009, 03:13 PM   #6
pgpython
Member
 
Registered: Dec 2005
Location: Sheffield, UK
Distribution: Gentoo
Posts: 142

Rep: Reputation: 32
if you really need to. There are 2 things you can do

1 create a function class and pass the attributes to the function:

In python a function is basically just an object with the method __call__ note the double underscore signifying its a special method. When a function gets called its __call__ which will get called so you could write something like:

Code:
class Command(object):

    def __init__(self, func, *args, **keywds):
          self.func = func
          self.args = args
          self.keywds = keywds

    def __call__(self);
           return self.func(*self.args, **self.keywds)
you can then create a Command object passing it the functions and any arguments and keyword arguments ready to be called later and it will behave as any other function

2. Using a closure, in python nested scopes are allowed. Hence why you can write hello_world inside of createWidgets using this technique you can write a function which will write a function. Particulary useful if the inner function functionality remains the same but what it operates on doesnt.

Code:
def factoryMethod(self, *args, **keywds):

      def myfunc(): pass #myfunc can see args and keywds
     
      return myfunc
you can call factoryMethod and myfunc functioned will be returned operating on the parameters passed initally to factoryMethod
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
How do I make python programs run without entering the command python? trist007 Programming 5 03-22-2009 08:21 PM
Error in basic button response program in Python 2.4 with the Tkinter module jojotx0 Programming 1 05-23-2006 07:43 PM
found with button was clicked djgerbavore Programming 2 06-29-2005 09:35 AM
Python and Tkinter 1337 Twinkie Fedora 2 08-03-2004 11:35 AM
Python: Tkinter. Chu Programming 0 11-10-2003 01:56 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:50 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration