Pass widget name on button click - python

Can someone help, i need to generate 10 buttons and then when i click it must change the text on the unnamed button.
trying to get the event.widget but with no successes
from tkinter import ttk
root = ttk()
def gonow(e):
e.config(text="clicked")
for x in range(0, 10):
ttk.Button(root, name="but"+x,width="30", height=3, text=x).grid( column=0,
r.ow=0, padx=10, pady=5)
butok=ttk.Button(root, width="30", height=3, text=x, command=lambda var="but"+x:
gonow(var)).grid( column=0, row=0, padx=10, pady=5)
if __name__ == "__main__":
root.mainloop()
New update
b = tk.Button(frm_txt_json_case_btn, width="30", height=3, text=str(titulo+" "+cherep), fg=fcolor,relief=relifst, borderwidth=4,command=lambda titulo=titulo,wrd2srch=words2search,assumirrow=assumirrow,hiden_row=assumirrowr,resp_kib=resp_kiblog,repkib=repkib,urrrl=url_conf, jsump=jsonreq, explis=expectresq, frm_txt_json_case_tit=frm_txt_json_case_tit, inp_cond_protocol=inp_cond_protocol, resp_json=resp_json_input,lblexp=lblexpect, reqtxt=reqst_input,frm_txt_json_case_btn=frm_txt_json_case_btn: ChangConfWI(reqtxt, lblexp, frm_txt_json_case_tit, resp_json, inp_cond_protocol,urrrl, jsump, explis,frm_txt_json_case_btn,repkib,resp_kib,wrd2srch,hiden_row,assumirrow,titulo))
b.grid(column=colcount, row=rowcount, padx=10, pady=5)
buttonslst.append(b)
valbut=int(assumirrowr)-8
print(valbut)
print(buttonslst[valbut])
fvarbut=buttonslst[valbut]
print(fvarbut)
ttk.Button(frm_but_oknot, width="15", text="OK", image=photoOK, command=lambda assumirrow=assumirrow,filename=filename_report,exp=lblexpect,obs=resp_kiblog,urrrl=url_conf,tipo_de_conf=tipo_de_conf, resp_json_input=resp_json_input, reqst_input=reqst_input: savetoxls("geradorteste",resp_json_input,reqst_input, "OK",tipo_de_conf,urrrl,obs,exp,filename,assumirrow,fvarbut)).grid( column=0, row=0, padx=1, pady=15)

When you pass x to gonow, it is the index of the button, not the button itself. You could store the buttons in a list (note: the buttons, not the result of grid!), and then use the index:
buttons = []
for x in range(0, 3):
b = tk.Button(root, width=30, height=3, text=x, command=lambda x=x: gonow(buttons[x]))
b.grid(column=0, row=x, padx=10, pady=5)
buttons.append(b)
Or postpone the command creation after the button is created and pass the button itself:
for x in range(0, 3):
b = tk.Button(root, width=30, height=3, text=x)
b.config(command=lambda b=b: gonow(b))
b.grid(column=0, row=x, padx=10, pady=5)
(Note: There are a few more unrelated (syntax) errors throughout your code that you should fix.)

Related

Tkinter, class, and calling external python program

I have a program called main.py:
def prog2():
exec(open("prog2.py").read())
buttonHMI = tk.Button(text="Program HMI", width=15, font=("Arial", 14), command=prog2)
buttonHMI.grid(column=0, row=3, columnspan=1, padx=20, pady=10, sticky=W)
So there's 1 button and when pressed it executes a 2nd program called prog2:
from tkinter import *
from tkinter import ttk
window = tk.Tk()
def close():
window.destroy
CB1 = Checkbutton(window, text="Enable VNC", font=("Arial", 12), variable=action_VNC)
CB1.grid(row=0, sticky=W, padx=10)
CB1.configure(bg='#34aeeb')
ButtonClose= tk.Button(window, text="Close", width=20, font=("Arial", 14), command=window.destroy)
ButtonClose.grid(columnspan=2, column = 3, row=9, sticky=W, padx=10, pady=10)
class Timer:
def __init__(self, window=None):
self.sv = tk.StringVar()
ButtonShow = tk.Button(window, text="Program HMI", width=20, font=("Arial", 14), command=self.actions)
ButtonShow.grid(columnspan=2, row=9, column = 0, sticky=W, padx=10, pady=10)
progress = ttk.Progressbar(window, orient = HORIZONTAL, length = 500, mode = 'determinate')
progress.grid(row=10, columnspan = 4, sticky=W, padx=10, pady=10)
outText = Text(window, width=50, height=20, wrap=WORD)
outText.grid(row=11, columnspan=4, padx=10)
###########################################################
#start actions.
def actions(self):
print("action")
Timer()
window.mainloop()
The problem I'm having is from main.py, I open prog2, some of the objects (Buttonshow, progress, outText) will show up in the main.py window. But CB1 and Close objects will show in prog2. If I execute prog2.py by itself, then all the objects will show correctly in prog2 window. How do I get all of prog2 objects to show in prog2?

Tkinter Button Callback Lambda Unexpected Result

I want to create multiple rows of tkinter widgets and I thought storing them in a dictionary would be a clean way to do this. I'm having trouble getting the callbacks for the buttons to work correctly though. With the code as is, the value passed to the button callback is always E and I can't see why that is. How do I pass the correct key to the callback please - i.e. A for the first row, B for the second etc?
import tkinter as tk
NUM_ROWS = 5
BOLD_FONT = ("calbri", 16, "bold")
NORMAL_FONT = ("calbri", 16, "normal")
def submit():
print("you win")
def clear(key):
print(key)
# widgets[key]["factor_field"].delete(0,"end")
# widgets[key]["factor_field"].insert(0, key)
data = {}
widgets = {}
root = tk.Tk()
# Build widgets
for i in range(NUM_ROWS):
key = chr(i + 65)
this_row = widgets[key] = {}
this_row["label"] = tk.Label(root, text=key, font=BOLD_FONT)
this_row["label"].grid(row=i, column=0, padx=5, pady=10)
this_row["factor_field"] = tk.Entry(root, width=60, font=NORMAL_FONT)
this_row["factor_field"] .grid(row=i, column=1, padx=5, pady=10)
this_row["target_node_field"] = tk.Entry(root, width=5, font=NORMAL_FONT)
this_row["target_node_field"].grid(row=i, column=2, padx=5, pady=10)
this_row["clear_button"] = tk.Button(root, text="Clear", command=lambda: clear(
key), font=BOLD_FONT).grid(row=i, column=3, padx=5, pady=10)
submit_button = tk.Button(root, text="Submit", command=submit,
font=BOLD_FONT).grid(row=NUM_ROWS + 1, column=0, padx=5, pady=10)
print(widgets)
root.mainloop()
Use this:
this_row["clear_button"] = tk.Button(root, text="Clear",
command=lambda x=key: clear(x),
font=BOLD_FONT)
this_row["clear_button"].grid(row=i, column=3, padx=5, pady=10)
In your current code, the value for the key variable is fixed at E after the for loop has completed. As a result, your existing lambda function will always call clear('E').

What can I do to make the frame without widgets?

What I want the frame to do is that when I click on the 'clear' button, the frame is cleaned but it does not and when I enter a string that is not valid and then a valid one, it shows traces of the past and past action. I already tried changing the Label.grid () by a Label.pack (), but it is worse since the 'animation' looks like a stack without removing any element when the 'clear' button is pressed
This is basically what would make it change
from tkinter import *
import tkinter.ttk as ttk
def clear():
area.delete(0,END)
frame.config(bd=1, relief=SUNKEN)
frame.update()
status = Label(frame)
status.grid(row=0, column=0, sticky=NSEW)
def statusVal(value):
if not value == 0:
status = Label(frame, background="#ff4242", fg="#262626", text="Cadena invalida", anchor="center")
status.grid(row=0, column=0)
frame.config(bd=1, relief=SUNKEN, background="#ff4242")
frame.update()
else:
status = Label(frame, background="#56ed42", fg="#262626", text="Cadena valida", anchor="center")
status.grid(row=0, column=0)
frame.config(bd=1, relief=SUNKEN, background="#56ed42")
frame.update()
#Test
def validation():
capture = area.get()
if capture == '1':
return statusVal(0)
else:
return statusVal(1)
root = Tk()
root.geometry("300x150+300+300")
area = Entry(root)
area.grid(row=1, column=0, columnspan=2, sticky=E+W+S+N, padx=5)
frame = Frame(root, bd=1, relief=SUNKEN)
frame.grid(row=2, column=0, padx=5, pady=5, columnspan=2, sticky=W+E+S+N)
frame.columnconfigure(0,weight=5)
frame.rowconfigure(0,weight=5)
abtn = Button(root, text="Validate", command=validation)
abtn.grid(row=1, column=3)
cbtn = Button(root, text="Clear", command=clear)
cbtn.grid(row=2, column=3, pady=5)
root.mainloop()
See if this works better. The main change was to have the status Label always exist and hide or unhide it as desired — instead of creating a new one every time the validation() function was called. I also removed the code that was explicitly updating the frame which isn't necessary.
from tkinter import *
import tkinter.ttk as ttk
def clear():
area.delete(0,END)
status.grid_remove() # Hide. but remember grid options.
def statusVal(value):
if not value == 0:
status.config(background="#ff4242", fg="#262626", text="Cadena invalida",
anchor="center")
status.grid() # Unhide
else:
status.config(background="#56ed42", fg="#262626", text="Cadena valida",
anchor="center")
status.grid() # Unhide
#Test
def validation():
capture = area.get()
if capture == '1':
statusVal(0)
else:
statusVal(1)
# Main
root = Tk()
root.geometry("300x150+300+300")
area = Entry(root)
area.grid(row=1, column=0, columnspan=2, sticky=E+W+S+N, padx=5)
frame = Frame(root, bd=1, relief=SUNKEN)
frame.grid(row=2, column=0, padx=5, pady=5, columnspan=2, sticky=W+E+S+N)
frame.columnconfigure(0,weight=5)
frame.rowconfigure(0,weight=5)
# Initialize status Label.
status = Label(frame, anchor="center")
status.grid(row=0, column=0)
status.grid_remove() # Hide it.
abtn = Button(root, text="Validate", command=validation)
abtn.grid(row=1, column=3)
cbtn = Button(root, text="Clear", command=clear)
cbtn.grid(row=2, column=3, pady=5)
root.mainloop()

Dynamically fit tkinter window to its content

I have a Toplevel Window with one grid row containing a Label, Entry and a "+" Button (window on startup)
When I hit the Add-Button a new row with the same content is generated. But the problem is, that the window doesn't resize and fit to its new contents. Should look like this resized window.
The code is below:
def process_map():
numbers = {0:'\u2080', 1:'\u2081', 2:'\u2082', 3:'\u2083', 4:'\u2084', 5:'\u2085', 6:'\u2086', 7:'\u2087', 8:'\u2088', 9:'\u2089'}
button_pos = tk.IntVar(0)
ENTRIES = {}
def add_button():
if button_pos.get() >= 10:
index = numbers[button_pos.get()//10] + numbers[button_pos.get()%10]
else:
index = numbers[button_pos.get()]
lb = tk.Label(top_root, text='\u03C6'+index)
lb.grid(row=button_pos.get(), column=0, sticky='NWES')
entry = tk.Entry(top_root, width=4, relief='sunken', bd=2)
entry.grid(row=button_pos.get(), column=1, sticky='WE', padx=5, pady=5)
ENTRIES.update({button_pos.get():entry})
bt.grid(row=button_pos.get(), column=2, sticky='WE', padx=5, pady=5)
bt_close.grid(row=button_pos.get()+1, column=1, padx=5, pady=5)
bt_start.grid(row=button_pos.get()+1, column=0, padx=5, pady=5)
button_pos.set(button_pos.get()+1)
center(top_root)
top_root = tk.Toplevel(root)
top_root.title('Select \u03C6')
lb = tk.Label(top_root, text='\u03C6\u2081', height=1)
lb.grid(row=0, column=0, sticky='NWES')
entry = tk.Entry(top_root, width=4, relief='sunken', bd=2)
entry.grid(row=0, column=1, sticky='WE', padx=5, pady=5)
button_pos.set(button_pos.get()+2)
ENTRIES.update({button_pos.get():entry})
bt = tk.Button(top_root, text='+', command=add_button,)
bt.grid(row=0, column=2, sticky='WE', padx=5, pady=5)
bt_close = tk.Button(top_root, text='Cancel', width=15, command=top_root.destroy)
bt_close.grid(row=button_pos.get()+1, column=1, padx=5, pady=5)
bt_start = tk.Button(top_root, text='Start', width=15)
bt_start.grid(row=button_pos.get()+1, column=0, padx=5, pady=5)
center(top_root)
top_root.mainloop()

How can I prevent Toplevel() from opening two additional windows?

I have a program that uses Tkinter and I'm trying to assign a command to a button in my root window that opens one additional window. I'm using Toplevel(), but whenever I click the button I've assigned the command to, two windows open, one with my root window's name and one with the name of the additional window I've assigned.
I've tried using .withdraw and .destroy, to hide or remove this extra root window, but nothing seems to be working.
Here is my code:
import Tkinter
from Tkinter import *
root = Tk()
root.wm_title("VACS")
# # Top label # #
SetParameters = Label(text="Set Parameters", width=110, relief=RIDGE)
SetParameters.grid(row=1, column=0, columnspan=7, padx=5, pady=5)
# # Spatial freq settings # #
SpatialFreq = Label(text="Spatial Frequency", width=15, relief=RIDGE)
SpatialFreq.grid(row=3, column=0, padx=5, pady=5)
From1 = Label(text="from")
From1.grid(row=3, column=1, padx=5, pady=5)
Select1 = Spinbox(from_=0, to=10, width=25)
Select1.grid(row=3, column=2, padx=5, pady=5)
To1 = Label(text="to")
To1.grid(row=3, column=3, padx=5, pady=5)
Select2 = Spinbox(from_=0, to=10, width=25)
Select2.grid(row=3, column=4, padx=5, pady=5)
Steps = Label(text="in steps of")
Steps.grid(row=3, column=5, padx=5, pady=5)
Select3 = Spinbox(from_=0, to=10, width=25)
Select3.grid(row=3, column=6, padx=5, pady=5)
# # Contrast settings # #
Contrast = Label(text="Contrast", width=15, relief=RIDGE)
Contrast.grid(row=5, column=0, padx=5, pady=5)
From2 = Label(text="from")
From2.grid(row=5, column=1, padx=5, pady=5)
Select4 = Spinbox(from_=0, to=10, width=25)
Select4.grid(row=5, column=2, padx=5, pady=5)
To2 = Label(text="to")
To2.grid(row=5, column=3, padx=5, pady=5)
Select5 = Spinbox(from_=0, to=10, width=25)
Select5.grid(row=5, column=4, padx=5, pady=5)
Steps2 = Label(text="in steps of")
Steps2.grid(row=5, column=5, padx=5, pady=5)
Select6 = Spinbox(from_=0, to=10, width=25)
Select6.grid(row=5, column=6, padx=5, pady=5)
# # Test button # #
Test = Button(text="Begin Test", width=25, command=Top)
Test.grid(row=6, column=0, columnspan=7, pady=5)
# # Directory input window # #
def Top():
Toplevel()
Toplevel().wm_title("Directory")
root.mainloop()
If you click "Begin Test" in the root window, two extras pop up. I only want the one that says "Directory."
Any ideas?
You're creating two, since Toplevel() is the constructor call:
Toplevel()
Toplevel().wm_title("Directory")
Instead, create one and save it:
top = Toplevel()
top.wm_title("Directory")

Categories

Resources