How to view and unview a password in tkinter - python

I have a program (below) that creates an entry box that shows only '*' when you type in it and it creates a button next to the text box. I want the button to show what has been typed in the entry box while it is being pressed. I have tried to use <Button-1> and <ButtonRelease-1> but to no avail.
import tkinter as tk
def myFunc() :
#Something#
pass
root = tk.Tk()
root.title('Password')
password = tk.Entry(root, show = '*')
password.grid(row = 0, column = 1)
password_label = tk.Label(text = 'Password:')
password_label.grid(row = 0, column = 0)
button = tk.Button(text = '.', command = myFunc)
button.grid(row = 0, column = 2)

Try this:
import tkinter as tk
def show_stars(event):
password.config(show="*")
def show_chars(event):
password.config(show="")
root = tk.Tk()
root.title("Password")
password = tk.Entry(root, show="*")
password.grid(row=0, column=1)
password_label = tk.Label(text="Password:")
password_label.grid(row = 0, column=0)
button = tk.Button(text="Show password")
button.grid(row=0, column=2)
button.bind("<ButtonPress-1>", show_chars)
button.bind("<ButtonRelease-1>", show_stars)
Using the bindings that #BryanOakley suggested

Only if button is pressed it changes the text from * to the text entered.
import tkinter as tk
def myFunc():
#Something#
if password.cget("show")=="*":
password.configure(show="")
elif password.cget("show") =="":
password.configure(show="*")
root = tk.Tk()
root.title('Password')
password = tk.Entry(root, show = '*')
p = password
password.grid(row = 0, column = 1)
password_label = tk.Label(text = 'Password:')
password_label.grid(row = 0, column = 0)
button = tk.Button(text = '.', command = myFunc)
button.grid(row = 0, column = 2)
root.mainloop()

Related

Text Field that appears if user choose Yes in the combo box in tkinter

I want to add a text field and input text if the user choose "Yes" in the combo box; other wise nothing will be added. Tried this but didn't work
Combo = ttk.Combobox(window, values = vlist)
Combo.set("Pick an Option")
Combo.pack()
if (Combo.get()=="Yes"):
tkinter.Label(window, text="Number of Workers", bg = "white",fg = "black", font=("Times",13,"bold")).place(x=155,y=240)
inputtxt3 = Text(window, height = 1, width = 25, bg = "light yellow")
inputtxt3.pack()
inputtxt3.place(x=325, y=238)
Does this help you?
from tkinter import Tk, StringVar
from tkinter.ttk import Label, Combobox, Button
root = Tk()
def check(): # For checking the value of ComboBox
combo_value = var.get()
if combo_value == "Yes":
lbl.config(text="You selected 'Yes'")
else:
lbl.config(text="You selected 'No'")
var = StringVar() # To store the value of the Combobox
Combo = Combobox(root, values=["Yes", "No"], textvariable=var)
Combo.pack(pady=20)
btn = Button(root, text="Confirm", command=check)
btn.pack(pady=20)
lbl = Label(root)
lbl.pack(pady=20)
root.mainloop()

tkinter throws error using a variable for button name to set state

I want to pass a button name to tkinter as a variable. This method works for Text fields, but not for buttons in my code.
I am building a gui app and I want to have a generic clear function that zaps a text entry field and resets a button from NORMAL to DiSABLED.
There are multiple buttons and fields, hence the desire to make this generic.
For the code I have, the buttons are present with the exception of clear all.
I am setting the variable w_button to the specific name of the (existing) button based on what is passed to the function.
def switch_clear(elem_type):
if elem_type == 'scn':
w_button = 'b_clear_scn'
clear_field = 'scn_file_entry'
print ('scenario')
elif elem_type == 'sol2':
w_button = 'b_clear_sol2'
clear_field = 'sol2_file_entry'
print ('sol2')
elif elem_type == 'mdl':
w_button = 'b_clear_mdlList'
clear_field = 'mdlList_file_entry'
print ('mdl')
elif elem_type == 'all':
print ('clear all TBD')
return()
if w_button["state"] == NORMAL:
clear_field.delete(0, END)
w_button["state"] = DISABLED
return()
Here's what happens:
C:\utils>my_frame3.py
scenario
Traceback (most recent call last):
File "C:\utils\my_frame3.py", line 127, in <module>
b_clear_scn = Button(first_frame, text = "Clear scenario", command = switch_clear('scn'), height = 2, state=DISABLED)
File "C:\utils\my_frame3.py", line 100, in switch_clear
if w_button["state"] == NORMAL:
TypeError: string indices must be integers
C:\utils>
I realize I could duplicate and push the clear operations into the if/elif statements, and I may have to live with that but - is it possible to reference buttons as variables? How can I do this?
Complete code as requested below. The preview is a mess despite using the code widget, but in my file lines are correctly formatted (notepad++). Tx
import os, sys
from tkinter import *
from tkinter import messagebox
from tkinter import filedialog
root2 = Tk()
root2.title('Model Processing')
root2.geometry('{}x{}'.format(512, 400))
# colors
color1 = 'light cyan'
color2 = 'gold'
color3 = 'RosyBrown1'
color4 = 'lavender'
color5 = 'linen'
bg_color = 'azure'
# number of items to process; until >1 OK is disabled; if >1 OK is enabled TBD
l_to_do = [] # items to process; scn, sol2, modelList, installed models
# functions/commands
def callback():
print ('A button was clicked.')
return;
def my_exit():
result = messagebox.askquestion("Cancel Model Processing", "Are you sure?", icon='warning')
if result == 'yes':
root2.quit()
else: # user changed mind
pass
def choose_import_file(str_ftype):
which_field = ''
which_clear_btn = ''
ftype = str_ftype
mdl_opts = {}
if ftype == 'scn':
title_msg = 'Choose a scenario file'
mdl_opts['filetypes'] = [('Supported types', ('.scn')),
('scenario files',('.scn'))]
which_field = scn_file_entry
which_clear_btn = 'b_clear_scn'
elif ftype == 'sol2':
title_msg = 'Choose a SOL2 file'
mdl_opts['filetypes'] = [('Supported types', ('.txt')),
('sol2 files',('.txt'))]
which_field = sol2_file_entry
elif ftype == 'mdllist':
title_msg = 'Choose a ModelList file'
print ('TBD: ModelList file')
file_input = filedialog.askopenfilename(title = title_msg, **mdl_opts)
if file_input == '':
print ('error or cancelled by user')
return
else:
f_inp_file = os.path.basename(file_input)
f_inp_file_base = str(file_input.split('.')[0])
f_inp_file_ext = str.lower(str(file_input.split('.')[1]))
f_inp_d_name = os.path.dirname(file_input)
print('File chosen:', f_inp_file_base)
# populate scenario file field
which_field.insert(INSERT,file_input)
which_clear_btn["state"] = NORMAL
# define appropriate clear button active
# define_clear_btn.configure(state = ACTIVE)
return
def switch_clear(elem_type):
if elem_type == 'scn':
if b_clear_scn["state"] == NORMAL:
scn_file_entry.delete(0, END)
b_clear_scn["state"] = DISABLED
elif elem_type == 'sol2':
f b_clear_sol2["state"] == NORMAL:
clear_field = 'sol2_file_entry'
b_clear_sol2["state"] = DISABLED
elif elem_type == 'mdl':
if b_clear_mdlList["state"] == NORMAL:
clear_field = 'mdlList_file_entry'
b_clear_mdlList["state"] = DISABLED
elif elem_type == 'all':
print ('clear all TBD')
return()
return()
# create all of the main containers
first_frame = Frame(root2, bg=color5, width = 512, height=90, pady=10)
second_frame = Frame(root2, bg=color5, width = 512, height=90, pady=10)
third_frame = Frame(root2, bg=color5, width=512, height=90, pady=10)
fourth_frame = Frame(root2, bg=color5, width = 512, height = 90, pady=10)
# layout all of the main containers
root2.grid_rowconfigure(3, weight=1)
root2.grid_rowconfigure(2, weight=1)
root2.grid_rowconfigure(1, weight=1)
root2.grid_columnconfigure(0, weight=1)
first_frame.grid(row=0, sticky="ew")
second_frame.grid(row=1, sticky="ew")
third_frame.grid(row=2, sticky="ew")
fourth_frame.grid(row = 3, sticky="e")
# create the widgets for the first frame
#scn_label = Label(first_frame, text = 'Scenario file')
scn_file_entry = Entry(first_frame, background=bg_color, width = 50)
b_choose_scn = Button(first_frame, text = "Choose a scenario..", command = lambda: choose_import_file('scn'), height = 2)
b_clear_scn = Button(first_frame, text = "Clear scenario", command = switch_clear('scn'), height = 2, state=DISABLED)
# layout the widgets in the first frame
#scn_label.grid(row = 0, column = 0, padx = (10,50), pady=5)
scn_file_entry.grid(row = 0, column = 1, padx = (10,10))
b_choose_scn.grid(row=0, column=0, padx = (10,10), sticky=W)
b_clear_scn.grid(row=2, column=0, padx = (10,10), sticky=W)
# second frame
# sol2_label = Label(second_frame, text = 'Sol2 file')
sol2_file_entry = Entry(second_frame, background=bg_color, width = 50)
b_choose_sol2 = Button(second_frame, text = "Choose SOL2 file..", command = lambda: choose_import_file('sol2'), height = 2)
b_clear_sol2 = Button(second_frame, text = "Clear SOL2", command = switch_clear('sol2'), height = 2, state=DISABLED)
# layout the widgets in the second frame
# sol2_label.grid(row = 0, column = 0, padx = (10,50), pady=5)
sol2_file_entry.grid(row = 0, column = 1, padx = (10,10), sticky=EW)
b_choose_sol2.grid(row=0, column=0, padx = (10,10), sticky=W)
b_clear_sol2.grid(row=2, column=0, padx = (10,10), sticky=W)
# third frame
# mdlList_label = Label(third_frame, text = 'ModelList.txt file')
mdlList_file_entry = Entry(third_frame, background=bg_color, width = 50)
b_choose_mdlList = Button(third_frame, text = "Choose ModelList.txt file..", command = callback, height = 2)
b_clear_mdlList = Button(third_frame, text = "Clear ModelList", command = callback, height = 2, state=DISABLED)
# layout the widgets in the third frame
#mdlList_label.grid(row = 0, column = 0, padx = (10,10), pady=5, sticky = 'ns')
mdlList_file_entry.grid(row = 0, column = 1, padx = (10,10), sticky=EW)
b_choose_mdlList.grid(row=0, column=0, padx = (10,10), sticky=W)
b_clear_mdlList.grid(row=2, column=0, padx = (10,10), sticky=W)
#####################################################################
# create bottom widgets
#####################################################################
clear_all = Button(fourth_frame, text='Clear All', padx = '5', command = callback, height = 2, state=DISABLED)
ok_btn = Button(fourth_frame, text='OK', padx = '5', command = callback, height = 2, state=DISABLED)
cancel_btn = Button(fourth_frame, text='Cancel', height = 2, padx = '12', command = my_exit)
#####################################################################
# layout the bottom widgets
#####################################################################
clear_all.grid(row = 0, column = 2, sticky = 'e')
ok_btn.grid(row = 0, column = 3, sticky = 'e')
cancel_btn.grid(row = 0, column = 4, sticky = 'e')
# commands/bindings
root2.mainloop()
I believe this is what you are trying to do. The below is fully commented with explanations. switch_clear becomes entirely unnecessary with this method. The buttons directly clear their corresponding entry in their command, and Entry validation takes care of the corresponding button state.
Note: I wrote all of this before you posted your full code
import tkinter as tk
root = tk.Tk()
root.geometry('400x400')
#toggle the state of buttons based on entry text length
def toggle_button(name, text):
global btn_switch
btn_switch[name]['state'] = 'normal' if len(text) else 'disabled'
return True
#to hold the buttons so they are easy to position
#just for this example
buttons = tk.Frame(root)
buttons.pack(side='top', anchor='nw')
#create a tcl wrapper for the validate command
vcmd = tk.Widget.register(root, toggle_button)
#mock-up of your entries ~ validate on key press. send widget name and full text to vcmd
scn_file_entry = tk.Entry(root, width=20)
scn_file_entry.configure(validate="key", validatecommand=(vcmd, '%W', '%P'))
scn_file_entry.pack(side='left', anchor='nw')
sol2_file_entry = tk.Entry(root, width=20)
sol2_file_entry.configure(validate="key", validatecommand=(vcmd, '%W', '%P'))
sol2_file_entry.pack(side='left', anchor='nw')
mdlList_file_entry = tk.Entry(root, width=20)
mdlList_file_entry.configure(validate="key", validatecommand=(vcmd, '%W', '%P'))
mdlList_file_entry.pack(side='left', anchor='nw')
#mock-up of your buttons ~ delete the entry text in a lambda and let entry validation handle the button state
b_clear_scn = tk.Button(buttons, text="scn", state='disabled')
b_clear_scn.configure(command=lambda: scn_file_entry.delete(0, 'end'))
b_clear_scn.pack(side='left', anchor='nw')
b_clear_sol2 = tk.Button(buttons, text="sol2", state='disabled')
b_clear_sol2.configure(command=lambda: sol2_file_entry.delete(0, 'end'))
b_clear_sol2.pack(side='left', anchor='nw')
b_clear_mdlList = tk.Button(buttons, text="mdl", state='disabled')
b_clear_mdlList.configure(command=lambda: mdlList_file_entry.delete(0, 'end'))
b_clear_mdlList.pack(side='left', anchor='nw')
#create a dictionary of 'widget name':corresponding button, for toggle_button to reference
btn_switch = {
f'{scn_file_entry}':b_clear_scn,
f'{sol2_file_entry}':b_clear_sol2,
f'{mdlList_file_entry}':b_clear_mdlList,
}
root.mainloop()

Using get() function on tkinter entry widget

I am trying to create a standard user ID/PASS login. When I use the next function to check if the entered password and name are right, I always get the "wrong values entered" message. Basically, the variables entry_1 and entry_2 are not storing the input text and I want a solution for that. Maybe any of you guys might propose a solution for that?
I have tried to assign entry_1 and entry_2 to variables but it did'nt work out.
from tkinter import *
root = Tk() # creates a window and initializes the interpreter
root.geometry("500x300")
name = Label(root, text = "Name")
password = Label(root, text = "Password")
entry_1 = Entry(root)
entry_2 = Entry(root)
name.grid(row = 0, column = 0, sticky = E) # for name to be at right use sticky = E (E means east)
entry_1.grid(row = 0, column =1)
x = "Taha"
password.grid(row = 1, column = 0)
entry_2.grid(row = 1, column =1)
y = "123"
c = Checkbutton(root, text = "Keep in logged in").grid(columnspan = 2 ) # mergers the two columns
def next():
if a == entry_1 and b == entry_2:
print ("Proceed")
else:
print("wrong values entered")
def getname():
return name
Next = Button(root, text = "Next", command=next).grid(row = 3, column = 1)
root.mainloop() # keep runing the code
I want the program to return "Proceed" once correct values are entered.
in your code you're not checking for the user input anywhere. You should use get() to return user input. I've modified your code accordingly. Now if you enter Taha as username and 123 as password, you'll get the "Proceed" message.
from tkinter import *
root = Tk() # creates a window and initializes the interpreter
root.geometry("500x300")
name = Label(root, text="Name")
password = Label(root, text="Password")
entry_1 = Entry(root)
entry_2 = Entry(root)
name.grid(row=0, column=0, sticky=E) # for name to be at right use sticky = E (E means east)
entry_1.grid(row=0, column=1)
x = "Taha"
password.grid(row=1, column=0)
entry_2.grid(row=1, column=1)
y = "123"
c = Checkbutton(root, text="Keep in logged in").grid(columnspan=2) # mergers the two columns
def next_window():
user_name = entry_1.get()
user_pass = entry_2.get()
if x == user_name and y == user_pass:
print("Proceed")
else:
print("wrong values entered")
def get_name():
return name
Next = Button(root, text="Next", command=next_window).grid(row=3, column=1)
root.mainloop()
thanks to the people who helped, with your help i could find the missing part in the code. i should have used .get() funtion in order to get the entered text back.
here is the upgraded code with some improvements.
from tkinter import *
from tkinter import messagebox
root = Tk() # creates a window and initializes the interpreter
root.geometry("500x300")
name = Label(root, text = "Name")
password = Label(root, text = "Password")
entry_1 = Entry(root)
entry_2 = Entry(root)
name.grid(row = 0, column = 0, sticky = E) # for name to be at right use sticky = E (E means east)
entry_1.grid(row = 0, column =1)
x = "Taha"
password.grid(row = 1, column = 0)
entry_2.grid(row = 1, column =1)
y = "123"
c = Checkbutton(root, text = "Keep in logged in").grid(columnspan = 2 ) # mergers the two columns
def next():
a = entry_1.get()
b = entry_2.get()
if a == "Taha" and b =="123":
messagebox.showinfo("Login", "successfuly logged in ")
root.destroy()
print ("Proceed")
else:
messagebox.showerror("Error", "wrong values entered")
print("wrong values entered")
root.destroy()
Next = Button(root, text = "Next", command=next).grid(row = 3, column = 1)
root.mainloop() # keep runing the code

Changing text of labels defined in a loop

I'm trying to make a scalable counter.
In the first window you enter how many counters you want.
In the second window there are labels and buttons used to add one to the label.
Here is my code:
from tkinter import *
root = Tk()
def newWindow():
window = Toplevel()
for i in range(int(textbox.get())):
exec("global label"+ str(i))
exec("label" + str(i) + " = Label(window, text = '0')")
exec("label" + str(i) + ".grid(row = 0, column = i)")
exec("global button"+ str(i))
exec("button" + str(i) + " = Button(window, text = 'Add', command = lambda: setText(label" + str(i) + "))")
exec("button" + str(i) + ".grid(row = 1, column = i)")
def setText(label):
label.config(text = str(int(label.cget("text")) + 1))
textbox = Entry(root)
textbox.grid(row = 0)
submitButton = Button(root, text = "Submit", command = newWindow)
submitButton.grid(row = 0, column = 1)
root.mainloop()
However this is the error I get:
name 'label_' is not defined
where _ is i.
Making them global didn't fix this either.
Help please!
If you're using exec in this way, you're doing something very wrong.
The simple solution is to add widgets to a list or dictionary. Though, in this specific case you don't need that because you're never referencing the label anywhere but in the button command.
Here's a working example:
from tkinter import *
root = Tk()
def newWindow():
global labels
window = Toplevel()
labels = {}
for i in range(int(textbox.get())):
label = Label(window, text='0')
button = Button(window, text='Add', command = lambda l=label: setText(l))
label.grid(row=0, column=i)
button.grid(row=1, column=i)
# this allows you to access any label later with something
# like labels[3].configure(...)
labels[i] = label
def setText(label):
label.config(text = str(int(label.cget("text")) + 1))
textbox = Entry(root)
textbox.grid(row = 0)
submitButton = Button(root, text = "Submit", command = newWindow)
submitButton.grid(row = 0, column = 1)
root.mainloop()
If you wanted to make use of labels, you could have your button pass in the index, and let setText get the widget from the dictionary:
def setText(i):
label = labels[i]
label.configure(...)
...
button = Button(..., command=lambda i=i: setText(i))

Python tkinter: access child widgets of a widget

I have a string 'currentMessage' and a Label to display it.
I have a Toplevel widget, which contains a Text widget to provide new value for 'currentMessage':
from tkinter import *
from tkinter import ttk
root = Tk()
mainFrame = ttk.Frame(root)
mainFrame.grid()
currentMessage = 'current Message'
ttk.Label(mainFrame, text = currentMessage).grid(padx = 10, pady = 10)
def updateCurrentMessage(popupWindow):
currentMessage = popupWindow.textBox.get(0.0, END)
def changeValues():
popup = Toplevel(mainFrame)
popup.grid()
textBox = Text(popup, width = 20, height = 5)
textBox.grid(column = 0, row = 0)
textBox.insert(END, 'new message here')
b = ttk.Button(popup, command = lambda: updateCurrentMessage(popup))
b.grid(column = 0, row = 1, padx = 5, pady = 5)
b['text'] = 'Update'
theButton = ttk.Button(mainFrame, command = changeValues, text = 'Click')
theButton.grid(padx = 10, pady = 10)
mainFrame.mainloop()
I tried to get the content of 'textBox' Text widget of the Toplevel by using this function:
def updateCurrentMessage(popupWindow):
currentMessage = popupWindow.textBox.get(0.0, END)
But I got an error
'Toplevel' object has no attribute 'textBox'
So how do I access content of the widget 'textBox', which is a child widget of 'popup' (this Toplevel widget is only created when function changeValues() is called)?
I think probably this is what you are looking for -- although I'm just guessing, because you are asking for a solution for a specific problem you think you have, however if I were you I would rethink what exactly do I want to do:
from tkinter import *
from tkinter import ttk
# Create Tk Interface root
root = Tk()
# Initialize mainFrame
mainFrame = ttk.Frame( root )
mainFrame.grid()
# Initialize label of mainframe
theLabel = ttk.Label( mainFrame, text='Current Message' )
theLabel.grid( padx=10, pady=10 )
def createPopup():
# Initialize popup window
popup = Toplevel( mainFrame )
popup.grid()
# Initialize text box of popup window
textBox = Text( popup, width=20, height=5 )
textBox.grid( column = 0, row = 0 )
textBox.insert( END, 'New Message Here' )
# Initialize button of popup window
button = ttk.Button( master = popup,
command = lambda: theLabel.config(text=textBox.get(0.0, END)),
text = 'Update')
button.grid( column=0, row=1, padx=5, pady=5 )
# Initialize button of main frame
theButton = ttk.Button( mainFrame, command=createPopup, text='Click' )
theButton.grid( padx=10, pady=10 )
# Enter event loop
mainFrame.mainloop()
There is a way indeed, like this:
def updateCurrentMessage(popupWindow):
currentMessage = popupWindow.nametowidget('textBox').get(0.0, END)
def changeValues():
popup = Toplevel(mainFrame)
popup.grid()
textBox = Text(popup, width = 20, height = 5, name = 'textBox')
textBox.grid(column = 0, row = 0)
textBox.insert(END, 'new message here')
b = ttk.Button(popup, command = lambda: updateCurrentMessage(popup))
b.grid(column = 0, row = 1, padx = 5, pady = 5)
b['text'] = 'Update'
You can choose whatever you want for the 'name'.

Categories