Python's tkinter smart entry password - python

I want to create a password entry.
One easy solution is:
password = Entry(root, font="Verdana 22")
password.config(show="*");
but the problem is that to avoid typos, I want to show the item clicked to be visible only for a few seconds, while everything else is hidden. After a few seconds everything is hidden.

It's not easy to do exactly what you want with Tkinter, but here's something close: when you press a key it displays the whole contents of the Entry, but after one second the text is hidden again.
I developed this on Python 2; to use it on Python 3 change Tkinter to tkinter.
import Tkinter as tk
class PasswordTest(object):
''' Password Entry Demo '''
def __init__(self):
root = tk.Tk()
root.title("Password Entry Demo")
self.entry = e = tk.Entry(root)
e.pack()
e.bind("<Key>", self.entry_cb)
b = tk.Button(root, text="show", command=self.button_cb)
b.pack()
root.mainloop()
def entry_cb(self, event):
#print(`event.char`, event.keycode, event.keysym )
self.entry.config(show='')
#Hide text after 1000 milliseconds
self.entry.after(1000, lambda: self.entry.config(show='*'))
def button_cb(self):
print('Contents:', repr(self.entry.get()))
PasswordTest()
It would be tricky to only display the last char entered. You'd have to modify the displayed string manually while maintaining the real password string in a separate variable and that's a bit fiddly because the user can move the insertion point cursor at any time.
On a final note, I really don't recommend doing anything like this. Keep passwords hidden at all times! If you want to reduce the chance of typos in newly-chosen passwords, the usual practice is to make the user enter the password twice.

This a simple trick to visible the password with a checkbutton.
When it is checked the password will be visible
from Tkinter import *
from tkinter import ttk
def show_hide_psd():
if(check_var.get()):
entry_psw.config(show="")
else:
entry_psw.config(show="*")
window = Tk()
window.wm_title("Password")
window.geometry("300x100+30+30")
window.resizable(0,0)
entry_psw = Entry(window, width=30, show="*", bd=3)
entry_psw.place(x = 5, y = 25)
check_var = IntVar()
check_show_psw = Checkbutton(window, text = "Show", variable = check_var, \
onvalue = 1, offvalue = 0, height=2, \
width = 5, command = show_hide_psd)
check_show_psw.place(x = 5, y = 50)
window.mainloop()

Related

Tkinter how to lock Text widget by checking checkbox?

I am new to programming and Tkinter. I want to DISABLED textbox when checkbox is pressed and open it NORMAL when box is not ticked. Here is my code:
from tkinter import *
root = Tk()
def lock_fields():
if check == True:
data.configure(state=DISABLED)
if check == False:
data.configure(state=NORMAL)
check = BooleanVar()
open_for_edit = Checkbutton(root, text="check the box for editing", variable=check,
onvalue=True, offvalue=False, command=lambda: lock_fields())
open_for_edit.pack()
check = check.get()
data = Text(root)
data.insert(END, "I would like to be able to edit this text only when checkbox is checked.")
data.pack()
root.mainloop()
It seems that for some reason the check-variable is always False when it enters to lock_fields function. I tried passing check argument to the method.
You're pretty close, only thing is that the check.get() line must be in the function. Also you don't need the lambda. Try this:
from tkinter import *
root = Tk()
def lock_fields():
if check.get():
data.configure(state=DISABLED)
else:
data.configure(state=NORMAL)
check = BooleanVar()
open_for_edit = Checkbutton(root, text="check the box for editing", variable=check, onvalue=True, offvalue=False, command=lock_fields)
open_for_edit.pack()
data = Text(root)
data.insert(END, "I would like to be able to edit this text only when checkbox is checked.")
data.pack()
root.mainloop()

How to get the entry text and display in another entry?

I just want that when I type my name inside the entry box then appears in another entry with some add text. The idea is type in the entry below and after that it showed in the big entry.I was looking for this solution, but just found place in Label. I don't want in Label. The window is more big, must drag to show the entry. There's is a picture that i use in this script:
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
cat = Entry(root)
cat.place(x=48, y=25, width= 350, height=140)
user = Entry(root)
user.place(x=75, y=550)
btn = Button(root, text='START')
btn.place(x=220, y=410)
root.mainloop()
#
Ok, It works the way you told me,thank you!
But now i'm facing another problem.
The problem is when i insert the function of the game in the second window. I tested in one window and it works, but when i place the function in the second window gives an error when i press the "Start" button:
'''user_try = int(txt.get())
NameError: name 'txt' is not defined'''
When i press reset button gives another error:
'''user_try = int(txt.get())
NameError: name 'txt' is not defined'''
So i know that is missing definition, but i don't know how to make a reference for this command that it's in the second window. Like i said running with just one window the program works.
Maybe i should make using class, i don't know, but i wish to make this way that i started. However if there's no other way to do as i'm doing, let's go.
I just simplify the script here, actualy the main script is more bigger, so my idea is when open the program, there is a window and the user read the instructions about the game and proceed open the second window. The window have pictures and some hidden buttons in the next picture, so there will be an interactivity with the environment.
The guess number is just the beggining. After that there will be new challeges.
I'm very excited doing this, but i'm stuck in this point. The part one i finished, the pictures, the hidden buttons it's exacly the way i want, but the challenge stops here in this problem.
from tkinter import *
from PIL import Image, ImageTk, ImageSequence
import random
from tkinter import messagebox
pc = random.randint(1,10)
def reset():
global pc
pc = random.randint(1,10)
cat['text'] = 'Ok! Lets Try Again!'
def openwin2():
win1.withdraw()
win2 = Toplevel()
win2.geometry('350x300+180+100')
win2.title('second window')
txt = Entry(win2)
txt.place(x=10,y=10)
cat = Label(win2,wraplength=300)
cat.place(x=10,y=50)
cat.config(text='Hi! I Am thinking a number between 1 and 10.')
btn = Button(win2,text='start',command=check)
btn.place(x=30, y=150)
btn2 = Button(win2, text='reset', command=reset)
btn2.place(x=110,y=150)
win2.mainloop()
def check():
user_try = int(txt.get())
if user_try < pc:
msg = 'Hmmmm... the number, which I thought of, is greater than this.'
elif user_try > pc:
msg = 'How about trying a smaller number ?!'
elif user_try == pc:
msg = 'Well Done! You guessed! It was %s the number!' % user_try
else:
msg = 'Something Went Wrong...'
cat['text'] = msg
win1 = Tk()
win1.title('First Window')
win1.geometry('350x300')
user = Label(win1,text='first window')
user.place(x=10,y=10)
btn1 = Button(win1,text='Open Window 2', command=openwin2)
btn1.place(x=10,y=50)
win1.mainloop()
There are multiple ways to do this in tkinter, here's a rework of your code using StringVar objects set to the textvariable properties of your Entry objects:
import tkinter as tk
def doit():
out_string.set("Hello " + in_string.get())
root = tk.Tk()
in_string = tk.StringVar()
out_string = tk.StringVar()
cat = tk.Entry(root, textvariable=in_string)
cat.place(x=20, y=25, width=100)
user = tk.Entry(root, textvariable=out_string)
user.place(x=20, y=75)
btn = tk.Button(root, text='START', command=doit)
btn.place(x=20, y=150)
root.mainloop()
Per #Mike-SMT, here's a different approach using Entry.get() and Entry.insert(). It augments the text when the user clicks the button:
import tkinter as tk
def doit():
user.insert(tk.END, cat.get())
root = tk.Tk()
cat = tk.Entry(root)
cat.place(x=20, y=25, width=100)
user = tk.Entry(root)
user.place(x=20, y=75)
user.insert(0, "Hello ")
btn = tk.Button(root, text='START', command=doit)
btn.place(x=20, y=150)
root.mainloop()
However, you'll see that subsequent button clicks keep appending the text. When working with Entry.insert(), you need to work with Entry.delete() and/or other Entry methods to properly manipulate the text.

Python: Using Tkinter radio-buttons to add/remove fields from GUI

I'm currently working on a GUI-based (Tkinter) project used to reduce matrices, just for practice.
Before I dive into the actual math stuff, I'm working on a basic window to ask the user for information to format their matrix.
In one field, I have radio-buttons - one is "Fraction", the other is "Decimal" - they can choose either for their output format. What I want is, if the user chooses "Decimal", another Entry field will appear below so that they can enter the number of decimals to round to, and if they choose "Fraction", the field won't appear.
I've searched around a bit on Stack Overflow, and saw a bit about using "raise()" and "lower()" methods, but it's not working right now. If you guys can give any input, that would be great. General feedback about the GUI is also appreciated - I learned GUIs in Python in school a while back, so if the format is bad, let me know!
Thanks in advance!
Edit: I'm running Python 3.4.
import tkinter
class Reducer:
'''
Takes user input of a matrix and row-reduces it to RREF.
GUI-Based interface that asks the user for the # of rows and columns, as well as output formatting.
The program can output as a fraction or a decimal with a specified number of decimals.
'''
def __init__(self):
'''
Initializes the GUI interface that asks the user for input.
No parameters or returns.
'''
self.main_window = tkinter.Tk()
#Initalize frames.
self.info_frame = tkinter.Frame()
self.size_frame = tkinter.Frame()
self.format_frame = tkinter.Frame()
self.digit_frame = tkinter.Frame()
self.button_frame = tkinter.Frame()
#Object for the information frame.
self.info_label = tkinter.Label(self.info_frame, text="Enter the number of rows and columns, your preferred output format,"
" and the number of trailing decimals if applicable.", justify="left",
wraplength=275).pack()
#Objects for the size frame - the matrix's rows/columns are set here.
self.row_label = tkinter.Label(self.size_frame, text="Rows:").pack(side="left")
self.row = tkinter.Entry(self.size_frame, width=3).pack(side="left")
self.col_label = tkinter.Label(self.size_frame, text="Columns:").pack(side="left")
self.col = tkinter.Entry(self.size_frame, width=3).pack(side="left")
#Objects for the digit frame
self.digit_label = tkinter.Label(self.digit_frame, text="Digits:")
self.digit = tkinter.Entry(self.digit_frame, width=3)
self.digit_label.pack(side="left")
self.digit.pack(side="left")
#Objects for the format frame - the output formatting is specified here.
self.output_var = tkinter.IntVar()
self.output_var.set(0)
self.fraction = tkinter.Radiobutton(self.format_frame, text="Fraction", variable=self.output_var, value=0,
command=self.hide_digits()).pack(side="left")
self.decimal = tkinter.Radiobutton(self.format_frame, text="Decimal", variable=self.output_var, value=1,
command=self.show_digits()).pack(side="left")
#Object for the bottom frame
self.button = tkinter.Button(self.button_frame, text="Next", command=self.reduce).pack()
#Pack frames.
self.info_frame.pack(anchor="nw")
self.size_frame.pack(anchor="nw")
self.format_frame.pack(anchor="nw")
self.digit_frame.pack(anchor="nw")
self.button_frame.pack(anchor="nw")
tkinter.mainloop()
def show_digits(self):
self.digit_label.lift(self.col)
self.digit.lift(self.col)
def hide_digits(self):
self.digit_label.lower(self.col)
self.digit.lower(self.col)
def reduce(self):
pass
reducer = Reducer()
Here is an example of what I mentioned earlier! this makes a new entry field (one at any time).
import tkinter as tk
root = tk.Tk()
global num
num = 0
def create():
global entry
global num
if num == 0:
num = 1
entry = tk.Entry()
entry.pack()
def destroy():
global entry
global num
if num == 1:
num = 0
entry.destroy()
button1 = tk.Button(text = 'create entry', command = create)
button1.pack()
button2 = tk.Button(text = 'destroy entry', command = destroy)
button2.pack()
root.mainloop()
you could also disable and enable the entry field like this, but then the widget is always there so it's up to you:
import tkinter as tk
root = tk.Tk()
global entry
entry = tk.Entry(state = 'disabled')
entry.pack()
def create():
global entry
entry.config(state = 'normal')
def destroy():
global entry
entry.config(state = 'disabled')
button1 = tk.Button(text = 'create entry', command = create)
button1.pack()
button2 = tk.Button(text = 'destroy entry', command = destroy)
button2.pack()
root.mainloop()
hope that helps a bit.

Why Won't My Button Be Displayed??

#Last one Looses (II)
from tkinter import *
from tkinter import ttk
root = Tk()
#window
root.title("Last one Looses Mark II")
#Counters Entry
counters = StringVar()
countersL = Label(root, text = "How many counters do you want to play with (10-50)")
countersL.pack(side = LEFT)
countersE = Entry(root, textvariable = counters, bd = 5)
countersE.pack(side = RIGHT)
#Function to process this
def countersinput():
no_counters = int(input(counters.get()))
no_counters = int(input(counters.get()))
#Submit Button
countersB = Button(root, text = "Submit", command = countersinput)
countersB.pack(side = BOTTOM)
#Making sure the counters are between 10-50
while no_counters > 50 or no_counters < 10:
Error = Message(root, text="You need to pick between 10 and 50 counters...")
Error.pack()
counters = StringVar()
countersL = Label(root, text = "How many counters do you want to play with (10-50)")
countersL.pack(side = LEFT)
countersE = Entry(root, textvariable = counters, bd = 5)
countersE.pack(side = RIGHT)
def countersinput():
no_counters = int(input(counters.get()))
countersB = Button(root, text = "Submit", command = countersinput)
countersB.pack(side = BOTTOM)
#Sucess Message
Sucess = Message(root, text=("You are playing with",no_counters,"counters"))
root.mainloop()
Whenever I run it in IDLE the tkinter window does not come up and when I run it into the command line (python one...) it displays the window but with no "submit" button.
I'm really confused please help!
First off, do you realize that your GUI program is asking for input from the command line, and that you're doing that before creating the submit button? That's the reason why the submit button is not showing up. If you're writing a GUI program, you should not be trying to read input from the command line.
If you enter a number between 10 and 50 from the terminal, your code should display a window. However, if you enter a number outside that range, nothing will ever show because of the while no_counters ... loop. That loop will run infinitely, preventing any other interaction with the GUI, and preventing any other widgets from showing up.

Get the same input multiple times in python tkinter?

I am making a program to get multiple user names and store them in a XML file. The XML part works fine, but I am having trouble with the GUI. I want to be able to ask the user how many users he wants to input, then repeat an Entry that number of times. How can I do that, while maintaining a quit function? I tried:
def quitter():
exit()
quit()
quitterButton = Button(master, text="Quit", command=quitter)
mainCanvas.create_window(50, 330, window=quitterButton, tag="quitter")
num = int(raw_input("How many users are you going to put in?"))
for x in range(0,num):
#Create User entry Variable
userEnter = StringVar()
usrVar = ""
#Create enter box:
userEntryBox = Entry(master, textvariable = userEnter)
mainCanvas.create_window(250, 300, window=userEntryBox, tag="UserEnterA")
def gotInput(self):
usrVar = userEnter.get();
mainCanvas.create_text(250, 330, text="User Inputted: " + usrVar, tags="0")
mainCanvas.delete("UserEnterA")
#Bind entry box
userEntryBox.bind('<Key-Return>', gotInput)
userEntryBox.wait_window(userEntryBox)
#Create a new user element
newUsr= ET.Element('Member')
#Add element to the Root
root.append(newUsr)
#Make a sub element Name, set name
usrName = ET.SubElement(newUsr, 'Name')
usrName.text = usrVar;
...
tree.write('./output.xml')
What is the best way to go around it? I won't know the number of inputs, and I want the quit button to work at all times .
Behavior of your program is a bit unclear for me, but I try to help.
First solution: show tkinter askstring dialog num times. You can break for loop if user press Cancel button. It's not exactly what you want, but it's very easy to implement:
from tkinter import *
import tkinter.simpledialog as simpledialog
def add_users():
n = simpledialog.askinteger('', 'How many users are you going to put in?', initialvalue=1, minvalue=1, maxvalue=10)
if not n: # 'Cancel'
return
for i in range(n):
user = simpledialog.askstring('', 'User #%s from #%s' % (i+1, n))
if user is None: # 'Cancel'
return
# Do something useful
print(user)
root = Tk()
Button(root, text='Add users', command=add_users).pack(padx=50, pady=50)
Button(root, text='Quit', command=root.destroy).pack(pady=30)
root.mainloop()
Second (if you want to put entry and all new names to window with quit button):
from tkinter import *
import tkinter.simpledialog as simpledialog
class YourApp():
def __init__(self):
self.root = Tk()
Button(self.root, text='Quit', command=self.root.destroy).pack(pady=20)
self.ask_button = Button(self.root, text='Add users', command=self.add_users)
self.ask_button.pack(padx=50, pady=50)
self.root.mainloop()
def add_users(self):
self.users_count = 0
self.user_name = StringVar()
self.frame = Frame(self.root)
self.frame.pack()
self.users_count = simpledialog.askinteger('', 'How many users are you going to put in?', initialvalue=1, minvalue=1, maxvalue=10)
self.user_entry = Entry(self.frame, textvariable=self.user_name)
self.user_entry.pack(pady=10)
self.user_entry.bind('<Key-Return>', self.on_new_user)
self.user_entry.focus_set()
def on_new_user(self, event):
# your code
print(self.user_name.get())
Label(self.frame, text='User Inputted: %s' % self.user_name.get()).pack()
self.users_count -= 1
if not self.users_count:
self.user_entry.destroy()
self.user_name.set('')
YourApp()
There are three geometry managers in Tkinter: place (it's very similar to canvas in your case), grid and pack.
Canvas usually used for drawing pictures or graphs.

Categories

Resources