EDIT: I tried to edit it based on one suggestion that it needs to be tied to a function. But still not working properly. Thank you very much!
Hope you can help me. Saw related questions but not exactly the same. Thank you very much!
I have a radiobutton. Based on the selected value, the number of buttons will change. However, the number of buttons dont change. The number just based on the default value of the radiobutton (i tried changing it).
import tkinter
from tkinter import *
root = Tk()
TIME_SUBFRAME = root
#dont mind much this part, this is just the popup window that will show after I click the buttons dependent on the radiobutton
def month():
CAL_WINDOW = Toplevel(TIME_SUBFRAME) #other parts removed
#this is the part that I would want to be dependent on the radiobutton
ONLY_MONTH = Button(TIME_SUBFRAME, text='Month', command=month)
START_MONTH = Button(TIME_SUBFRAME, text='Start Month', command=month)
END_MONTH = Button(TIME_SUBFRAME, text='End Month', command=month)
def sing_month():
START_MONTH.destroy()
END_MONTH.destroy()
ONLY_MONTH.grid(row = 3, column = 2, columnspan = 2)
def mult_month():
ONLY_MONTH.destroy()
START_MONTH.grid(row = 3, column = 2)
END_MONTH.grid(row = 3, column = 3)
#Radiobuttons for timepoint selection type
YRTYPE = IntVar(TIME_SUBFRAME, 1)
SING_MONTH = Radiobutton(TIME_SUBFRAME, text = "Single Month", command = sing_month, variable = YRTYPE, value = 1)
MULT_MONTH = Radiobutton(TIME_SUBFRAME, text = "Multiple Months", command = mult_month, variable = YRTYPE, value = 2)
SING_MONTH.grid(row = 2, column = 2, padx = 10, pady = 10)
MULT_MONTH.grid(row = 2, column = 3, padx = 10, pady = 10)
root.mainloop()
The radiobutton numbers needs to checked their value when a function is called.You have declared checking statement in the current running block, which will return initial value of your radiobuttons.
The values needs to be checked when user checks the radiobutton.So, we need an extra button widget commanded with a function that checks the value of both radiobuttons and performs the related actions.
The radiobutton will not check the values automatically, it needs to be checked by function.
Here's your Solution,
import tkinter
from tkinter import *
root = Tk()
TIME_SUBFRAME = root
#dont mind much this part, this is just the popup window that will show after I click the buttons dependent on the radiobutton
def month():
CAL_WINDOW = Toplevel(TIME_SUBFRAME) #other parts removed
#this is the part that I would want to be dependent on the radiobutton
ONLY_MONTH = Button(TIME_SUBFRAME, text='Month', command=month)
START_MONTH = Button(TIME_SUBFRAME, text='Start Month', command=month)
END_MONTH = Button(TIME_SUBFRAME, text='End Month', command=month)
def sing_month():
START_MONTH.grid_remove()
END_MONTH.grid_remove()
ONLY_MONTH.grid(row = 3, column = 2, columnspan = 2)
def mult_month():
ONLY_MONTH.grid_remove()
START_MONTH.grid(row = 3, column = 2)
END_MONTH.grid(row = 3, column = 3)
#Radiobuttons for timepoint selection type
YRTYPE = IntVar(TIME_SUBFRAME, 1)
SING_MONTH = Radiobutton(TIME_SUBFRAME, text = "Single Month", command = sing_month, variable = YRTYPE, value = 1)
MULT_MONTH = Radiobutton(TIME_SUBFRAME, text = "Multiple Months", command = mult_month, variable = YRTYPE, value = 2)
SING_MONTH.grid(row = 2, column = 2, padx = 10, pady = 10)
MULT_MONTH.grid(row = 2, column = 3, padx = 10, pady = 10)
root.mainloop()
Related
I have a check button that is checked by default. If the user unchecks it, a label and an entry should appear. I tried to do so by using the key binding method; however, it has a drawback which is that if the user checks the checkbox again, the new label and entry won't disappear. How do I solve that problem?
checkButtonVar = IntVar(value = 1)
checkButtonIsChnaceDefault = Checkbutton(root, variable = checkButtonVar)
labelIsChanceDefault = Label(root, text="Make chance = 0.9?")
labelIsChanceDefault.grid(row=3, column = 0, sticky = 'w')
checkButtonIsChnaceDefault.grid(row = 3, column = 1)
def checkCheckButton(event):
labelChance = Label(root, text = "Enter chance of winning")
labelChance.grid( row = 3, column = 2)
global entryChance
entryChance = Entry(root, borderwidth = 3)
entryChance.grid(row = 3, column = 3)
checkButtonIsChnaceDefault.bind('<Button-1>', checkCheckButton)
Here's a screenshot of the program to make things clear.
You don't need to bind the Check-button. Use command option. And setting offvalue and onvalue can control the appearance.
See the tkinter.Checkbutton
checkButtonVar = IntVar()
checkButtonIsChnaceDefault = Checkbutton(root, variable = checkButtonVar,offvvalue=0,onvalue=1,command=checkCheckButton)
...
checkButtonIsChnaceDefault.grid(row = 3, column = 1)
#==== Define the widgets here.
labelChance = Label(root, text = "Enter chance of winning")
entryChance = Entry(root, borderwidth = 3)
def checkCheckButton():
if checkButtonVar.get()==0:
labelChance.grid( row = 3, column = 2)
entryChance.grid(row = 3, column = 3)
else:
labelChance.grid_forget()
entryChance.grid_forget()
I'm using grid_remove() and grid() command to hide/show the widget but the result is the other widget is move out of the original position.
How to hide/show the widget without moving widget
Example:
from tkinter import *
from tkinter import ttk
GUI = Tk()
GUI.title("myTest")
GUI.geometry("700x700")
Nameget = StringVar()
Priceget = StringVar()
Quantityget = StringVar()
Unitget = StringVar()
Partnumget = StringVar()
L_Partnum = ttk.Label(GUI, text = 'Part number')
L_Partnum.grid(row = 0, column = 0)
L_namme = ttk.Label(GUI, text = 'Name')
L_namme.grid(row = 0, column = 1)
L_quan = ttk.Label(GUI, text = 'Quantity')
L_quan.grid(row = 1, column = 2)
L_quan.grid_remove()
L_price = ttk.Label(GUI, text = 'Price')
L_price.grid(row = 3, column = 3)
E_partnum = ttk.Entry(GUI, textvariable = Partnumget)
E_partnum.grid(row = 1, column = 0)
E_namme = ttk.Entry(GUI,textvariable = Nameget)
E_namme.grid(row = 1, column = 1)
E_unit = ttk.Entry(GUI,textvariable = Unitget)
E_quan = ttk.Entry(GUI,textvariable = Quantityget)
E_quan.grid(row = 2, column = 2)
E_quan.grid_remove()
E_price = ttk.Entry(GUI,textvariable = Priceget)
E_price.grid(row = 4, column = 3)
I_check_vat = IntVar()
def d_check_vat_1():
E_partnum.focus()
if I_check_vat.get() == 1:
L_quan.grid()
E_quan.grid()
elif I_check_vat.get() == 0:
L_quan.grid_remove()
E_quan.grid_remove()
C_CHECK_VAT = ttk.Checkbutton(GUI, text="click here to see the result", variable=I_check_vat, command=d_check_vat_1)
C_CHECK_VAT.grid(row = 5, column = 0)
GUI.mainloop()
Before clicking:
After clicking:
image with the expected output:
The problem is grid() does not take up empty space by default, it gives the last empty row/col to the widget(if previous rows before it are empty).
So what you can do is, set minimum space for your column and row so that those space will remain empty, so change your function to:
def d_check_vat_1():
E_partnum.focus()
if I_check_vat.get():
L_quan.grid(row=2, column=2)
E_quan.grid(row=3, column=2)
width = E_quan.winfo_reqwidth() # Get widget width
height = L_quan.winfo_reqheight() # Get widget height
GUI.rowconfigure(2,minsize=height) # Now apply the values
GUI.rowconfigure(3,minsize=height)
GUI.columnconfigure(2,minsize=width)
else:
L_quan.grid_remove()
E_quan.grid_remove()
Now its dynamic as well, it takes the width of widget and applies that as the minsize of that row so that row will have that empty space.
I am new with Python GUI creation and I am trying to get the file path of the .csv file from a directory and print it on a text box in a GUI. I am using tkinter library for the GUI and I can't seem to make it work. Is there anyone who can help me with this problem?
import tkinter as tk
from tkinter.filedialog import askopenfilename
def browseFile1():
global infile1
infile1=askopenfilename()
txt1.insert(0.0, infile1)
root = tk.Tk()
root.title("CSV Comparison Tool")
Label = tk.Label(root, text="Select CSV files to compare").grid(row = 1, column = 0, columnspan = 30)
browseButton1 = tk.Button(root,text="Browse", command=browseFile1).grid(row = 2, column = 30)
txt1 = tk.Text(root, width = 100, height = 1).grid(row = 2, column = 0, columnspan = 30)
root.mainloop()
The error says:
AttributeError: 'NoneType' object has no attribute 'insert'
I tried 1 button first and applying it on the next one it it works. I am using spyder as a tool.
Thanks!
Your problem is these lines:
Label = tk.Label(root, text="Select CSV files to compare").grid(row = 1, column = 0, columnspan = 30)
browseButton1 = tk.Button(root,text="Browse", command=browseFile1).grid(row = 2, column = 30)
txt1 = tk.Text(root, width = 100, height = 1).grid(row = 2, column = 0, columnspan = 30)
The grid method on a widget—like most methods that mutate objects in Python—returns None. So you're just storing None in Label, and browseButton1, and txt1. So when you later try this:
txt1.insert(0.0, infile1)
That's trying to call None.insert, which obviously doesn't work. Tkinter catches the error, prints it out to the terminal, and keeps going as if your function had never been called.
The solution is to just not do that. Instead, do this:
Label = tk.Label(root, text="Select CSV files to compare")
Label.grid(row = 1, column = 0, columnspan = 30)
browseButton1 = tk.Button(root,text="Browse", command=browseFile1)
browseButton1.grid(row = 2, column = 30)
txt1 = tk.Text(root, width = 100, height = 1)
txt1.grid(row = 2, column = 0, columnspan = 30)
Now, not only does your code work, it even fits in a typical editor window or Stack Overflow page.
I want to create a GUI where you specify a bunch of files for later processing (commandline parsing a dozen files is just a PITA).
So now I want to group a lable and a button for better readability.
I've tried something like that:
DC1_path_label = Label(window_fine_DC, text = "Please specify the path of DC 1:", relief=RAISED)
DC1_B = Tkinter.Button(window_fine_DC, textvariable = DC_path1, command = setDC1)
DC2_path_label = Label(window_fine_DC, text="Please specify the path of DC 2:", relief=RAISED)
DC2_B = Tkinter.Button(window_fine_DC, textvariable=DC_path2, command=setDC2)
DC1_path_label.grid(row = 0, column = 1)
DC1_B.grid(row = 1, column = 1)
DC2_path_label.grid(row = 3, column = 1)
DC2_B.grid(row = 4, column = 1)
but it seems to have no effect, also paddings dont work that great either, since those go in all directions equally.
And while we are at it, is there a more elegant way to change a window than closing the old one, and opening a new?
Sorry if this is a stupid question, I'm fairly new with python/gui stuff...
I believe what you need is to provide a tuple to your padx and/or pady.
You can specify padding for each side this way.
I use pady as an example here to show how you can provide padding on only one side. Notice how the top Label is padded at its top but the bottom button is not padded on the bottom side.
from tkinter import *
root = Tk()
DC1_path_label = Label(root, text = "Please specify the path of DC 1:", relief=RAISED)
DC1_B = Button(root)
DC2_path_label = Label(root, text="Please specify the path of DC 2:", relief=RAISED)
DC2_B = Button(root)
DC1_path_label.grid(row = 0, column = 1, pady = (10, 0))
DC1_B.grid(row = 1, column = 1, pady = (10, 0))
DC2_path_label.grid(row = 3, column = 1, pady = (10, 0))
DC2_B.grid(row = 4, column = 1, pady = (10, 0))
root.mainloop()
Result:
Update:
As far as changing your window there are several options for manipulating what is there and replacing the content.
You could destroy() the widgets and make new ones. Though this does not strike me as more elegant. It will allow you to keep the window open though.
There are some config options you can use to change the text of current widgets or rearrange the grid through a series of configs. Though this does not strike me as elegant either.
I want to have the text input of this entry box save to a list and then be printed. I cannot have it save the input upon the button press and it just prints the placeholder variable.
names = []
from tkinter import*
class Trip:
def __init__(self, parent):
E_name = "q"
self.En_name = "g"
self.En_name = str(self.En_name)
self.go = Frame(parent, width = 500, height = 450, bg = "snow", pady = 30, padx = 10)
self.go.grid(row = 1, column = 0)
self.go.grid_propagate(0) # to reserve space required for frame
self.tet = Frame(parent, width = 500, height = 450, bg = "snow")
name = Label(self.go, text = "Name:", bg = "snow")
name.grid(row = 1, column = 0, sticky = E)
self.E_name = Entry(self.go, width = 40, textvariable = self.En_name)
self.E_name.grid(row = 1, column = 1, sticky = W, pady = 4)
menuButton = Button(self.go, text = "Continue", command = self.breakeverything)
menuButton.grid(row = 8, column = 1, pady = 4)
def breakeverything(self):
names.append(self.En_name)
print (names[0])
self.E_name.delete(0, "end")
#main routine
if __name__ == "__main__":
root = Tk()
root.title("Traveller Details")
play = Trip(root)
root.geometry("500x450+0+0")
root.mainloop()
A textvariable is supposed to be a tkinter.StringVar(), not a primitive string. Your application looks simple enough that it shouldn't even need it. Take out self.En_name, take out the textvariable, and just retrieve the current value of the Entry widget in breakeverything() (which should no longer be an appropriate name):
def breakeverything(self):
names.append(self.E_name.get())
print(names[-1]) # printing the last name in the list seems more useful
self.E_name.delete(0, "end")
I would also recommend moving names into Trip.__init__ and making it an instance variable like everything else, with self.names = []. It'll make it easier to keep track of scopes.
You're using textvariable incorrectly (you must use one of the special Tkinter variables such as StringVar), but you don't need to use it at all. Simply save a reference to the widget, then call the get method when you want the value:
self.E_name = Entry(self.go, width = 40)
...
print("you entered: " + self.E_name.get())
If you insist o using textvariable, use a StringVar and then call the get method on that instead:
self.En_name = StringVar()
self.E_name = Entry(..., textvariable=self.En_name)
...
print("you entered: " + self.En_name.get())