I am making a simple Log In Menu using Python Tkinter. The code works for logging in and all that stuff but I want to make a working create new account button or something like that. I will be doing that using lists but first I need to make sure that the Entry field pops up on clicking the create new account button, Here is the code :-
from tkinter import*
from tkinter import messagebox
class Login:
def __init__(self,root):
self.root=root
self.root.title("Login")
self.root.geometry("1199x600+100+50")
self.bg=PhotoImage(file="png.png")
self.bg_image=Label(self.root,image=self.bg).place(x=0,y=0,relwidth=1,relheight=1)
#Frame
Frame_login=Frame(self.root,bg="white")
Frame_login.place(x=150,y=150,height=340,width=500)
title=Label(Frame_login,text="Login Here",font=("Impact",35, "bold","underline"),fg="red",bg="white").place(x=160,y=30)
desc=Label(Frame_login,text="Login Area",font=("Goudy old",15, "bold","underline"),fg="purple",bg="white").place(x=80,y=100)
lbl_user=Label(Frame_login,text="Username:",font=("Goudy old",15,"underline","bold"),fg="#00ffff",bg="white").place(x=115,y=140)
self.txt_user=Entry(Frame_login,font=("times new roman", 15),bg="lightgray")
self.txt_user.place(x=115,y=170,width=350,height=35)
lbl_pass=Label(Frame_login,text="Password:",font=("Goudy old",15,"underline","bold"),fg="#00ffff",bg="white").place(x=115,y=210)
self.txt_pass=Entry(Frame_login,font=("times new roman", 15),bg="lightgray")
self.txt_pass.place(x=115,y=240,width=350,height=35)
forget_btn= Button(Frame_login,command=self.register,text="Create New Account",cursor="hand2", bg="white", fg='lime', bd=0,font=("times new roman", 12)).place(x=115,y=280)
log_btn= Button(self.root,command=self.login_function,text="Login",cursor="hand2", fg="#d77337", bg="#d77337", font=("times new roman", 20)).place(x=315,y=470,width=180,height=40)
def login_function(self):
if self.txt_pass.get()=="" or self.txt_user.get()=="":
messagebox.showerror("Error!","All fields are required", parent=self.root)
elif self.txt_user.get()!="abcd" or self.txt_pass.get()!="1234":
messagebox.showerror("Error!"," Invalid Username or Password", parent=self.root)
else:
messagebox.showinfo("Welcome!","Succesfully Logged In!")
root=Tk()
obj=Login(root)
root.mainloop()
Here is a simple example of how that might look like:
from tkinter import Tk, Frame, Button, Entry, Label
class Login(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
# data frame
self.data_frame = Frame(self)
self.data_frame.pack(pady=10)
# username:
Label(self.data_frame, text='Username:').pack()
# username entry
self.username = Entry(self.data_frame)
self.username.pack()
# password:
Label(self.data_frame, text='Password:').pack()
# password entry
self.password = Entry(self.data_frame)
self.password.pack()
# button frame
self.btn_frame = Frame(self)
self.btn_frame.pack()
# login btn
Button(self.btn_frame, text='Login', command=self.login).pack(side='left', padx=10, pady=10)
# signup button
Button(self.btn_frame, text='Sign Up', command=self.sign_up).pack(side='left', padx=10, pady=10)
def login(self):
print('login successful')
root.destroy()
def sign_up(self):
SignUp(root).pack()
self.destroy()
class SignUp(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
# data frame
self.data_frame = Frame(self)
self.data_frame.pack(pady=10)
# username:
Label(self.data_frame, text='Username:').pack()
# username entry
self.username = Entry(self.data_frame)
self.username.pack()
# password:
Label(self.data_frame, text='Password:').pack()
# password entry
self.password = Entry(self.data_frame)
self.password.pack()
# button frame
self.btn_frame = Frame(self)
self.btn_frame.pack()
# login btn
Button(self.btn_frame, text='Sign Up', command=self.sign_up).pack(side='left', padx=10, pady=10)
# signup button
Button(self.btn_frame, text='Cancel', command=self.cancel).pack(side='left', padx=10, pady=10)
def sign_up(self):
print('Signed up')
Login(root).pack()
self.destroy()
def cancel(self):
Login(root).pack()
self.destroy()
root = Tk()
Login(root).pack()
root.mainloop()
Both classes are pretty much frames and can be changed depending on which button user presses, can also add more functionality to the methods. Otherwise both classes are pretty much identical, they are almost copies just a few things like button names and method names are changed the rest is the same
Related
I'm trying to create new tabs in my navigation bar notebook by clicking on the last tab. To further complicate the task my application is written with classes. My current and less elegant solution requires an Entry with a Button to create the new tab with the title entered in the Entry widget. Does anyone know a more elegant solution to my problem?
Heres my code:
import tkinter as tk
from tkinter import ttk
class MainApp(tk.Tk):
"""Main window class"""
def __init__(self):
super(MainApp, self).__init__()
self.geometry("1000x1000")
self.main_window = tk.Frame(self)
self.main_window.pack(side="top", fill="both", expand=True)
# saving all tabs & Frames to a dictionary to be able to access them later
self.frames = {}
self.tabs = {}
# create a tab bar
self.navbar = Navbar(self.main_window)
# set the layout
self.set_layout()
def set_layout(self):
"""creates the default app layout"""
self.add_tab("Settings") # first page
self.add_tab("Case 1")
def add_tab(self, title):
"""adds a new tab with name title to the navbar"""
tab = ttk.Frame(self)
self.navbar.add(tab, text=title)
self.tabs[title] = tab
# check if Settings or Case type Tab, to create MainInput frame with correct buttons
if title.lower().find("setting") != -1:
self.frames[title] = MainInput(self, tab, self.navbar, settings=True)
else:
self.frames[title] = MainInput(self, tab, self.navbar, case=True)
self.navbar.pack(fill=tk.BOTH, expand=tk.YES)
for tab in self.tabs:
self.frames[tab].grid(sticky="nesw")
def add_frame(self, title, frame):
"""adds the frame to frames dict with key title"""
self.frames[title] = frame
class Navbar(ttk.Notebook):
"""returns a Notebook"""
def __init__(self, parent):
ttk.Notebook.__init__(self, parent)
#staticmethod
def delete(tab):
"""delete current tab"""
tab.forget(tab.select())
class MainInput(tk.Frame):
"""The base frame of every tab"""
def __init__(self, root, parent, notebook, settings=False, case=False):
tk.Frame.__init__(self, parent)
# Either build a settings or testcase tab
if settings is True:
SettingsField(root, parent)
if case is True:
CaseGeneral(parent, notebook)
class SettingsField(tk.Frame):
"""Creates a settings tab"""
def __init__(self, root, parent):
tk.Frame.__init__(self, parent)
# add the "new tab" name entry and button
tk.Label(parent, text="Add new Testcase:").grid(row=0, column=0, columnspan=2, sticky="w")
tk.Label(parent, text="Name:").grid(row=1, column=0, sticky="w", padx=20)
new_tab_title = tk.Entry(parent, textvariable=tk.StringVar(), width=30)
new_tab_title.grid(row=1, column=1, columnspan=2, sticky="w")
add_button = tk.Button(parent, text="add", command=lambda: [root.add_tab(new_tab_title.get())])
add_button.grid(row=1, column=3, sticky="w", padx=5)
class CaseGeneral(tk.Frame):
def __init__(self, parent, notebook):
tk.Frame.__init__(self, parent)
# create "delete current tab" buton
tk.Label(parent, text="delete Testcase").grid(row=0, column=0)
delete_button = tk.Button(parent, text="delete", command=lambda: [Navbar.delete(notebook)])
delete_button.grid(row=0, column=1, sticky="w")
Images of the running code:
Settings Tab
Cases
Note: Please don't roast me since this is my first post here :)
A really simple solution would be to create a binding on <<NotebookTabChanged>> that creates a new tab whenever the last tab on the row is selected. You can then create a tab with a "+" as the label and make sure it's the last tab.
Here's a simple example of the technique. It gives the new tab a label of <untitled>. Every time you click on the last tab it creates a new tab immediately before the last tab and then selects it.
import tkinter as tk
from tkinter import ttk
def handleTabChange(event):
if notebook.select() == notebook.tabs()[-1]:
index = len(notebook.tabs())-1
frame = tk.Frame(notebook)
notebook.insert(index, frame, text="<untitled>")
notebook.select(index)
root = tk.Tk()
notebook = ttk.Notebook(root)
notebook.bind("<<NotebookTabChanged>>", handleTabChange)
notebook.pack(fill="both", expand=True)
# add a tab that creates new tabs when selected
frame = tk.Frame()
notebook.add(frame, text="+")
root.mainloop()
So, I've been trying to bind the enter key to press the button I have in this python program -- yes I've seen the numerous other questions related to this, but none of their code worked with this program for whatever reason. Posting code below to see if anyone has a good solution.
The below code does everything as expected -- it will pull up the GUI, show the goofy jar-jar picture, the button, and the entry fields with the prefilled text, but the enter key on my keyboard will not produce a result as it happens when I press the button with the mouse.
import tkinter as tk
from PIL import Image, ImageTk, ImageTransform
from tkinter.filedialog import askopenfile
root = tk.Tk()
class guiMenu:
def __init__(self, master):
myFrame = tk.Frame(master)
# logo
logo = Image.open('jar.jpg')
logo2 = logo.resize((200, 200), Image.ANTIALIAS)
logo2 = ImageTk.PhotoImage(logo2)
self.logo_label = tk.Label(image=logo2)
self.logo_label.image = logo2
self.logo_label.grid(column=1, row=0)
# instructions
self.instructions = tk.Label(master,
text="Input your email address and password to extract email attachments.\n "
"You should also select the folder you wish the attachments to reach.")
self.instructions.grid(columnspan=3, column=0, row=3)
# store the user login info in variables
def storeUserLogin():
clientEmailInput = self.emailEntry.get()
clientPasswordInput = self.passwordEntry.get()
print(clientEmailInput, clientPasswordInput)
# delete email prefill on click
def onEmailClick(event):
self.emailEntry.configure()
self.emailEntry.delete(0, 100) # this deletes the preexisting text for email entry
self.emailEntry.unbind('<Button-1>', self.on_click_id)
# delete pw prefill on click
def onPWClick(event):
self.passwordEntry.configure()
self.passwordEntry.delete(0, 100) # this deletes the preexisting text for email entry
self.passwordEntry.unbind('<Button-1>', self.on_click_id2)
# email entry box
self.emailEntry = tk.Entry(master, width=50)
# emailEntry = tk.StringVar(None)
# emailEntry.set("Email Address")
self.emailEntry = tk.Entry()
self.emailEntry.insert(0, "Email Address")
self.emailEntry.configure()
self.emailEntry.grid(column=1, row=1)
# on-click function
self.on_click_id = self.emailEntry.bind('<Button-1>', onEmailClick)
# enter key function
def enterFunction(event=None):
master.bind('<Return>', lambda event=None, loginButton.invoke())
# password entry box
self.passwordEntry = tk.Entry()
self.passwordEntry.insert(0, "Password")
self.passwordEntry.grid(column=1, row=2)
# on click function
self.on_click_id2 = self.passwordEntry.bind('<Button-1>', onPWClick)
# button to login
def loginButton():
self.loginButtonText = tk.StringVar()
self.loginButton = tk.Button(master, textvariable=self.loginButtonText, font="Arial",
commands=lambda: [storeUserLogin(), enterFunction()],
width=5, height=2,
bg="white", fg="black")
self.loginButtonText.set("LOGIN")
self.loginButton.grid(column=1, row=4)
self.canvas = tk.Canvas(root, width=600, height=250)
self.canvas.grid(columnspan=3)
g = guiMenu(root)
root.mainloop()
You're Binding the loginButton function in another function which is never called and you are writing the OOPs wrong here. You shouldn't define your functions in init function.Here is some changes that i made in your code. I am not good at explaining but i hope this will help. I wrote reasons too in code where i change the code.
import tkinter as tk
from PIL import Image, ImageTk, ImageTransform
from tkinter.filedialog import askopenfile
root = tk.Tk()
class guiMenu:
def __init__(self, master):
#definr master in Class so we can use it from entire class
self.master = master
myFrame = tk.Frame(master)
# logo
logo = Image.open('Spitball\Spc.jpg')
logo2 = logo.resize((200, 200), Image.ANTIALIAS)
logo2 = ImageTk.PhotoImage(logo2)
self.logo_label = tk.Label(image=logo2)
self.logo_label.image = logo2
self.logo_label.grid(column=1, row=0)
#Create Email Entry box (we are creating Email and Password entry box when class is initialize)
self.emailEntry = tk.Entry(master, width=50)
self.emailEntry.insert(0, "Email Address")
# emailEntry = tk.StringVar(None)
# emailEntry.set("Email Address")
# self.emailEntry = tk.Entry() # You should not create two entry boxes with same name
# self.emailEntry.configure() # We dont need to configure email entry here
#Create Password Entry box (we are creating Email and Password entry box when class is initialize)
self.passwordEntry = tk.Entry()
self.passwordEntry.insert(0, "Password")
#Grid the email and password entry box.Here email entry box will display first beacuse we grid it first.
self.emailEntry.grid(column=1, row=1)
self.passwordEntry.grid(column=1, row=2)
# instructions
self.instructions = tk.Label(master,
text="Input your email address and password to extract email attachments.\n "
"You should also select the folder you wish the attachments to reach.")
self.instructions.grid(columnspan=3, column=0, row=3)
#Create Login Button
self.loginButtonText = tk.StringVar()
self.loginButton = tk.Button(self.master, textvariable=self.loginButtonText, font="Arial",
command=self.storeUserLogin,
width=5, height=2,
bg="white", fg="black")
# I dont see here the use of Canvas so i commented out it.
# self.canvas = tk.Canvas(self.master, width=600, height=250)
# on-click function
self.on_click_id = self.emailEntry.bind('', self.onEmailClick)
# on click function
self.on_click_id2 = self.passwordEntry.bind('', self.onPWClick)
#Bind enter key with loginButtonFunc
self.master.bind('',self.loginButtonFunc)
def storeUserLogin(self):
# store the user login info in variables
clientEmailInput = self.emailEntry.get()
clientPasswordInput = self.passwordEntry.get()
print(clientEmailInput, clientPasswordInput)
# delete email prefill on click
def onEmailClick(self,event):
self.emailEntry.configure()
self.emailEntry.delete(0, 100) # this deletes the preexisting text for email entry
self.emailEntry.unbind('', self.on_click_id)
# delete pw prefill on click
def onPWClick(self,event):
self.passwordEntry.configure()
self.passwordEntry.delete(0, 100) # this deletes the preexisting text for email entry
self.passwordEntry.unbind('', self.on_click_id2)
# button to login
def loginButtonFunc(self,event=None):
self.loginButtonText.set("LOGIN")
self.loginButton.grid(column=1, row=4,pady=5)
# self.canvas.grid(columnspan=3)
g = guiMenu(root)
root.mainloop()
The Incorrect-Dimiss button erases on click and when Return key is pressed, but if I enter anything afterwards, nothing happens. The issue is that if I enter it correct, the login button pops up and it works. If I enter it incorrect, the dismiss button pops up, and clicking or pressing enter erases it. Now, anything I enter after an incorrect attempt whether correct or incorrect does nothing.
(1) In order to avoid this, I was wondering if the program could just restart on clicking/pressing enter the dismiss button, without the window closing, or another reopening, but I do not know how to do this.
(2)Also is there a max login attempts code that ends/restarts the program and if so how would I place it in this code? (something like if >3 incorrect then quit)
Here is the code (python3)- try it for yourself if you would like:
from tkinter import *
class Application(object):
def __init__(self, event=None):
self.root = Tk()
self.root.configure(bg="darkorchid1", padx=10, pady=10)
self.root.title("WELCOME")
self.username = "Bob"
self.welcome = Label(self.root, text="WELCOME TO MY PROGRAM", bg="lightgrey", fg="darkorchid1")
self.welcome.pack()
self.label0 = Label(self.root, text="ENTER NAME:", bg="purple", fg="white", height=5, width=50)
self.label0.pack()
self.entry = Entry(self.root, width=25)
self.entry.configure(fg= "white",bg="grey20")
self.entry.pack()
self.entry.bind("<Return>", self.submit)
self.button = Button(self.root, text="SUBMIT", highlightbackground="green", width=48, command=self.submit)
self.button.pack()
def submit(self, event=None):
username = self.entry.get()
if username == self.username:
self.button1 = Button(self.root, text='LOGIN', highlightbackground="green", width=28, command=self.root.destroy)
self.button1.pack()
self.entry.bind("<Return>", self.login)
else:
self.button2 = Button(self.root, text="INCORRECT- CLICK TO DIMISS THIS MESSAGE", highlightbackground="red", width=48, command=self.incorrect)
self.button2.pack()
self.entry.bind("<Return>", self.incorrect)
def incorrect(self, event=None):
self.button2.destroy()
def login(self, event=None):
self.root.destroy()
app=Application()
mainloop()
Instead of destroying the button I want this to restart the program but cannot find the correct command. This would destroy the button since it doesn't exist at the beginning of the program, as well as allow for incorrect or correct input to actually work after the first try.
def incorrect(self, event=None):
self.button2.destroy()
I am a beginner so the more simple, the better at this point. Thank you.
Not an expert myself but fiddled with TKinter some time ago. From what I know the only way to restart a TKinter app is by running it in a thread and then killing and restarting that thread. I would recommend you to take a look at Python's multiprocessing or threading module.
Something you could also try (which worked for me in that past, but isn't really the correct way of doing this I suppose) is to have ROOT = Tk()as a global variable, then having your submit-button as a stand-alone class and have it import global ROOT before executing ROOT.Destroy() and then have it call the application class again, which can also call the global variable (which would cause it to start again). It's a method I've used to have the TKinter window update while I was using it. But the threading method is often mentioned as the proper way of doing this as far as I know..
As a very limited example (short on time for a more extensive one), I did something like this in my old script:
ROOT_WINDOW = ""
VARIABLE1 = 'some variable here'
def func1():
global ROOT_WINDOW
global VARIABLE1
ROOT_WINDOW = Tk()
#(Insert application code that uses or requires variable1)
func2()
def func2():
global ROOT_WINDOW
global VARIABLE1
ROOT_WINDOW.Destroy()
Change variable1
func1()
With regard to setting a maximum number of login attempts. I solved this by creating a separate startup script. It works correctly but I dare not to post it here as it is a real ugly and incorrect way of solving the problem that also comes with a security issue (of having to store your sudo password within a variable).
Sorry for not being able to be of more help.
First of all I would change the bind to return to the root window instead of the entry (otherwise you have to click on the entry field for the return to have an effect)
Next you need 3 state variables for your class.
self.button1 = None
self.button2 = None
self.attempts = 0
Then by checking the state of each you can accomplish (what I think) you want
Here’s the whole code modified
from tkinter import *
class Application(object):
def __init__(self, event=None):
self.root = Tk()
self.root.configure(bg="darkorchid1", padx=10, pady=10)
self.root.title("WELCOME")
self.username = "Bob"
self.welcome = Label(self.root, text="WELCOME TO MY PROGRAM", bg="lightgrey", fg="darkorchid1")
self.welcome.pack()
self.label0 = Label(self.root, text="ENTER NAME:", bg="purple", fg="white", height=5, width=50)
self.label0.pack()
self.entry = Entry(self.root, width=25)
self.entry.configure(fg= "white",bg="grey20")
self.entry.pack()
self.root.bind("<Return>", self.submit)
self.button = Button(self.root, text="SUBMIT", highlightbackground="green", width=48, command=self.submit)
self.button.pack()
self.button1 = None
self.button2 = None
self.attempts = 0
def submit(self, event=None):
username = self.entry.get()
if username == self.username:
if (self.button2 != None): # after I added disabling the submit button this check might not be necessary
return
if (self.button1 == None):
self.button1 = Button(self.root, text='LOGIN', highlightbackground="green", width=28, command=self.root.destroy)
self.button1.pack()
self.root.bind("<Return>", self.login)
self.button.config(state="disabled")
else:
if (self.button2 == None):
self.button2 = Button(self.root, text="INCORRECT- CLICK TO DIMISS THIS MESSAGE", highlightbackground="red", width=48, command=self.incorrect)
self.button2.pack()
self.root.bind("<Return>", self.incorrect)
self.button.config(state="disabled")
def incorrect(self, event=None):
self.attempts += 1
if (self.attempts > 2):
self.root.destroy()
else:
self.root.bind("<Return>", self.submit)
self.button.config(state="normal")
self.button2.destroy()
self.button2 = None
def login(self, event=None):
self.root.destroy()
app=Application()
mainloop()
Okay, so I've got a basic window with an EDIT and VIEW button. As my code stands, EDIT and VIEW both return a message "this button is useless". I created these under the class "main_window". I created another class "edit_window" that I'm hoping to call when the EDIT button is clicked. Essentially, clicking the edit button should change display the new window with buttons ADD and REMOVE. Here's my code so far...what would be the next logical step?
from Tkinter import *
#import the Tkinter module and it's methods
#create a class for our program
class main_window:
def __init__(self, master):
frame = Frame(master)
frame.pack(padx=15,pady=100)
self.edit = Button(frame, text="EDIT", command=self.edit)
self.edit.pack(side=LEFT, padx=10, pady=10)
self.view = Button(frame, text="VIEW", command=self.view)
self.view.pack(side=RIGHT, padx=10, pady=10)
def edit(self):
print "this button is useless"
def view(self):
print "this button is useless"
class edit_window:
def __init__(self, master):
frame = Frame(master)
frame.pack(padx=15, pady=100)
self.add = Button(frame, text="ADD", command=self.add)
self.add.pack()
self.remove = Button(frame, text="REMOVE", command=self.remove)
self.remove.pack()
def add(self):
print "this button is useless"
def remove(self):
print "this button is useless"
top = Tk()
top.geometry("500x500")
top.title('The Movie Machine')
#Code that defines the widgets
main = main_window(top)
#Then enter the main loop
top.mainloop()
Just create a Toplevel instead of using a Frame:
class MainWindow:
#...
def edit(self):
EditWindow()
class EditWindow(Toplevel):
def __init__(self):
Toplevel.__init__(self)
self.add = Button(self, text="ADD", command=self.add)
self.remove = Button(self, text="REMOVE", command=self.remove)
self.add.pack()
self.remove.pack()
I've changed the class names according to the CapWords convention (see PEP 8). This is not mandatory, but I recommend you to use it in all your Python projects to keep an uniform style.
I am trying to create frame with 2 input areas (for login and password) and confirmation button (after this button is pressed - code will read areas values). But I don't know how to do it inside class App without using some global function.
from Tkinter import *
class App:
def __init__(self, master):
frame_credentials = Frame(master, width=100, height=200)
frame_credentials.pack()
self.label_login = Label(frame_credentials, text='login')
self.text_login = Entry(frame_credentials, width=15)
self.label_pass = Label(frame_credentials, text='password')
self.text_pass = Entry(frame_credentials, show="*", width=15)
self.button_ok = Button(frame_credentials, text="Login")
self.label_login.grid(row=0, column=0)
self.text_login.grid(row=1, column=0)
self.label_pass.grid(row=2, column=0)
self.text_pass.grid(row=3, column=0)
self.button_ok.grid(row=0, column=1, rowspan=4)
self.button_ok.bind("<Button-1>", enter_in)
def enter_in(self):
print self.text_login, self.text_pass
root = Tk()
app = App(root)
root.mainloop()
Don't bind to <Button-1>; instead, use the command attribute and give it the name of a method in your object. For example:
class App:
def __init__(...):
...
self.button_ok = Button(..., command=self.enter_in)
...
def enter_in(self):
<put your login logic here>