TkInter: How to call a variable from a callback function button? - python

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

Related

What can I use instead of a while loop that will check something over and over?

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)

Tkinter - StringVar() trace not executing command

I wrote this code to be a version manager, but it doesn't execute the command changeDir(). Why?
https://pastebin.com/VSnhzRzF
You forgot to pass a 'name' argument to changeDir function. And there's no exception because your statement has no effect!
Snippet to represent the problem:
import sys
def exec_smth():
# execution without effect
exec('write_smth')
try:
# execution with exception because of missing argument
exec('write_smth()')
except TypeError as error:
# now we pass an argument
exec('write_smth("I failed because of %s" % error )')
def write_smth(smth):
sys.stdout.write(smth)
exec_smth()
Anyway, outside your __init__ function there're no StringVars at all thanks to garbage collector, so your code would fail anyway!
There're even more problems, because you never bind any of your sv{} to a widget and expect something in return! But ok, let's try to do things with exec:
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entries = []
for _ in range(5):
exec('self.sv{} = tk.StringVar()'.format(_))
exec('self.sv{}.trace("w", self.change_sv)'.format(_))
exec('self.entries.append(tk.Entry(self, text="", textvariable=self.sv{}))'.format(_))
for entry in self.entries:
entry.pack()
def change_sv(*args):
# get id of a variable (you can't rely on that (0-9)!)
idx = args[1][-1:]
# get new value
value = getattr(args[0], 'sv{}'.format(idx)).get()
# result
print('Value changed in self.sv%s to %s!' % (idx, value))
app = App()
app.mainloop()
Output:
As you see - we always need a reference to StringVars and I think that option with a list of them is far better!
Note: If you need to pass something to callback function - use a lambda function! All code tested with Python 3.
Links:
The Variable Classes
Tkinter Callbacks
Behavior of exec function in Python 2 and Python 3

Python - tkinter - How to capture bind function

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.

Tkinter entry widget get is undefined, not updating to my main function,

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.

Changing python global variables between modules

I'm trying to carry a change from a global variable over to another module in Python2.7.
I've done this in similar situations before but for some reason it won't work in this instance.
The first file is the one that runs the program. It sets up a global variable and changes it according to the option selected. I've pasted a bit of the code below.
runnerMod:
import Tkinter
from main_mod import*
choice = "0"
def main():
main_mod=functOne()
class GUI(Tkinter.Tk):
def __init__(self, parent):
Tkinter.Tk.__init__(self, parent)
self.parent = parent
self.initialize()
def initialize(self):
self.grid()
self.update()
btnOption1 = Tkinter.Button(self, text=u"Option 1", command=self.onButtonClick)
btnOption1.grid(column=0, row=1)
def onButtonClick(self):
selection = "1"
self.destroy()
exec 'choice=%s' %selection in globals()
main()
class menuSelection:
def OPTIONCHOSEN(self):
return choice
if __name == "__main__":
app = GUI(None)
app.mainloop
I want the global variable named choice from runnerMod.py to carry over to this module.
main_mod:
from runnerMod import menuSelection
def functOne():
userInput = menuSelection().OPTIONCHOSEN()
print userInput
The global variable choice starts at 0, but I want to change it to 1 in the runnerMod.py module and have this reflected in the main_mod.py module. Since I'm rewriting an interface to an existing program my options are a little limited in the way its coded. Anyone have any ideas here?
As it turns out, I couldn't pass over changes to a global variable from runnerMod.py because it was the module that launched the program. What I had to do was use runnerMod.py to launch the program and then call a function in main_mod.py. This function called BACK to a class in runnerMod.py and loaded up the GUI. Only by calling back and THEN modifying the global variable could I pass over the changes.

Categories

Resources