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.
Related
This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 1 year ago.
I'm stuck on the following problem. With a for-loop, I want to make a few checkboxes that automatically update a label stating whether the checkbox is ticked or not. However, it gives the wrong results (it always says that the checkboxes are ticked, whether this is the case or not; noteworthy is the fact that the checkboxes are unticked by default), see here how the GUI looks like (including error). The IntVars corresponding with the checkboxes are working correctly, as can be seen when ticking at least one of the checkboxes and pressing a button whose function is to read the checkboxes. See also the following code:
import tkinter as tk
top = tk.Tk()
n_passes = 3
checkbox_var = [0] * n_passes
checkbox = [0] * n_passes
def tick_passes(i): # update label saying if checkboxes are ticked
if checkbox_var[i].get == 0:
label = tk.Label(top, text = f"pass #{i} not ticked")
else:
label = tk.Label(top, text = f"pass #{i} ticked")
label.grid(row = 1, column = i)
def check_checkbox_var(): # check whether checkbox_var[i] is updated
for i in range(n_passes):
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
for i in range(n_passes):
checkbox_var[i] = tk.IntVar() # turn on/off certain passes
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
checkbox[i] = tk.Checkbutton(top, text = f"Tick pass {i}", variable =
checkbox_var[i], command = tick_passes(i))
checkbox[i].grid(row = 0, column = i, sticky=tk.W)
var_button = tk.Button(top, text = "Check checkbox_var", command =
check_checkbox_var).grid(row = 2, column = 0) # check whether checkbox_var[i] is updated
top.mainloop()
Could somebody help me with updating the labels? If there is another way to fix this issue, e.g. with buttons to be pressed instead of checkbuttons to be ticked, that would also work for mee.
i is always 2 because you're actually not running any loop after mainloop is started.
The following kind of works but you need to change something about the labels, because right now all labels are just added on top of each other. You should create them once and then just update the text but I'll leave that part for you.
import tkinter as tk
top = tk.Tk()
n_passes = 3
checkbox_var = [0] * n_passes
checkbox = [0] * n_passes
def tick_passes(): # update label saying if checkboxes are ticked
for i in range(n_passes):
if checkbox_var[i].get() == 0:
label = tk.Label(top, text = f"pass #{i} not ticked")
else:
label = tk.Label(top, text = f"pass #{i} ticked")
label.grid(row = 1, column = i)
def check_checkbox_var(): # check whether checkbox_var[i] is updated
for i in range(n_passes):
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
for i in range(n_passes):
print(i)
checkbox_var[i] = tk.IntVar() # turn on/off certain passes
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
checkbox[i] = tk.Checkbutton(top, text = f"Tick pass {i}", variable =
checkbox_var[i], command = tick_passes)
checkbox[i].grid(row = 0, column = i, sticky=tk.W)
var_button = tk.Button(top, text = "Check checkbox_var", command =
check_checkbox_var).grid(row = 2, column = 0) # check whether checkbox_var[i] is updated
top.mainloop()
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()
I have the following code for my GUI:
root = Tk()
draft = Frame(root)
draft.grid()
root.title("test")
var = StringVar()
emailLabel = Label(draft, text="E-Mail:")
emailLabel.grid(row = 0, column = 0)
email = Entry(draft, justify=LEFT)
email.grid(row = 0, column = 1)
email.insert(0, "E-Mail")
passLabel = Label(draft, text="Pass:")
passLabel.grid(row = 1, column = 0)
password = Entry(draft, justify=LEFT, show="*")
password.grid(row = 1, column = 1)
password.insert(0, "Password")
start = Button(draft, text = "Start")
start.grid(row = 2, column = 0)
stop = Button(draft, text = "Stop")
stop.grid(row = 2, column = 1)
status = Text(draft)
status.grid(row = 3)
status.insert(INSERT, "TESTING")
However, it's not lining up the way I want it. I want the label and textboxes aligned to the left not the right, and the status text box to take up the entire size of the bottom (It's more or less a log).
Here's a screenshot:
To make the Text widget span over multiple columns, use the columnspan argument:
status.grid(row=3, columnspan=2)
Additionally, you can use the sticky parameter in the grid method to make the widgets occupy as many space as possible. Use this in every grid call:
widget.grid(..., sticky=N+W+E+S)
If you want the labels to be smaller, you have to rethink your layout a bit.
(Little note: it's not suggested to import * from tkinter. import tkinter as tk is preferred.)
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 :)
I'm new to this GUI business with python2.7 and Tkinter. I'm trying to create a new frame depending on which Radiobutton the user choose, like a menu. When I click on a radiobutton it creats a new frame just like I want, but if I continue to click on the same radiobutton, it will create another frame, and another frame, etc. Can't seem to figure out on how to check if the Radiobutton is already marked (clicked on just once).
Hope I made myself clear, thankful for help!
class Books:
""" Books() is the main class for creating the whole interface """
def __init__(self):
""" Initialize the first function in class Books() """
self.library = "library.txt"
self.filepath = os.getcwd() + "/" + self.library
self.window = Tk()
self.window.title("Personal library")
self.window.wm_iconbitmap(default="myicon.ico")
userChoice = Frame(self.window, height = 1, bd = 1, relief = RIDGE)
userChoice.pack(side = TOP, pady = 10, padx = 5)
self.menuChoice = IntVar()
btAddBooks = Radiobutton(userChoice, text = "Add a new book to the library", value = 1, variable = self.menuChoice, command = self.processChoice)
btAddBooks.grid(row = 1, sticky = W)
btFindBooks = Radiobutton(userChoice, text = "Print info about a book", value = 2, variable = self.menuChoice, command = self.processChoice)
btFindBooks.grid(row = 2, sticky = W)
btPrintBooks = Radiobutton(userChoice, text = "Print all book titles in library", value = 3, variable = self.menuChoice, command = self.processChoice)
btPrintBooks.grid(row = 3, sticky = W
def processChoice(self):
""" Used to handle user choice of Radiobuttons """
if self.menuChoice.get() == 1:
self.processAddBooks()
elif self.menuChoice.get() == 2:
self.processFindBook()
elif self.menuChoice.get() == 3:
self.processShowBooks(self.filepath)
def processAddBooks(self):
""" Add a new book to the library. """
# Create a new frame
questions = Frame(self.window, height = 1, bd = 1, relief = SUNKEN)
questions.pack(fill = X, pady = 10, padx = 5)
# Do stuff with frame here...
Well, if you only need one frame to be open at a time, you can call frame.destroy() on the previous frame before you instantiate the new frame. However, this approach will require that there be something initialized for Tkinter to destroy the first time one of the buttons is selected, otherwise you'll get an error. For my purpose, I just created a throwaway class with a destroy method that did nothing, then used an instance of that class as a placeholder bound to that variable until my Toplevel widget was created for the first time. If you want multiple frames open at the same time, just not duplicates of the same option, try using a different variable name for each frame and only creating the frame if not frame.winfo_exists()--though I'm not 100% sure this wouldn't be susceptible to the same issue of needing a placeholder assigned to that variable until the frame is created the first time. If such is needed, the placeholder class would need a winfo_exists() method that would return False.