Create an Entry box if a specific item on Optionmenu is selected - python

I'm trying to create an entry box for a user to manually input a variable that doesn't exist in a list of a optionmenu widget. is this possible?
from Tkinter import *
import Tkinter as tk
class Demo1:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
x = (master.winfo_screenwidth() - master.winfo_reqwidth()) / 2
y = (master.winfo_screenheight() - master.winfo_reqheight()) / 2
master.geometry("+%d+%d" % (x, y))
master.deiconify()
self.subtests = StringVar()
self.subtests.set("Enter Test Type")
choices = ['Potato','Tomato','Onion','Other']
self.testnumber = OptionMenu(master, self.subtests, *choices).grid(row = 2, column = 3)
self.confirmbutton = Button (master, text="Confirm Test", width=20, command =lambda: self.confirmsubtest(master))
self.confirmbutton.grid(row = 5, sticky = E)
def main():
root = tk.Tk()
app = Demo1(root)
root.mainloop()
if __name__ == '__main__':
main()
As mentioned, if the user needs to select a variable that is not on the list. Is it possible to allow the user to manually enter the variable through an entry box in the same window (ex: Selecting "Other" in the list that generates an entry/widget/something)?

If anyone searches for the same thing. The process is to add the command variable to the optionmenu and disable the entry widget once the desired highlighted choice is on. This is done by configuring the button/widget/anything with a .config(state=NORMAL) or .config(state=DISABLED).
self.testnumber = OptionMenu(master, self.subtests, *choices, command = self.optupdate).grid(row = 2, column = 3)
self.testnumber.grid(row = 4, column = 1)
def optupdate(self,value):
if value == "Other":
self.otherEntry.config(state=NORMAL)
else:
self.otherEntry.config(state=DISABLED)
return

Related

How to make python - tkinter dropdown command update after event

I am remaking a GUI calculator app in Tkinter, in order to learn about classes, methods, attributes, and also to shorten my original code. In order to shorten the code, I made a frame class that generates frames, entries, labels and dropdown menus, so I don't have to create them individually. Everything went well until I got to the dropdown menu part. When the user selects a different option from the Filters - dropdown menu like V, or B or L etc. the value in frame 1 -> entry[1] doesn't update. The method that updates the value in that entry is called add(self) and it's a part of calculator class.
Here is the simple version
import numpy as np
import tkinter as tk
window = tk.Tk()
window.geometry("920x500")
window.resizable(0,0)
window.title('Exposure Time Calculator')
class Calculator:
def __init__(self, window):
self.create_test_frame1()
self.create_test_frame2()
self.add(None)
def create_test_frame1(self):
labelvalues=['val 1','val 2']
entryvalues=['203','1333']
self.frame_1 = frame('Test Frame 1',labelvalues,entryvalues,6, 2, 0, 0, "no",0,0,0,0,0,30,40)
def create_test_frame2(self):
labelvalues = ['val 3','val 4']
entryvalues = ['10','24.5']
option_menu_values = ['B','V','R','I','Luminance','Hydrogen 3nm']
self.frame_2 = frame('Frame 2', labelvalues, entryvalues, 14, 2, 0, 2,
"option_menu1_yes", option_menu_values,'Filters',
0,0,0,
5,20)
def add(self, e):
qe = self.frame_1.entry[1]
bandOption = self.frame_2.clicked.get()
if bandOption == "B":
qe.delete(0,tk.END)
qe.insert(0,22)
elif bandOption == "V":
qe.delete(0,tk.END)
qe.insert(0,33)
class frame:
# Creates a frame class for automatic frame generation
# with entries, labels and/or option menus
# 1. name : frame name
# 2. label_default_values: name of labels
# 3. entry_default_values: default values in entries
# 4. entry_width: the entries dimensions
# 5. I: number of labels and entries
# 6. grid_row: frame grid row placement
# 7. grid_column: frame grid column placement
# 8. option_menu: true or false if user wants a option list or not
# 9. option_list_values: list for option menu
# 10. option_label: name for option menu label
# 11. ipax, ipady: padding
# 12. comand: comand for option list
def __init__(self, name, label_default_values, entry_default_values, entry_width, I, grid_row, grid_column,
option_menu1, option_list_values, option_label,
option_menu2, option2_list_values,option_label2,
ipad_x, ipad_y
):
self.name = name
self.label_default_values = label_default_values
self.entry_default_values = entry_default_values
self.I = I
self.grid_row = grid_row
self.grid_column = grid_column
self.dropMenu_options = option_list_values
self.label = option_label
self.entry_width = entry_width
self.dropMenu_options2 = option2_list_values
self.option_label2 = option_label2
self.ipad_x = ipad_x
self.ipad_y = ipad_y
frame = tk.LabelFrame(window, text = name, highlightbackground='grey', highlightthickness=1)
frame.grid(row=self.grid_row, column=self.grid_column, padx=5, pady=5, ipadx=ipad_x, ipady=ipad_y)
if option_menu1 == "option_menu1_yes":
self.clicked = tk.StringVar()
self.clicked.set(self.dropMenu_options[0])
self.drop = tk.OptionMenu(frame, self.clicked, *self.dropMenu_options, command = self.add)
self.drop.grid(row=5, column=1, sticky="ew")
label = tk.Label(frame, text = option_label, highlightbackground='grey', highlightthickness=1)
label.grid(row = 5, column = 0, sticky = "w")
if option_menu2 == "option_menu2_yes":
self.clicked2 = tk.StringVar()
self.clicked2.set(self.dropMenu_options2[0])
self.drop2 = tk.OptionMenu(frame, self.clicked2, *self.dropMenu_options2)
self.drop2.grid(row=6, column=1, sticky="ew")
label = tk.Label(frame, text = option_label2, highlightbackground='grey', highlightthickness=1)
label.grid(row = 6, column = 0, sticky = "w")
self.entry ={}
for i in range(0, self.I):
label = tk.Label(frame, text = self.label_default_values[i], justify = "left")
label.grid(row=i, column=0, sticky = "w")
self.entry[i] = tk.Entry(frame, textvariable = float(self.entry_default_values[i]), width=self.entry_width)
self.entry[i].grid(row=i, column=1, sticky = "e")
self.entry[i].delete(0, tk.END)
self.entry[i].insert(0, self.entry_default_values[i])
c=Calculator(window)
window.mainloop()
The method add is in the Calculator class, so instead of self.add you need to call add on the calculator. Since the frame doesn't know what the calculator is, you need to pass it in when constructing the frame.
Something like the following, where the calculator instance is passed as the first option:
self.frame_1 = frame(self, 'Test Frame 1', ...)
Next, you need to define your class to accept and save the reference to the calculator and then use it in the command of the OptionMenu:
class frame:
def __init__(self, calculator, name, ...):
self.calculator = calculator
...
self.drop = tk.OptionMenu(..., command = self.calculator.add)
Also, you define add like this:
def add(self, e):
I assume that means you think the second parameter is an event object. It is not. It is the value that was picked from the optionmenu.
Arguably, a better way to define this would be to actually use this new value if provided, and fall back to calling get if a value isn't provided. Also, you can reduce the wall of if statements into a single dictionary lookup to make the code shorter and more robust.
def add(self, new_value=None):
qe = self.frame_1.entry[1]
bandOption = self.frame_2.clicked.get() if new_value is None else new_value
band = {"B": 22, "V": 33}
qe.delete(0, "end")
qe.insert(0, band[bandOption])
This solution is 2/3 the size of your original, and more flexible and easier to maintain.
There are 2 problems:
The first one is that you mentioned and to fix it:
rename def add(self) to def add(self, e) and rename add() to add(None). Then change lambda event: self.add to self.add
The second one is:
AttributeError: 'frame' object has no attribute 'frame_camera'
but is not question related
It works if I define add(event) outside classes.
def add(event):
qe = c.frame_1.entry[1]
bandOption = c.frame_2.clicked.get()
if bandOption == "B":
qe.delete(0,tk.END)
qe.insert(0,22)
elif bandOption == "V":
qe.delete(0,tk.END)
qe.insert(0,33)
And this in the frame class:
self.drop = tk.OptionMenu(frame, self.clicked, *self.dropMenu_options, command = lambda event:add(event))

Why can't I specific the default selected radiobutton?

I am making a simple GUI using Python's tkinter module, and I'm having a lot of trouble with radiobuttons. I wish to have the first selected by default, but the other two are selected at the start. Additionally, when I just pass the cursor over the window, the first one becomes checked (I do not click) so all 3 show as selected. My code:
import tkinter as tk
class openGUI(object):
def __init__(self):
# title of window
window.title("DUNE LArTPC Simulator")
# label for choices
self.question = tk.Label(window, text = "Do you want to create new or analyse existing data?")
self.question.grid(row = 0, column = 0, columnspan = 3)
# buttons corresponding to choices
self.createBtn = tk.Button(window, text = "Create", command = self.createData)
self.analyseBtn = tk.Button(window, text = "Analyse", command = self.analyseData)
self.createBtn.grid(row = 1, column = 0)
self.analyseBtn.grid(row = 1, column = 2)
def analyseData(self):
"""
Not implemented yet.
"""
pass
def createData(self):
# edit window to display new widgets (irritating to have lots of windows open!)
window.title("Select variable")
self.question.destroy()
self.createBtn.destroy()
self.analyseBtn.destroy()
# text in window
variableQ = tk.Label(window, text = "Please select Independent variable for dataset:")
variableQ.grid(row = 0, column = 0, columnspan = 3)
# radioselect variable
selection = tk.StringVar()
selection.set("lifetime")
# radioselect buttons
lifetimeBtn = tk.Radiobutton(window, variable = selection, value = "lifetime", text = "Lifetime")
elecNoiseBtn = tk.Radiobutton(window, variable = selection, value = "electronic", text = "Electronic Noise")
radioactivityBtn = tk.Radiobutton(window, variable = selection, value = "radioactive", text = "Radioactivity")
lifetimeBtn.grid(row = 1, column = 0)
elecNoiseBtn.grid(row = 1, column = 1)
radioactivityBtn.grid(row = 1, column = 2)
# create window
window = tk.Tk()
# create class object with methods to populate
# window with widgets
initWin = openGUI()
# enter mainloop
window.mainloop()
Running the above gives me:
I have tried using lifetimeBtn.select() method instead of setting the StringVar(), but this does not seem to work either. What have I missed?
EDIT: added rest of code to show how I am using class and functions to manipulate the window.
It is because selection is a local variable inside createData() function and it will be garbage collected after function completes.
Change selection to instance variable self.selection.

Tkinter entry getting text entered by user

I am very new to Tkinter ( I find it very difficult to learn). I have a python script working based on user input. I would like to wrap a GUI around it and eventually put it on web. In any case for user input I would like to get this from the GUI with a combination of Entry widgets and some buttons. First thing is I was reading and some people mentioned to use a class so I have the following. I have a few questions
I would like to check to see if indeed the users entered a value before he hits the GO button. How do I do this?
I would like the value entered to be made accessible by the rest of the program in the main body. How do I do this?
Thanks,
from Tkinter import *
class MainWindow():
def get_fc(self):
a = self.fc_gui.get()
return a
def __init__(self, master):
self.master = master
self.master.title('TEST')
self.fc_gui = DoubleVar(self.master, value = 500.00)
self.fclabel1 = Label(self.master, text = 'Please Enter a value', fg = 'black', bg = 'yellow')
self.fclabel1.grid(row = 0, column = 0)
self.fcedit1 = Entry(self.master, textvariable = self.fc_gui, bd = 5 )
self.fcedit1.grid(row = 1, column = 0)
fcbutton1 = Button(self.master, text='GO', command = self.get_fc)
fcbutton1.grid(row = 1, column = 1)
master = Tk()
MainWindow(master)
master.mainloop()
It doesn't make sense to return to a Button. The Button can't do anything with the value. Instead, save the value as an instance variable.
You don't have a mainloop().
You can't really check if the user entered a value before they hit "Go" - at the start of the program, of course they haven't entered anything yet. If you needed to track the contents of this field, there are ways to do that, but it's not necessary for a simple validation. Just check the value when they hit the button.
from Tkinter import *
class MainWindow():
def get_fc(self):
a = self.fc_gui.get()
if a: # this block will execute if a has content
self.a = a # save it for future use
def __init__(self, master):
self.master = master
self.master.title('TEST')
self.fc_gui = DoubleVar(self.master, value = 500.00)
self.fclabel1 = Label(self.master, text='Please Enter a value',
fg = 'black', bg = 'yellow')
self.fclabel1.grid(row = 0, column = 0)
self.fcedit1 = Entry(self.master, textvariable = self.fc_gui, bd = 5 )
self.fcedit1.grid(row = 1, column = 0)
fcbutton1 = Button(self.master, text='GO', command = self.get_fc)
fcbutton1.grid(row = 1, column = 1)
master = Tk()
MainWindow(master)
master.mainloop() # don't forget mainloop()

Why is this code working I took from a textbook for GUI Python?

Why isn't this working. This is straight from the text book. I'm getting an Attribute error saying self._area does not exist.
from Tkinter import *
import math
class CircleArea(Frame):
def __init__(self):
"""Sets up a window and widgets."""
Frame.__init__(self)
self.master.title("Circle Area")
self.grid()
#Label and field for radius
self._radiusLabel = Label(self, text = "Radius")
self._radiusLabel.grid(row = 0, column = 0)
self._radiusVar = DoubleVar()
self._radiusEntry = Entry(self, textvariable = self._radiusVar)
self._radiusEntry.grid(row = 0, column = 1)
#Label and field for the area
self._areaLabel = Label(self, text = "Area")
self._areaLabel.grid(row = 1, column = 0)
self._areaVar = DoubleVar()
self._areaEntry = Entry(self, textvariable = self._areaVar)
self._areaEntry.grid(row = 1, column = 1)
# The command button
self._button = Button(self, text = "Compute", command = self._area)
self._button.grid(row = 2, column = 0, columnspan = 2)
def _area(self):
"""Event handler for button."""
radius = self._radiusVar.get()
area = radius ** 2 * math.pi
self._areaVar.set(area)
def main():
CircleArea(). mainloop()
run = CircleArea()
run.main()
Is it because the _area method is declared after it is called? That doesn't make sense why it wouldn't work using a down up programming technique. I'm really new to GUI just started learning. First chapter on GUI for class.
edit*: I'm expecting a window to pop up and have one Entry field for input for the radius of the circle. With a label Radius. And an output entry field for the results of the area of the circle based on the radius. and a compute button at the bottom which computes it.
And I just wanted to get used to typing the different commands and such. I haven't even been in the lecture for this yet. I was just seeing what this code would do and what it would look like. I typed it all out by hand if that makes you feel better.:P Instead of copy and pasting.
The problem is that your indenting is wrong. _area and main are defined within __init__, which you don't want. Correct indenting is below (you don't need a main function).
from Tkinter import *
import math
class CircleArea(Frame):
def __init__(self):
"""Sets up a window and widgets."""
Frame.__init__(self)
self.master.title("Circle Area")
self.grid()
#Label and field for radius
self._radiusLabel = Label(self, text = "Radius")
self._radiusLabel.grid(row = 0, column = 0)
self._radiusVar = DoubleVar()
self._radiusEntry = Entry(self, textvariable = self._radiusVar)
self._radiusEntry.grid(row = 0, column = 1)
#Label and field for the area
self._areaLabel = Label(self, text = "Area")
self._areaLabel.grid(row = 1, column = 0)
self._areaVar = DoubleVar()
self._areaEntry = Entry(self, textvariable = self._areaVar)
self._areaEntry.grid(row = 1, column = 1)
# The command button
self._button = Button(self, text = "Compute", command = self._area)
self._button.grid(row = 2, column = 0, columnspan = 2)
def _area(self):
"""Event handler for button."""
radius = self._radiusVar.get()
area = radius ** 2 * math.pi
self._areaVar.set(area)
run = CircleArea()
run.mainloop()
Actually I think you miss an argument in your main method,you define a class CircleArea , but in python you know that, each method defined in class must have an default argument named 'self',so just try this
def main(self):
CircleArea(). mainloop()
I think it will work as you wish :)

Trying to put drop down list on a code using Tkinter

I'm tring to put some drop down list on a graphic interface I'm building.
I've found the following code for a drop down list, but I'm not able to adapt it to my code.
from Tkinter import *
def print_it(event):
print var.get()
root = Tk()
var = StringVar()
var.set("a")
OptionMenu(root, var, "a","b","c", command=print_it).pack()
root.mainloop()
This is my code, it's quite simple what I've done so far. A menu shows up, it asks for how many (n) components does the users want to enter, and it shows n options to entry. The code above shows 'blank' entrys after you put the desired number of components. I want to replace those three blank entrys with three drop down list.
It's marked when I want to put those dropdown lists.
from Tkinter import *
import Image
import ImageTk
import tkFileDialog
class Planificador:
def __init__(self,master):
master.title("Planificador")
self.frameOne = Frame(master)
self.frameOne.grid(row=0,column=0)
# Logo
self.imgLabel = Label(self.frameOne, image = None)
self.imgLabel.grid(row=0,column=0)
self.img = ImageTk.PhotoImage(file = "logo.png")
self.imgLabel["image"] = self.img
self.botones()
def botones(self):
self.piezastext = Label(self.frameOne, text = " number of components ", justify="center")
self.piezastext.grid(row=1, column=0)
self.entrypiezas = Entry(self.frameOne,width=5)
self.entrypiezas.grid(row=2, column=0)
self.aceptarnumpiezas = Button(self.frameOne,text="Aceptar", command=self.aceptar_piezas,width=8)
self.aceptarnumpiezas.grid(row=6, column=0)
def aceptar_piezas(self):
num_piezas = self.entrypiezas.get()
print num_piezas
self.piezastext.grid_remove()
self.entrypiezas.grid_remove()
self.aceptarnumpiezas.grid_remove()
n = 1;
while n <= int(num_piezas):
self.textopieza = Label(self.frameOne, text = "Pieza", justify="left")
self.textopieza.grid(row=n, column=0)
// INSTEAD THESE 'n' BLANK ENTRYS, I WANT TO PUT 'n' DROP DOWN LISTS
self.entrypiezas = Entry(self.frameOne,width=5)
self.entrypiezas.grid(row=n, column=1)
self.aceptarpiezas = Button(self.frameOne,text="Aceptar",width=8)
self.aceptarpiezas.grid(row=int(num_piezas)+1, column=0)
n += 1
# Main
if __name__ == "__main__":
# create interfacE
root = Tk()
movieApp = Planificador(root)
root.mainloop()
So I want to know how can I put that drop down list on a given frame, frameOnein my case, instead of a full window. Thanks in advance.
I modified your aceptar_piezas function to do what I think you want:
def aceptar_piezas(self):
num_piezas = self.entrypiezas.get()
print num_piezas
self.piezastext.grid_remove()
self.entrypiezas.grid_remove()
self.aceptarnumpiezas.grid_remove()
# Create a list of tuples to hold the dynamically created Optionmenus
# The first item in the tuple is the menu, the second is its variable
self.optionmenus = list()
n = 1
while n <= int(num_piezas):
self.textopieza = Label(self.frameOne, text = "Pieza", justify="left")
self.textopieza.grid(row=n, column=0)
# Variable for the Optionmenu
var = StringVar()
# The menu
menu = OptionMenu(self.frameOne, var, "a","b","c")
menu.grid(row=n, column=1)
# Set the variable to "a" as default
var.set("a")
# Add the menu to the list of Optionmenus
self.optionmenus.append((menu, var))
n += 1
def clicked():
"""This function was made just to demonstrate. It is hooked up to the button"""
for optionmenu in self.optionmenus:
print optionmenu[1].get()
print self.optionmenus
# This button doesn't need to be in the while loop
self.aceptarpiezas = Button(self.frameOne, text="Aceptar", command=clicked, width=8)
self.aceptarpiezas.grid(row=int(num_piezas)+1, column=0)
The tuples in the list are in the order that the Optionmenus were created. So, the first tuple contains the data for the first Optionmenu, the second for the second, and so forth.

Categories

Resources