Changing state of tkinter entry box depending on value of OptionMenu - python

I am using python 2.7 and trying to change the state of a tkinter entry box depending on the value of an OptionMenu widget. I found an example of how to do it online here, it's for python 3 but I don't think that's the issue (correct me if I am wrong). Some example code is below,
from Tkinter import *
class App:
def _disable_f2(self):
if self.filt.get() == 'bandpass':
self.filter_menu.configure(state='normal')
else:
self.filter_menu.configure(state='disabled')
def __init__(self, master):
self.f2var = Tkinter.StringVar()
self.f2var.set('5.0')
self.f2_entry = Tkinter.Entry(master, textvariable=self.f2var,
width=5)
self.f2_entry.pack()
self.filt = Tkinter.StringVar()
self.filt.set('bandpass')
self.filter_menu = Tkinter.OptionMenu(master, self.filt,
'bandpass', 'lowpass ',
'highpass',
command=self._disable_f2)
self.filter_menu.pack(ipadx=50)
root = Tk()
app = App(root)
root.mainloop()
however, I keep getting the following error even though I am not passing two arguments. Anyone know what the cause is?
TypeError: _disable_f2() takes exactly 1 argument (2 given)

If you just accept one more argument and print it, you can find out what the argument is that is passed by the OptionMenu:
def _disable_f2(self, arg):
print arg
You will see it prints the new value of the OptionMenu. Because this argument is passed you need the function to accept it, and you actually are using it (with self.filt.get()) so it's fine that it's passed.
You can rewrite your _disable_f2 function to:
def _disable_f2(self, option):
if option == 'bandpass':
self.f2_entry.configure(state='normal')
else:
self.f2_entry.configure(state='disabled')
In your original code you disabled the optionmenu when the option was not 'bandpass', but I assume you want to disable the entry right? That's what this code does.
Also, if you use from Tkinter import *, you don't have to use Tkinter.StringVar(), but you can just use StringVar(). Same goes for Entry(...), OptionMenu(...) and Tk().
Allthough I would advise to use import Tkinter as tk, and use tk.StringVar() etc.

If _disable_f2 is being given two arguments, let it have what it wants.. try below...
:)
from Tkinter import *
class App:
def _disable_f2(self, master):
if self.filt.get() == 'bandpass':
self.filter_menu.configure(state='normal')
else:
self.filter_menu.configure(state='disabled')
def __init__(self, master):
self.f2var = StringVar()
self.f2var.set('5.0')
self.f2_entry = Entry(master, textvariable=self.f2var,
width=5)
self.f2_entry.pack()
self.filt = StringVar()
self.filt.set('bandpass')
self.filter_menu = OptionMenu(master, self.filt,
'bandpass', 'lowpass ',
'highpass',
command=self._disable_f2)
self.filter_menu.pack(ipadx=50)
root = Tk()
app = App(root)
root.mainloop()

Related

Tkinter: using return for widgets

So, I have been having trouble figuring out what does return do when used for tkinter widgets
here are 3 blocks of code that have the same result, and I wasn't sure what their difference is and whether they differ in performance, and finally, which one is the standard approach
1
import tkinter as tk
class App:
def __init__(self):
window = tk.Tk()
self.label_in_window(window, text = "hello world!")
window.mainloop()
def label_in_window(self, parent, text):
return tk.Label(parent, text = text).pack()
App()
2
import tkinter as tk
class App:
def __init__(self):
window = tk.Tk()
self.label_in_window(window, text = "hello world!")
window.mainloop()
def label_in_window(self, parent, text):
tk.Label(parent, text = text).pack()
return
App()
3
import tkinter as tk
class App:
def __init__(self):
window = tk.Tk()
self.label_in_window(window, text = "hello world!")
window.mainloop()
def label_in_window(self, parent, text):
tk.Label(parent, text = text).pack()
App()
Per code answer:
does not make sense, because you are returning something, but then throwing the returned result away.
you can remove the return statement because all functions by default return None, and a return statement without a value also returns None. This then makes 2. and 3. equal.
If you just want to put the creation of widgets into a separate function, use the 3rd code.
Anyways, all the returns do not make sense in your code, because they will always return None. Guess why ? No ? I'll explain it. It's because of this line:
tk.Label(parent, text = text).pack()
First you create a tk.Label object. Then, you call its pack method which of course returns None. So in the end, you have not a tk.Label, but a None. To change this, you should first assign your tk.Label object to a variable, then call the pack method of the variable, then return the variable:
def label_in_window(self, parent, text):
label = tk.Label(parent, text=text)
label.pack()
return label
But, if you are not planning to use the label later (set a new text, for example), it doesn't make sense to return the label. If you do want to use it later, the standard approach in a class would be to assign the label to an attribute of your class. Also, you should move the window.mainloop out of the class, and functions / methods should be named after what they do, not which result they produce:
import tkinter as tk
class App:
def __init__(self):
self.window = tk.Tk()
self.add_label(self.window, text="hello world!")
def add_label(self, parent, text):
self.label = tk.Label(parent, text=text)
self.label.pack()
app = App()
app.window.mainloop()
In the first example you used:
return tk.Label(parent, text=text).pack()
Which creates a label, calls .pack() on the label. It returns whatever .pack() returns (which is None). For more info please read this. So it's identical to:
tk.Label(parent, text=text).pack()
return None
The second example uses:
tk.Label(parent, text = text).pack()
return
Which creates the label. The return is the same as return None.
In the third example uses:
tk.Label(parent, text=text).pack()
Which creates a label then returns None.
Therefore, all the examples that you have shown are exactly the same. They all create a label and return None.
PS: If you use from dis import dis and then dis(App.label_in_window), you will see the decompiled bytecode, which is what python actually uses to run your code.

String Variable not setting initial value

class Lay():
def __init__(self):
root=Tk()
root.configure(background="black")
var=StringVar()
var.set("OVERVIEW")
Label(root,textvariable=var).grid(row=1,column=1,sticky=W+E+N+S)
Entry(root, textvariable = var).place(rely=1.0,relx=1.0,x=0,y=0,anchor=SE)
root.mainloop()
Hello, when i run this the initial value of the string variable does not appear, but when i type into the entry box, the text i type appears in the label. I'm not quite sure why this occurs, but i get an empty label to begin with, with the entry box. Thank you for any help.
Although, I couldn't reproduce the problem, I refactored your code to initialize tkinter widgets through a class(inspired by the snippet in the docs) and also increased the window size so that the widgets are clearly viewed. If there is anything else in your code that is calling multiple windows as #jasonharper suggested, you should share that.
import tkinter as tk
class Lay(tk.Tk):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.var=tk.StringVar()
self.var.set("OVERVIEW")
self.Widgets()
def Widgets(self):
self.displaylbl = tk.Label(self,textvariable=self.var)
self.displaylbl.grid(row=2,column=1,sticky=tk.W+tk.E+tk.N+tk.S)
self.entry = tk.Entry(self, textvariable = self.var)
self.entry.place(rely=1.0,relx=1.0,x=0,y=0,anchor=tk.SE)
app = Lay()
app.geometry("200x200")
app.mainloop()
Output:

Class atributes get linked when using tkinter

I'm using a tkinter interface to read in some information like file path, measurement variables etc. for my code. And I read them out with the use_entry function which just remains here as a kill command for the app. Then I run the code a few times to analyze different data sets.
It seems to work fine but i noticed that if two attributes get the same value (here exp and pwr) they get scrambled. Meaning that both become the same value permanently. So if i set exp to A and pwr to B i can freely change them , but as soon as I set both to the same string or int or whatever they start being changed simultaneously (here both are "A"). I can't resolve this unless i restart the consol or change one of the values outside of tkinter.
import tkinter as tk
class App:
def __init__(self, parent):
self.exp="A"
self.pwr="A"
self.parent=parent
self.exposure = tk.Entry(parent, textvariable=self.exp)
self.exposure.pack()
self.power = tk.Entry(parent, textvariable=self.pwr)
self.power.pack()
self.button4 = tk.Button(parent,
text="Done",
command=self.use_entry)
self.button4.pack()
def use_entry(self):
self.contents = (float(self.power.get()),float(self.exposure.get()))
self.parent.destroy()
root = tk.Tk()
app = App(root)
root.mainloop()
I'm rather new to using tkinter and I would be glad if someone could point out my mistake.
Use tk.StringVar instead of normal strings for textvariable in your entries.
self.exp = tk.StringVar(value='A')
self.pwr = tk.StringVar(value='A')
self.parent=parent
self.exposure = tk.Entry(parent, textvariable=self.exp)
self.exposure.pack(side=tk.LEFT,anchor=tk.W)
self.power = tk.Entry(parent, textvariable=self.pwr)
self.power.pack()

tkinter checkbutton not setting variable

Whatever I do to my checkbutton, it does not seem to set the variable.
Here's the parts of the code that are involved:
class Window:
def __init__(self):
self.manualb = 0 #to set the default value to 0
def setscreen(self):
#screen and other buttons and stuff set here but thats all working fine
manual = tkr.Checkbutton(master=self.root, variable=self.manualb, command=self.setMan, onvalue=0, offvalue=1) #tried with and without onvalue/offvalue, made no difference
manual.grid(row=1, column=6)
def setMan(self):
print(self.manualb)
#does some other unrelated stuff
It just keeps printing 0. Am I doing something wrong? Nothing else does anything to manual.
You're looking for IntVar()
IntVar() has a method called get() which will hold the value of the widget you assign it to.
In this particular instance, it will be either 1 or 0 (On or off).
You can use it something like this:
from tkinter import Button, Entry, Tk, Checkbutton, IntVar
class GUI:
def __init__(self):
self.root = Tk()
# The variable that will hold the value of the checkbox's state
self.value = IntVar()
self.checkbutton = Checkbutton(self.root, variable=self.value, command=self.onClicked)
self.checkbutton.pack()
def onClicked(self):
# calling IntVar.get() returns the state
# of the widget it is associated with
print(self.value.get())
app = GUI()
app.root.mainloop()
This is because you need to use one of tkinter's variable classes.
This would look something like the below:
from tkinter import *
root = Tk()
var = IntVar()
var.trace("w", lambda name, index, mode: print(var.get()))
Checkbutton(root, variable=var).pack()
root.mainloop()
Essentially IntVar() is a "container" (very loosely speaking) which "holds" the value of the widget it's assigned to.

Allow user to change default text in tkinter entry widget.

I'm writing a python script that requires the user to enter the name of a folder. For most cases, the default will suffice, but I want an entry box to appear that allows the user to over-ride the default. Here's what I have:
from Tkinter import *
import time
def main():
#some stuff
def getFolderName():
master = Tk()
folderName = Entry(master)
folderName.pack()
folderName.insert(END, 'dat' + time.strftime('%m%d%Y'))
folderName.focus_set()
createDirectoryName = folderName.get()
def callback():
global createDirectoryName
createDirectoryName = folderName.get()
return
b = Button(master, text="OK and Close", width=10, command=callback)
b.pack()
mainloop()
return createDirectoryName
getFolderName()
#other stuff happens....
return
if __name__ == '__main__':
main()
I know next to nothing about tkInter and have 2 questions.
Is over-riding the default entry using global createDirectoryName within the callback function the best way to do this?
How can I make the button close the window when you press it.
I've tried
def callback():
global createDirectoryName
createDirectoryName = folderName.get()
master.destroy
but that simply destroys the window upon running the script.
I don't know how experienced are you in Tkinter, but I suggest you use classes.
try:
from tkinter import * #3.x
except:
from Tkinter import * #2.x
class anynamehere(Tk): #you can make the class inherit from Tk directly,
def __init__(self): #__init__ is a special methoed that gets called anytime the class does
Tk.__init__(self) #it has to be called __init__
#further code here e.g.
self.frame = Frame()
self.frame.pack()
self.makeUI()
self.number = 0 # this will work in the class anywhere so you don't need global all the time
def makeUI(self):
#code to make the UI
self.number = 1 # no need for global
#answer to question No.2
Button(frame, command = self.destroy).pack()
anyname = anynamehere() #remember it alredy has Tk
anyname.mainloop()
Also why do you want to override the deafult Entry behavior ?
The solution would be to make another button and bind a command to it like this
self.enteredtext = StringVar()
self.entry = Entry(frame, textvariable = self.enteredtext)
self.entry.pack()
self.button = Button(frame, text = "Submit", command = self.getfolder, #someother options, check tkitner documentation for full list)
self.button.pack()
def getfolder(self): #make the UI in one method, command in other I suggest
text = self.enteredtext.get()
#text now has whats been entered to the entry, do what you need to with it

Categories

Resources