robertlugg / easygui

easygui for Python
http://easygui.readthedocs.org/en/master/
BSD 3-Clause "New" or "Revised" License
455 stars 114 forks source link

Using callback in textbox - how? #132

Closed fiddybux closed 6 years ago

fiddybux commented 6 years ago

Hi,

Following advice, I've been trying to refine my code to pass commands into easygui, which primarily helps with debugging. It's been going well, on balance.

However, I'm having difficulty with the callback function of the textbox.

I've read the following and I've failed to implement it functionally:

http://easygui.readthedocs.io/en/latest/api.html

Here is says that:

callback: function
if set, this function will be called when OK is pressed

None
If cancel is pressed

If I have callback set as follows, it does nothing, as expected:

if easygui.ynbox(msg_a, title_a):
    pass
    easygui.textbox(
        msg=msg_b, title=title_b, text=ans_y_filecont, callback=None)
else:
    easygui.textbox(
        msg=msg_b, title=title_c, text=ans_n_filecont, callback=None)

If I write my code as follows, it just quits (following issue of quit() command) as soon as the textbox is presented on screen, so the textbox immediately disappears:

callback_quit = quit()
if easygui.ynbox(msg_a, title_a):
    pass
    easygui.textbox(
        msg=msg_b, title=title_b, text=ans_y_filecont, callback=callback_quit)
else:
    easygui.textbox(
        msg=msg_b, title=title_c, text=ans_n_filecont, callback=callback_quit)

At least I know quit() is working, but why isn't it waiting until the callback on CANCEL button is pressed?

Am I implementing the callback function incorrectly?

Is there another function I should be calling with callback?

Thanks.

zadacka commented 6 years ago

Could you debug and confirm that the code is actually all being executed?

From that pass in the middle of your block it will be impossible for you to ever reach the code where you create the first textbox. If that is the textbox you are expecting to see, then your problem is nothing to do with the callback.

callback_quit = quit()
if easygui.ynbox(msg_a, title_a):
    pass  # pass will prevent the below line ever being executed
    easygui.textbox(
        msg=msg_b, title=title_b, text=ans_y_filecont, callback=callback_quit)
else:
    easygui.textbox(
        msg=msg_b, title=title_c, text=ans_n_filecont, callback=callback_quit)

In the event that this does not fix the problem, could you reduce the code sample to a smaller segment showing exactly the single EasyGUI call that causes problems? If I can re-produce it that would also be helpful - so it would be good to see what the argument values and callback are that you're using.

fiddybux commented 6 years ago

Hi,

Removing the 'pass' command did not fix the situation. I accept I should have been using it anyway; I included this because I totally misunderstood its function. I believed it would the YES option for a ynbox. I was wrong.

Anyway, removal didn't help.

I have re-written a bit of test code that you should be able to copy and paste verbatim. There are two examples:

import easygui

msg_conf = "Continue..."
title_choose = "Choose Y or N..."
msg_y = "You pressed Yes..."
title_y = "You're a Yes presser..."
msg_n = "You pressed No..."
title_n = "You're a No presser..."
text_y = "The rhythm is the bass"
text_n = "The bass is the treble"
if easygui.ynbox(msg=msg_conf, title=title_choose):
    easygui.textbox(
        msg=msg_y, title=title_y, text=text_y, callback=None)
else:
    easygui.textbox(
        msg=msg_n, title=title_n, text=text_n, callback=None)
msg_final = (
    "If you made it this far then perhaps it didn't exit on CANCEL button! "
    "Or you ended up here as a correct result of the OK button. "
    "Whether you press YES or CANCEL results in the same situation...here.")
title_final = "You made it! But was it by mistake or by design?"
easygui.textbox(msg=msg_final, title=title_final)

Here we have callback=None in both cases whether Y or N is selected from the if / else parts of the code.

If you swap-out the None element for quit(), like so:

import easygui

msg_conf = "Continue..."
title_choose = "Choose Y or N..."
msg_y = "You pressed Yes..."
title_y = "You're a Yes presser..."
msg_n = "You pressed No..."
title_n = "You're a No presser..."
text_y = "The rhythm is the bass"
text_n = "The bass is the treble"
if easygui.ynbox(msg=msg_conf, title=title_choose):
    easygui.textbox(
        msg=msg_y, title=title_y, text=text_y, callback=quit())
else:
    easygui.textbox(
        msg=msg_n, title=title_n, text=text_n, callback=quit())
msg_final = "None of this will print at all."
title_final = "You didn't make it this far! Sorry."
easygui.textbox(msg=msg_final, title=title_final)

...it doesn't even get the chance to display the result for Y or N (the if / else parts of the code), and we don't get to see my lovely message at the end.

It is my understanding that the callback option should invoke if the user presses the CANCEL button on the textbox, and thus, the OK button progresses to the next stage. Is this the intended function?

Of course, there's also a reasonably high chance that I've made a mess of something, but one lives in hope that I am actually learning something and improving!

Anyway, back to you I guess.

Thanks!

zadacka commented 6 years ago

Okay, it looks like there are a few things going on.

First, let's cut your sample down to the minimum:

import easygui
easygui.textbox(msg='some mesage', title='some title', text='some text', callback=quit())

This is what I was really asking for before - the minimum amount of code required to illustrate the problem. No unrelated yes-no boxes or if logic - just the function call that is causing problems. It makes life easier for me to get to the root cause more quickly :)

As you can see from running the sample code above, we never display a box. This is because you are actually calling quit rather than passing it as a callback method. So when Python tries to get the value for the callback argument it actually exits.

Based on your comment, what you intend to do here is pass the quit method for use as a callback, like this:

import easygui
easygui.textbox(msg='some mesage', title='some title', text='some text', callback=quit)

Now the next thing to understand here is that the user callback gets called if the 'Ok' button is pressed, NOT if 'cancel' is pressed. You got this right in your first comment when you quoted from the docs. We can see this by introducing a print statement:

import easygui

easygui.textbox(msg='some mesage', title='some title', text='some text', callback=quit)
print 'we reached this print statement'

Now if you press 'cancel' the callback is NOT called, and the print statement will execute so you see output in the console. If the 'Ok' button is pressed then you call the callback and quit, and so you never reach the print statement.

Does that all make sense?

If you are ever unsure about something in the documentation, do be encouraged to go and look at the actual source code. Documentation gets out of date and/or can sometimes be misleading, and the source will actually tell you what is going on. In this case the source will show the conditions under which the callback is used.

fiddybux commented 6 years ago

It sort of make sense, but I'm not sure if my system is responding the same way as you described.

For example, regarding the following code:

import easygui

easygui.textbox(
    msg='some message', title='some title', text='some text', callback=quit)  
# quit will just end here on OK, CANCEL continues to next block

print("we reached this print statement")
easygui.textbox(
    msg='some message 2', title='some title 2', text='some text 2', callback=None)

In this example, I expected a button push of CANCEL to invoke 'quit' as part of the callback, and upon pressing CANCEL I expected the code to terminate, but this is not what is happening for me. Instead it is moving on to the next block of code, printing the message and presenting me with the second textbox I created to test it.

For me, the OK button is terminating the code, and presumably invoking the 'quit' callback. I'm quite confused now because the result is different to what I expected and read. However, I have taken stock of your point about outdated documentation, and I have not yet had to time to check the source as you indicate.

Is the functionality here back to front? Or is this the way it is meant to operate?

Thanks.

zadacka commented 6 years ago

In this case, the documentation is correct and your behaviour is expected.

Like the docs say (and you quoted at the start): callback: function if set, this function will be called when OK is pressed

And as in my previous reply above: the user callback gets called if the 'Ok' button is pressed, NOT if 'cancel' is pressed

I don't think that I can explain it much clearer than that. The callback function here is intended to provide you with a way to make extra stuff happen when the user presses 'Ok'. You've wired it up to the quit method. It is behaving exactly as described.

You may be just too close to the problem to see it - take a break and come back to it, maybe? As I read it, there are not any contradictions in the way the behaviour is described and how it is operating.

fiddybux commented 6 years ago

Thank you for taking the time and being patient with me.

I do find easygui very useful. Thank you for creating it!

zadacka commented 6 years ago

No problem-o! Did that last bit make sense? I sometimes get too close to a problem and have to step back a bit to see what's going on, so maybe you're experiencing the same thing?

I'm not the creator of EasyGUI - original credit for that goes to Stephen Ferg. I'm just trying to help maintain the project and occasionally help out.

fiddybux commented 6 years ago

Yes it made sense thanks.

Thanks for maintaining / helping out then!