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.
Related
Trying to make an tkinter atm gui, in the gui I made it so you can create new accounts with a set balance. I also wanted to make it so you can delete the last previous account you created but ran into an error. I stored all created accounts in a list and to delete them I tried to use the grid_forget method to delete the account in the -1 index but the program says it doesn't have an attribute called grid_forget, please help and thank you.
code:
import tkinter as tk
from tkinter import messagebox as mb
class BankAccount(tk.Tk):
def __init__(self, frame_title):
super().__init__()
self.title(frame_title)
self.geometry("350x370")
self.acc_list = []
#main window buttons
self.addAcc_button = tk.Button(self, text="Add Account", width=50, height=3, command=self.addAcc_window)
self.addAcc_button.grid()
self.removeAcc_button = tk.Button(self, text="Clear accounts", width=50, height=3, command=self.removeAcc)
self.removeAcc_button.grid()
self.deposit_button = tk.Button(self, text="Deposit", width=50, height=3)
self.deposit_button.grid()
self.withdrawal_button = tk.Button(self, text="Withdraw", width=50, height=3)
self.withdrawal_button.grid()
#main window label
self.accounts_label = tk.Label(self, text="Accounts: ", justify="center")
self.accounts_label.grid(pady=10)
#create second window when add acc* button is pressed + done button function/command
def addAcc_window(self):
self.AAW = tk.Toplevel(self)
self.accName_label = tk.Label(self.AAW, text="Enter Account Name:")
self.accName_label.grid()
self.accName_entry = tk.Entry(self.AAW)
self.accName_entry.grid()
self.AAW_done_button = tk.Button(self.AAW, text="Done", command=self.AAW_Done_button)
self.AAW_done_button.grid(pady=20)
def AAW_Done_button(self):
if len(self.accName_entry.get()) == 0:
mb.showerror("Blank entry", "Field cannot be blank")
else:
self.add_accLabel = tk.Label(self, text="Account " + self.accName_entry.get() + ": Balance($0)")
self.add_accLabel.grid()
self.acc_list.append(self.accName_entry.get())
self.AAW.destroy()
#create third window when remove acc* button is pressed
def removeAcc(self):
self.acc_list[-1].grid_forget()
root = BankAccount("ATM")
root.mainloop()
In your code, self.acc_list contains the name of the accounts, so they are all strings which does not have grid_forget() function.
For your case, you need to add two things into self.acc_list for each account:
the account name
the label showing account name and balance
def AAW_Done_button(self):
...
self.acc_list.append([self.accName_entry.get(), self.add_accLabel])
...
Then you can delete the last account inside removeAcc() as below:
def removeAcc(self):
if self.acc_list:
name, label = self.acc_list.pop()
label.grid_forget() # or better call label.destroy()
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.
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()
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.
I am creating a ten question multiple choice quiz in Tkinter / Python. Essentially in the parent window there are 13 buttons - help button, user details, questions 1-10 and an 'End' button. Each button opens up a new window with the question, the options as checkbuttons and radiobuttons and an 'Enter' button which links to a piece of code that will calculate the correct answer and add 1 to the score if condition is true. Once the user has selected the answer and pressed 'Enter' the button will be disabled. However, once the user exits this window they are able to re answer the same question which will obviously result in multiple points being added to the global variable score. How do I disable the question button/window once the user has answered the question? And how do I make the 'Reveal Score' button only activated when all questions have been answered?
I have used a class to define each button and individual classes thereafter for each button so I am not sure if this will cause issues (I am new to Object Orientated). Thanks
I AM AWARE THAT INDENTATION IS NOT CORRECT, IHAD TO FORMAT IT FOR THIS WEBSITE
from Tkinter import * #Copied from online examples
import tkMessageBox #Copied from online examples
import Tkinter, Tkconstants, tkFileDialog #Copied from online examples
import Tkinter as tk #Copied from online examples
class Example(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
self.question_1_window = None
self.question_1 = tk.Button(self, text="1", foreground="blue", command=self.show_question_1)
self.question_1.pack(side="left")
def show_question_1(self):
'''show the question window; create it if it doesn't exist'''
if self.question_1_window is None or not self.question_1_window.winfo_exists():
self.question_1_window = Question_1_Window(self)
else:
self.question_1_window.flash()
class Question_1_Window(tk.Toplevel):
'''A simple instruction window'''
def __init__(self, parent):
tk.Toplevel.__init__(self, parent)
self.text = tk.Label(self, width=75, height=4, text = "1) Do you have the time to do at least twenty minutes of prefect duty each week?")
self.text.pack(side="top", fill="both", expand=True)
question_1_Var = IntVar() #creating a variable to be assigned to the radiobutton
Yes_1 = Radiobutton(self, text = "Yes", variable = question_1_Var, value=1, height=5, width = 20)
Yes_1.pack() #creating 'yes' option
#Here we are assigning values to each option which will be used in the validation
No_1 = Radiobutton(self, text = "No", variable = question_1_Var, value=2, height=5, width = 20)
No_1.pack() #creating 'no' option
def calculate_score_1():
Enter_1.config(state="disabled")
if (question_1_Var.get() == 1) and not (question_1_Var.get() == 2):
print("calculate score has worked") #test lines
parent.score_per_question[1] = 1
else:
print("not worked") #testlines
Enter_1 = Button(self, text= "Enter", width=10, command = calculate_score_1)
Enter_1.pack()
def flash(self):
'''make the window visible, and make it flash temporarily'''
# make sure the window is visible, in case it got hidden
self.lift()
self.deiconify()
# blink the colors
self.after(100, lambda: self.text.configure(bg="black", fg="white"))
self.after(500, lambda: self.text.configure(bg="white", fg="black"))
if __name__ == "__main__":
root = tk.Tk()
root.geometry("800x500") #defining the size of the root
root.title("Prefect Quiz") #defining root title
Example(root).pack(side="top", fill="both", expand=True)
root.mainloop()
If it creates a new window after than you can destroy it.
window.destroy()
"window" change depending on what you call your tkinter. TK
window = tkinter. TK
Whatever is before the = is what you replace "window" with.
hope that helped:)