Asked  6 Months ago    Answers:  5   Viewed   22 times

I'm new to Python and trying to write a program with tkinter. Why is the Hello-function below executed? As I understand it, the callback would only be executed when the button is pressed? I am very confused...

>>> def Hello():
        print("Hi there!")

>>> hi=Button(frame,text="Hello",command=Hello())
Hi there!
>>> 

 Answers

22

It is called while the parameters for Button are being assigned:

command=Hello()

If you want to pass the function (not it's returned value) you should instead:

command=Hello

in general function_name is a function object, function_name() is whatever the function returns. See if this helps further:

>>> def func():
...     return 'hello'
... 
>>> type(func)
<type 'function'>
>>> type(func())
<type 'str'>

If you want to pass arguments, you can use a lambda expression to construct a parameterless callable.

>>> hi=Button(frame, text="Hello", command=lambda: Goodnight("Moon"))

Simply put, because Goodnight("Moon") is in a lambda, it won't execute right away, instead waiting until the button is clicked.

Tuesday, June 1, 2021
 
lewiguez
answered 6 Months ago
37

Your anonymous lambda functions are can be though of as closures (as @abernert points out, they're not actually closures in Python's case) - they "close over" the variable i, to reference it later. However, they don't look up the value at the time of definition, but rather at the time of calling, which is some time after the entire while loop is over (at which point, i is equal to 10).

To fix this, you need to re-bind the value of i to a something else for the lambda to use. You can do this in many ways - here's one:

...
i = 1
while i < 10:
    # Give a parameter to the lambda, defaulting to i (function default
    # arguments are bound at time of declaration)
    newButton = Button(F, text="Show Number",
        command=lambda num=i: showNumber(num))
    ...
Tuesday, June 15, 2021
 
Pwner
answered 6 Months ago
36

In the case of Arraylist string objects the added elements are getting retrived. In case of String the method call has no effect on the String being passed.

It happens cause Java is Pass-by-Value and Strings are immutable

When you call

markAsNull(ArrayList<String> str)

The a new reference by name str is created for the same ArrayList pointed by al. When you add an element on str it gets added to same object. Later you put str to null but the object has the new values added and is pointed by a1.

When you call

markStringAsNull(String str)
{
    str = str + "Append me";
    // ...
}

The line str = str + "Append me"; creates a new String object by appending the given string and assignes it to str. but again it is just reference to actual string which now pointing to newly created string. (due to immutablity) and the original string is not changed.

Monday, August 2, 2021
 
Scott Kausler
answered 4 Months ago
90

I suspect that it is a kotlin compiler bug. Problem here is in interface IntStack which is implemented by IntArrayList:

interface Stack<T> {
    void push(T t);
}

interface IntStack extends Stack<Integer> {
    void push(int i);
}

Kotlin sees only one method push(Int) in interface IntStack, or, more precisely, kotlin wrongly supposes that push(int i) is an override of method push(T t).

Wednesday, August 4, 2021
 
Kumar V
answered 4 Months ago
37

If you want to pass the actual widget into the callback, you can do it like this:

button1 = Button(master, text='Search')
button1.configure(command=lambda widget=button1: DoSomething(widget))
button2 = Button(master, text='Search')
button2.configure(command=lambda widget=button2: DoSomething(widget))

Another choice is to simply pass in a literal string if you don't really need a reference to the widget:

button1 = Button(..., command=lambda widget="button1": DoSomething(widget))
button2 = Button(..., command=lambda widget="button2": DoSomething(widget))

Another choice is to give each button a unique callback, and have that callback do only the thing that is unique to that button:

button1 = Button(..., command=ButtonOneCallback)
button2 = Button(..., command=ButtonTwoCallback)

def ButtonOneCallback():
    value = user_input.get()
    DoSomething(value)

def ButtonTwoCallback():
    value=choice.get(choice.curselection()[0])
    DoSomething(value)

def DoSomething(value):
    ...

There are other ways to solve the same problem, but hopefully this will give you the general idea of how to pass values to a button callback, or how you can avoid needing to do that in the first place.

Saturday, August 14, 2021
 
Chania
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share