The radiobuttons cannot be unselected by default - python

def booking(self):
self.book_win = tk.Tk()
self.book_win.geometry('1000x600')
self.fm7 = tk.Frame(self.book_win,width=300,height=500)
self.fm7.grid(row=0,column=0,rowspan=3,columnspan=2)
self.fm8 = tk.Frame(self.book_win,width=300,height=500)
self.fm8.grid(row=0,column=2,rowspan=3,columnspan=2)
self.book_title = tk.Label(self.fm7,text='Room Prices per night',font=('Helvetica',24))
self.book_title.grid(row=0,columnspan=2,padx=10,pady=10)
self.lb_deluxe = tk.Label(self.fm7,text='Deluxe Room',font=('Helvetica',20))
self.lb_deluxe.grid(row=1,column=0,padx=10,pady=10)
self.pr1 = tk.Label(self.fm7,text=2050,font=('Helvetica',20))
self.pr1.grid(row=1,column=1,padx=10,pady=10)
self.lb_twin = tk.Label(self.fm7,text='Twin Bedroom',font=('Helvetica',20))
self.lb_twin.grid(row=2,column=0,padx=10,pady=10)
self.pr2 = tk.Label(self.fm7,text=2500,font=('Helvetica',20))
self.pr2.grid(row=2,column=1,padx=10,pady=10)
self.lb_king = tk.Label(self.fm7,text='King Bedroom',font=('Helvetica',20))
self.lb_king.grid(row=3,column=0,padx=10,pady=10)
self.pr3 = tk.Label(self.fm7,text=2890,font=('Helvetica',20))
self.pr3.grid(row=3,column=1,padx=10,pady=10)
self.lb_harbour = tk.Label(self.fm7,text='Harbour View Room',font=('Helvetica',20))
self.lb_harbour.grid(row=4,column=0,padx=10,pady=10)
self.pr4 = tk.Label(self.fm7,text=3120,font=('Helvetica',20))
self.pr4.grid(row=4,column=1,padx=10,pady=10)
self.var1 = tk.BooleanVar()
self.ck_breakfast = tk.Checkbutton(self.fm8,text='Breakfast',variable=self.var1,font=('Helvetica',20))
self.ck_breakfast.grid(row=0,columnspan=2,padx=10,pady=10)
self.lb_room = tk.Label(self.fm7,text='Type of Room',font=('Helvetica',20))
self.lb_room.grid(row=6,columnspan=2,padx=10,pady=10)
self.var2 = tk.StringVar()
self.var2.set(' ')
self.rb1 = tk.Radiobutton(self.fm7,text='Deluxe Room',variable=self.var2,value='Deluxe Room')
self.rb1.grid(row=7,column=0,padx=10,pady=10)
self.rb2 = tk.Radiobutton(self.fm7,text='Twin Bedroom',variable=self.var2,value='Twin Bedroom')
self.rb2.grid(row=7,column=1,padx=10,pady=10)
self.rb3 = tk.Radiobutton(self.fm7,text='King Bedroom',variable=self.var2,value='King Bedroom')
self.rb3.grid(row=8,column=0,padx=10,pady=10)
self.rb4 = tk.Radiobutton(self.fm7,text='Harbour View Room',variable=self.var2,value='Harbour View Room')
self.rb4.grid(row=8,column=1,padx=10,pady=10)
In this program, I would like to set all the radiobuttons at the beginning to be unselected. Although I tried self.var2.set(' ') it still does not work. I have already tried to find the solution and change thoroughly but there may have some problems occur. If possible can anyone help me to find out the problem?

The problem with your code was that it has more than one instance of Tk() hence the StringVar() doesnt know which instance to belong to(by default the first created Tk()). So make all additional child windows to Toplevel() and just keep one Tk() for the entire code, unless you exactly know what your doing.
Or if you still wish to keep multiple Tk() then give a master to almost all the extra widgets or variables created(StringVar,IntVar,PhotoImage,etc) like:
self.var2 = tk.StringVar(master=self.book_win)

This is might not work
self.var2 = tk.StringVar()
self.var2.set(None) #set this to none
self.rb1 = tk.Radiobutton(self.fm7,text='Deluxe Room',variable=self.var2,value='Deluxe Room')
self.rb1.grid(row=7,column=0,padx=10,pady=10)
self.rb2 = tk.Radiobutton(self.fm7,text='Twin Bedroom',variable=self.var2,value='Twin Bedroom')
self.rb2.grid(row=7,column=1,padx=10,pady=10)
self.rb3 = tk.Radiobutton(self.fm7,text='King Bedroom',variable=self.var2,value='King Bedroom')
self.rb3.grid(row=8,column=0,padx=10,pady=10)
self.rb4 = tk.Radiobutton(self.fm7,text='Harbour View Room',variable=self.var2,value='Harbour View Room')
self.rb4.grid(row=8,column=1,padx=10,pady=10)

Related

how to generate multiple buttons with a loop?

I have programmed software that displays a "tuile".
Definition of a tuile:
A tuile is a Frame which contains a button which displays an image and an explanatory text.
I would like to display 3 tuiles with 3 different settings.
listes_icones = ["icone1.png","icone2.png","icone3.png"]
listes_relx = [".3",".4",".5"]
listes_text = ["SYSTEM", "USER", "GAME"]
for i in range(3):
gen_img = PhotoImage(file=listes_icones[i])
gen_cadre = Frame(home,width=100, height=100,bg=bg_root)
gen_cadre.place(anchor="c", relx=listes_relx[i], rely=.5)
gen_img_bouton = Button(gen_cadre, image=gen_img, relief="flat",bg=bg_root)
gen_img_bouton.pack()
gen_text = Label(gen_cadre, text=listes_text[i], bg=bg_root, fg=text_color,font="blocktastic 18")
gen_text.pack()
I manage to display the text but not the button and the image, the variable is overwritten. How to solve this problem?
The problem that you are facing is like you said, the variable is overwritten in your loop. To solve this you need to keep track of your generated images. A simple solution is to store them in a list and get them in the next step. Here is an exampel:
import tkinter as tk
import PIL
listes_icones = ["icone1.png","icone2.png","icone3.png"]
gen_icons = []
listes_relx = [".3",".4",".5"]
listes_text = ["SYSTEM", "USER", "GAME"]
home = tk.Tk()
for i in range(3):
gen_img = tk.PhotoImage(file=listes_icones[i])
gen_icons.append(gen_img)
gen_cadre = tk.Frame(home,width=100, height=100)
gen_cadre.place(anchor="c", relx=listes_relx[i], rely=.5)
gen_img_bouton = tk.Button(gen_cadre, image=gen_icons[i], relief="flat")
gen_img_bouton.pack()
gen_text = tk.Label(gen_cadre, text=listes_text[i], font="blocktastic 18")
gen_text.pack()
home.mainloop()

Delete/hide HBox and children widgets using Button inside HBox

I am trying to make an input widget for a module i have made (see this SO question).
The input widget should have a title bar and a variable number of input lines below. I had in mind to have an delete button at the end of each input line.
The delete button should ideally delete the container widget and all the children widgets, but hiding the container widget and children would also be acceptable.
I have not been able to find a useful recipe to this problem.
Currently i got this code, but i have no clue less as how to solve the problem.
import ipywidgets as w
​
def add_btn_clicked(b):
input_box.children = (input_box.children[0], line()) + input_box.children[1:]
​
def delete_btn_clicked(b):
# ???
with output:
print(b.keys)
return None
add = w.Button(icon="plus-circle")
add.on_click(add_btn_clicked)
​
title = w.HBox([w.Label(value=str(i)) for i in range(3)]+[add])
​
def line():
delete = w.Button(icon="trash")
delete.on_click(delete_btn_clicked)
return w.HBox([w.FloatText(value=i) for i in range(3)]+[delete])
​
input_box = w.VBox([title,line()])
output = w.Output()
​
display(input_box)
display(output)
Is there a way to tell what the parent element is from the button click or another way to achieve what I am attempting?
You can create the widgets and container separately, then define the .parent attribute on the children as the container, before assembling together. That way you can effectively hide the container when the button is clicked (with .parent.layout.display = 'none').
import ipywidgets as w
def add_btn_clicked(b):
input_box.children = (input_box.children[0], line()) + input_box.children[1:]
def delete_btn_clicked(b):
b.parent.layout.display = 'none'
add = w.Button(icon="plus-circle")
add.on_click(add_btn_clicked)
title = w.HBox([w.Label(value=str(i)) for i in range(3)]+[add])
def line():
delete = w.Button(icon="trash")
delete.on_click(delete_btn_clicked)
val_widgets = [w.FloatText(value=i) for i in range(3)]
container = w.HBox()
delete.parent = container
for widg in val_widgets:
widg.parent = container
children = val_widgets + [delete]
container.children = children
return container
input_box = w.VBox([title,line()])
output = w.Output()
display(input_box)
display(output)

How do you use tkinter entry boxes to make a variable?

I'm currently trying to create an "orbit simulator" and this part of the code is part of it. However an errors occur when I try to run it. The get() function seems to not work as it simply outputs that it doesn't exist.
I'm really stumped at this.
import tkinter
runwin = tkinter.Tk()
runwin.title("Orbit Sim")
runwin.geometry("320x320")
def run21():
dt=ent21.get("1.0")
tg=ent22.get("1.0")
xz=ent23.get("1.0")
yz=ent24.get("1.0")
velz=ent25.get("1.0")
runwin.destroy()
lbl21 = tkinter.Label(runwin, text="How long to simulate for?").pack()
ent21 = tkinter.Entry(runwin).pack()
lbl22 = tkinter.Label(runwin, text="How many seconds pass per check?").pack()
ent22 = tkinter.Entry(runwin).pack()
lbl23 = tkinter.Label(runwin, text="Starting Positon? Please state X then Y.").pack()
ent23 = tkinter.Entry(runwin).pack()
ent24 = tkinter.Entry(runwin).pack()
lbl24 = tkinter.Label(runwin, text="Starting Velocity").pack()
ent25 = tkinter.Entry(runwin).pack()
btn21 = tkinter.Button(runwin, text="Submit", command=run21).pack()
runwin.mainloop()
t=0
while t < dt:
r3, t =m.sqrt((xz*xz)+(yz*yz)), t+tg
P.S. I'm not a genius at coding and the way i've written this code is pretty much the only way I can understand it without sufficient notes.
You have 3 problems I can see.
1st problem is you are using the grid manager on the widget directly and this will cause your get() method to error out. That is be cause the grid manager is returning None.
We can fix this by calling the grid manager on a new line.
2nd you are putting "1.0" in the get method and this is going to error out.
Just leave it blank like this get().
3rd you need to define your variables to be ran after the program closes as outside of the tkinter instance. Then you need to set the global call up in your function.
Take a look at the below code:
import tkinter
# the 5 below variables are listed outside of tkinter so your while statement
# after the mainloop can use the data.
dt = ""
tg = ""
xz = ""
yz = ""
velz = ""
runwin = tkinter.Tk()
runwin.title("Orbit Sim")
runwin.geometry("320x320")
def run21():
# this global is needed to tell the run21 function the variables are
# in the global namespace.
global dt, tg, xz, yz, velz
dt=ent21.get()
tg=ent22.get()
xz=ent23.get()
yz=ent24.get()
velz=ent25.get()
runwin.destroy()
lbl21 = tkinter.Label(runwin, text="How long to simulate for?").pack()
ent21 = tkinter.Entry(runwin)
ent21.pack()
lbl22 = tkinter.Label(runwin, text="How many seconds pass per check?").pack()
ent22 = tkinter.Entry(runwin)
ent22.pack()
lbl23 = tkinter.Label(runwin, text="Starting Positon? Please state X then Y.").pack()
ent23 = tkinter.Entry(runwin)
ent23.pack()
ent24 = tkinter.Entry(runwin)
ent24.pack()
lbl24 = tkinter.Label(runwin, text="Starting Velocity").pack()
ent25 = tkinter.Entry(runwin)
ent25.pack()
btn21 = tkinter.Button(runwin, text="Submit", command=run21).pack()
t=0
runwin.mainloop()
print(dt, tg, xz, yz, velz)
# commented out as it is not testable without knowing what "m" is.
# while t < dt:
# r3, t = m.sqrt((xz*xz)+(yz*yz)), t+tg
Don't define a widget and use the layout manager on the same line if you wish to use the Widget.
i.e DON'T DO THIS
ent21 = tkinter.Entry(runwin).pack()
DO THIS
ent21 = tkinter.Entry(runwin)
ent21.pack()
Like so
import tkinter
runwin = tkinter.Tk()
runwin.title("Orbit Sim")
runwin.geometry("320x320")
dt = ""
tg = ""
xz = ""
yz = ""
velz = ""
def run21():
global dt, tg, xz, yz, velz
dt=ent21.get()
tg=ent22.get()
xz=ent23.get()
yz=ent24.get()
velz=ent25.get()
runwin.destroy()
lbl21 = tkinter.Label(runwin, text="How long to simulate for?").pack()
ent21 = tkinter.Entry(runwin)
ent21.pack()
lbl22 = tkinter.Label(runwin, text="How many seconds pass per check?").pack()
ent22 = tkinter.Entry(runwin)
ent22.pack()
lbl23 = tkinter.Label(runwin, text="Starting Positon? Please state X then Y.").pack()
ent23 = tkinter.Entry(runwin)
ent23.pack()
ent24 = tkinter.Entry(runwin)
ent24.pack()
lbl24 = tkinter.Label(runwin, text="Starting Velocity").pack()
ent25 = tkinter.Entry(runwin)
ent25.pack()
btn21 = tkinter.Button(runwin, text="Submit", command=run21).pack()
runwin.mainloop()
One of the other commenters is correct too. Any code after .mainloop will not run until after the window is closed. Consider doing this inside the run21 function so it happens when the button is pressed.
I've removed "1.0" from your get since the get method of an entry widget doesn't take any arguments.
Also please consider better naming for your variables. Instead of ent21 consider entrySimulationTime or instead of ent24 consider entryStartingPosY. Your code will be much easier to understand that way.
EDIT: Added globals to expand the scope of dt etc.

Change the color of a single word in a tk option menu?

So I'm grabbing links of events off a website and putting them into a drop down menu to be selected. My code for the menu:
import Tkinter as tk
from Tkinter import StringVar
selectMenu = tk.Tk()
# #-> this is what I have
# Followed by what you can use
#var = Vars()
#events = var.GetVars('Event')
events = " "
options = []
links = []
#forms = (driver.find_elements_by_class_name("with-cats")) #This is what I have
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself
for x in forms:
#info = x.text
info = x #Again, this is so you can try it for yourself
if events in info.lower():
links.append(x)
for link in range(0,len(links)):
#options.append(links[link].text)
options.append(links[link])
list(set(options))
selection = []
for link in range(0,len(options)):
selection.append(options[link])
select = StringVar(selectMenu)
select.set("--None Selected--")
menu = tk.OptionMenu(selectMenu, select, *(selection))
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menu.pack(side="top", pady=10)
selectMenu.attributes('-topmost', True)
selectMenu.mainloop()
So this works fine and dandy, but I would like to improve the look to make it more obvious which events are open. To clarify, an event found that is open and put into the menu may look like "This is a cool event", but one that is closed would be read as "This is a cool event Closed". My aim is to be able to make the foreground red of either just the word Closed or the string containing Closed, whichever is possible if any (And I'm not sure if it's possible because menus and buttons on osx are usually defaulted to system settings, maybe there is a way around this?).
Current: Desired:
According to the documentation for OptionMenu here and here I don't think there is a way to set the color of text.
You might be able to get something close to what you want by using a listBox instead. See post here for the listBox example.
Found a solution! Using a Menu inside of a MenuButton the same way Tkinter creates MenuOptions, I was able to create a custom MenuOption. If you want to add more options, you can use the menbutton.configure() option to edit the button, and menbutton.menu to edit the menu items.
import Tkinter as tk
from Tkinter import Menu, Menubutton
class Vars():
global vari
vari = {}
def GetVars(self, var):
return vari.get(str(var))
def SendVars(self, var, val):
vari[str(var)] = val
class App():
def buttselect(self, link, menbutton, selectMenu):
var = Vars()
var.SendVars("Selection", link) # Store selected event
menbutton.configure(text=link) # Set menu text to the selected event
def prnt(self, link):
var = Vars()
print var.GetVars("Selection") # Print event
def __init__(self, selectMenu):
events = " "
options = []
links = []
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself
menbutton = Menubutton (selectMenu, text="--None Selected--", relief="raised")
menbutton.grid()
menbutton.menu = Menu (menbutton, tearoff=0)
menbutton["menu"] = menbutton.menu
#Get a list of event names
for x in forms:
info = x #Again, this is so you can try it for yourself
#If desired event keyword is in an event name, add it to the correct links
if events in info.lower():
links.append(x)
#Remove duplicates
for link in range(0,len(links)):
options.append(links[link])
list(set(options))
#Final list of event names turned into menu commands
for link in options:
if "Closed" in link:
menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu), foreground='red')
else:
menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu))
b = tk.Button(selectMenu, text="Selection", command= lambda link=link: self.prnt(link)) #Print selected event
b.pack()
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menbutton.pack(side="top", pady=10)
selectMenu = tk.Tk()
selectMenu.attributes('-topmost', True)
app = App(selectMenu)
selectMenu.mainloop()
This results in exactly the result desired:
I found a way!
Let's say x is an optionmenu with options:
options=['Red','Blue','Green']
defopt=tk.StringVar(options[0]) #StringVariable to hold the selected option.
x=tk.OptionMenu(self.optmenuframe,defopt,*options)
Now, get the menu object from the optionmenu and use entryconfig method. That's it!
x.children['menu'].entryconfig(0,foreground='red')
x.children['menu'].entryconfig(1,foreground='blue')
x.children['menu'].entryconfig(2,foreground='green')
#0 is the index of the option you want to apply the configurations to.

Dynamically printing value of entry in another entry

My code:
import tkinter as tk
disp = tk.Tk()
hlabel=tk.Label(text="host")
hlabel.grid(column=0,row=0)
host_entry = tk.Entry(disp)
host_entry.grid(row=0,column=1)
plabel=tk.Label(text="port")
plabel.grid(column=0,row=1)
port_entry = tk.Entry(disp)
port_entry.grid(row=1,column=1)
ulabel=tk.Label(text="Url")
ulabel.grid(column=0,row=3)
url_entry=tk.Entry(disp)
url_entry.grid(row=3,column=1)
url_entry.insert(0,'http://{0}:{1}'.format(host_entry.get(),port_entry.get()))
url_entry.config(state='disabled')
disp.mainloop()
I looked through this awesome answer but couldn't figure out.
The 'host' and 'port' should be displayed in the 'url' Entry as
http://localhost:8080.
The text should be displayed dynamically in url.
Thanks for your help.
The simplest solution is to use a textvariable for each entry, put a trace on each variable, and then update the third entry whenever the trace fires.
First, define a function to update the third entry. It will be called by the trace functions, which automatically appends some arguments which we won't use:
def update_url(*args):
host = host_var.get()
port = port_var.get()
url = "http://{0}:{1}".format(host, port)
url_var.set(url)
Next, create the variables:
host_var = tk.StringVar()
port_var = tk.StringVar()
url_var = tk.StringVar()
Next, add a trace on the host and port:
host_var.trace("w", update_url)
port_var.trace("w", update_url)
Finally, associate the variables with the entries:
host_entry = tk.Entry(..., textvariable=host_var)
port_entry = tk.Entry(..., textvariable=port_var)
url_entry=tk.Entry(..., textvariable=url_var)
Here it is as a full working example:
import tkinter as tk
def update_url(*args):
host = host_var.get()
port = port_var.get()
url = "http://{0}:{1}".format(host, port)
url_var.set(url)
disp = tk.Tk()
host_var = tk.StringVar()
port_var = tk.StringVar()
url_var = tk.StringVar()
host_var.trace("w", update_url)
port_var.trace("w", update_url)
hlabel=tk.Label(text="host")
plabel=tk.Label(text="port")
ulabel=tk.Label(text="Url")
host_entry = tk.Entry(disp, textvariable=host_var)
port_entry = tk.Entry(disp, textvariable=port_var)
url_entry=tk.Entry(disp, textvariable=url_var)
url_entry.config(state='disabled')
hlabel.grid(column=0,row=0)
host_entry.grid(row=0,column=1)
plabel.grid(column=0,row=1)
port_entry.grid(row=1,column=1)
ulabel.grid(column=0,row=3)
url_entry.grid(row=3,column=1)
disp.mainloop()

Categories