from tkinter import StringVar, messagebox, Entry, Tk
def accept(event):
acceptInput=messagebox.askquestion("Input Assessment","do you accept this input?")
return acceptInput
window=Tk()
userInput=StringVar()
e=Entry(window,textvariable=userInput)
e.pack()
e.bind('<Return>',accept)
window.mainloop()
My question is: How do I capture the returned value of the accept function?
I've tried:
e.bind('<Return>',a=accept.get())
and
a=e.bind('<Return>',accept).get()
bound functions don't "return". Your callback needs to set a global variable or call some other function. For example:
def accept(event):
global acceptInput
acceptInput=messagebox.askquestion("Input Assessment","do you accept this input?")
... or ...
def accept(event):
acceptInput=messagebox.askquestion("Input Assessment", "do you accept this input?")
do_something(acceptInput)
It is up to you to define what you want to do in do_something (eg: write the data to disk, show an error, play a song, etc), or how you want to use the global variable in some other function.
Generally speaking, these things are easiest to accomplish if pieces of your application are instances of a class -- Then accept can just set an attribute on the class. In this case, you might want to bind that functionality up in the Entry:
class AcceptEntry(Entry):
def __init__(self, *args, **kwargs):
Entry.__init__(self, *args, **kwargs)
self.bind('<Return>', self.accept)
self.acceptInput = None
def accept(self, event):
self.acceptInput = messagebox.askquestion("Input Assessment",
"do you accept this input?")
For the function bind, the <Return> doesn't mean the return of a function. Instead, it does mean the event "Enter key" that is pressed by the user.
So, if you like to get the response from the messagebox, then you have do it with other ways. Possibly using with another StringVar() option with your messagebox, or using any global variable.
Related
I have a button whose function is
def callback2():
callback()
The callback() function is
def callback():
usein = None
if inspect.stack()[1][3] == callback2:
global inputText
usein = inputText.get()
return None
while True: #freezes everything, because tkinter
if usein:
return usein
Now, the reason I have to do it like this is because other functions call callback() looking for the value inputted by the button, but I have to make them wait for the button to be pressed. But since I'm using tkinter, the while loop doesn't work - it just makes the GUI freeze. So what can I use instead? I've been working on this for days. I'd be glad to add any other parts of my code if needed.
isButtonClicked = false #a global variable
def callback2():
isButtonClicked = true
callback()
isButtonClicked = false
One idea may be to use a global variable called isButtonClicked and assign a false value, and modify the other methods which call callback method like this:
def othermethod():
if isButtonClicked:
callback()
But you've to make sure that the variables are thread-safe.
Not a tkinter expert, but if you want to get some text input on a button click, the following may work.
def callback():
usein = entry.get()
# do whatever with usein
master = Tk()
entry = Entry(master) # the text input
Button(master, text='Button', command=callback)
I have the following scenario where I want to execute a function with on_change:
def update_func:
calling_widget = < I need the name of the widget here: "SelectorWidget" >
do_something
SelectorWidget = MultiSelect(title="A widget", value = "default", options = option_list)
SelectorWidget.on_change('value', update_func)
The same update_func will be used on different widgets, and I'd like to be able to get the name of the Widget which triggered the function each time.
Any ideas?
Try:
from functools import partial
# add a widget arg to standard callback signature
def update_func(attr, old, new, widget):
# do something with widget
SelectorWidget = MultiSelect(title="A widget",
value="default",
options=option_list)
# use partial to make a callback callable with widget arg bound
SelectorWidget.on_change('value',
partial(update_func, widget=SelectorWidget))
I have a socket client that calls a View() class every time it receives a message. I've split my code in such a way such that this class can simply use print() or any other display method, as I like. However, it seems that Kivy is not fond of this method. I've extended Kivy's BoxLayout class for my view and can call the message() function. The class looks something like this:
class View(BoxLayout):
def __init__(self, **kwargs):
super(View, self).__init__(**kwargs)
self.btn = Button(text='Default')
# Bind button press method
self.btn.bind(on_press=self.message)
self.add_widget(self.btn)
def message(self, message):
self.btn.text = 'Meow'
self.add_widget(Button(text='Meow'))
print(str(message))
The message function is indeed called and it prints but the interface does not update. When I press the button however, it does update the interface as well as print.
I've looked into using a StringProperty to modify the button text but have failed that too. Just as a note, in case what I'm doing is completely infeasible, I'm trying to later draw an entire interface consisting of width * height buttons, in the form of a board.
Any input is very much appreciated, it's been driving me insane.
EDIT 1*
I've followed on a few comments and tried a few things out. I've added a Clock class and have it schedule an update() method from View. The update method simply changes the text of a few elements. I've noticed it works when I schedule it to, as shown below:
def update(self, *args, **kwargs):
self.btn.text = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for i in range(32))
def message(self, message):
try:
print(message)
self.text = 'sending'
except Exception as e:
print(e)
The thread now simply assigns the text property as seen in message(). The periodically triggered update() methods works too, assigning random text. Now the issue however that it cannot set the text. This does not work:
def update(self, *args, **kwargs):
self.btn.text = self.text
I must be doing wrong elsewhere, any suggestions?
EDIT 2*
The error I'm trying to debug is here.
Since you don't post a full working example, I can only guess at what your doing. It seems you have an event (incoming message) on a thread, and you want to display some text when this occurs. You need to 'push' UI updates to the main thread, but you don't need to do periodic updates with Clock, you can just schedule one-time calls with Clock.schedule_once.
from functools import partial
def update(self, text, *a):
self.btn.text = text
def message(self, message):
Clock.schedule_once(partial(self.update, message), 0)
As inclement mentioned, you can do this 'push to main thread' automatically with the #mainthread decorator:
#mainthread
def update(self, text):
self.btn.text = text
def message(self, message):
update(message)
This way, whenever you call update it will be executed on the main thread.
I am a absolutly beginner in Tkinter and I need already help:
I wanted to open a file with a button. I found everywhere this very simple example:
from Tkinter import *
from tkFileDialog import askopenfilename
def callback():
name= askopenfilename()
print name
errmsg = 'Error!'
Button(text='File Open', command=callback).pack(fill=X)
mainloop()
But how can I call now the variable "name" from the function callback? I need this variable outside of this function! Of course, I can also open the file also in the callback function, but I need the opened file to save the content in an array and work with the array...
The best approach would be to make callback a method in a class:
class Asker(object):
def __init__(self):
self.name = None
def callback(self):
self.name = askopenfilename()
print self.name
ask = Asker()
Button(text='File Open', command=ask.callback).pack(fill=X)
Now, object ask persists, and ask.name is None if the callback has not executed yet, and after it has, the result of askopenfilename.
You could use a global instead but there's really no advantage in so doing so I recommend you use this class-based approach.
If you need some variable outside a function you need a global variable
name="" # if you don't call the function it'll remain empty!
def callback():
global name
name= askopenfilename()
print name
i'm following a few different guides to re-learn Tkinter by writing a little application that grabs stock prices. My issue that I am up a wall against is calling the .get() method from my entry widget variable. I've seen a couple other suggestions to put all the widget creating inside a function and then call the function in the init method, however I'm getting the same error, even when using the self argument in front of my entry variables. I know it's an issue with the way i'm passing data from function to function, but I can't wrap my head around it. Here's the code, sorry for the wall of text:
class MyApp:
def __init__(self, parent):
self.myParent = parent
self.myContainer1 = Frame(parent)
self.myContainer1.pack()
self.createWidgets()
button1 = Button(self.myContainer1, command = self.button1Click)
button1.configure(text = "get quote")
button1.pack()
def createWidgets(self):
root.title("Stock App")
self.symbol = Entry(self.myContainer1)
self.symbol.pack()
self.symbol.focus_set()
def button1Click(self):
stock = symbol.get()
print stock
I've taken it down to simplest form even and just had the button1Click call a callback function-
def button1Click(self):
print callback()
def callback():
print symbol.get()
This returns the exact same error:
NameError: global name 'symbol' is not defined
Is it getting destroyed too early? how do I fix this?
I've referenced multiple documents for tkinter and have seen some great fixes but none are extensible, or um unable to see how they relate to me using it inside of an object.
Thanks in advance for the help.
As far as I can tell inside of your button1Click method you need to add self as in:
def callback():
print self.symbol.get()
You're missing self. to make the callback:
def callback():
print self.symbol.get()
instead.