I have two functions the top_signup_click and the top_login_click. The top_signup_click function is below the top_login_click function. The top_login_click function doesn't work because the_top_signup_click function is below it. To fix that issue I'll have to put the top_signup_click above the top_login_click function, which does solve the issue but it also creates another issue, now the top_signup_click function doesn't work. For both functions to work they both have to be below each other, but I don't think that's possible. If you know any other ways to do this please help. I tried using global functions to fix it but it didn't work.
import tkinter as tk
import tkinter.font as font
import tkinter.messagebox
signup_button = None
root = tk.Tk()
root.geometry('360x460')
#login stuff
def login_click():
readfile = open("emails.txt", "r")
lines = readfile.readlines()
isIN = False
for line in lines:
if f'{entry.get()}, {entry1.get()}' in line:
isIN = True
if not isIN:
tk.messagebox.showinfo(message ="You got your email/password wrong, are you sure you signed in?")
else:
tk.messagebox.showinfo(message ="You hacker, the email/password is correct")
def signup_click():
file = open("emails.txt","a")
file.write (entry.get())
file.write(f', {entry1.get()}\n')
def top_login_click():
global signup_button
signup_button.destroy()
login_button = tk.Button(root, text="Login", bg='royalblue', fg='white', command = login_click, width = 15, height = 2)
login_button['font'] = button_font
login_button.place(x=88,y=330)
#when the top sign up button is pressed
def top_signup_click():
global login_button
login_button.destroy()
signup_button = tk.Button(root, text="Sign-Up", bg='royalblue', fg='white', command = login_click, width = 15, height = 2)
signup_button['font'] = button_font
signup_button.place(x=88,y=330)
top_font = font.Font(family='Helvetica', size=14, weight='bold')
label_font = font.Font(family='Helvetica', size=20)
button_font = font.Font(family='Helvetica', size=14, weight='bold')
top_login_button = tk.Button(root,text = 'Login',width = 15, height = 3, command = top_login_click)
top_login_button.place(x=0,y=0)
top_login_button['font'] = top_font
top_signup_button = tk.Button(root,text = 'Sign-Up',width = 15, height = 3, command = top_signup_click)
top_signup_button.place(x=180,y=0)
top_signup_button['font'] = top_font
username_label = tk.Label(root, text = 'Username: ' )
username_label['font'] =label_font
username_label.place(x=120,y=120)
entry = tk.Entry(root, width = 40)
entry.place(x=65,y=170, height = 30)
password_label = tk.Label(root, text = 'Password: ' )
password_label['font'] =label_font
password_label.place(x=120,y=230)
entry1 = tk.Entry(root, width = 40)
entry1.place(x=65,y=280, height = 30)
login_button = tk.Button(root, text="Login", bg='royalblue', fg='white', command = login_click, width = 15, height = 2)
login_button['font'] = button_font
login_button.place(x=88,y=330)
root.mainloop()
The top_login_click function is on line 29-34 and the top_signup_click function is on line 37-42. Thanks in advance.
I wanted to comment this but seems like I don't have enough reputation but here is what I think.
You have set the variable signup_button = None right below the import statements so signup_button is not really a tk.Button object, instead it's a NoneType variable.
So just remove that statement and create
signup_button = tk.Button(<args here>)
and You should be good.
and try using place_forget() instead of destroy() IFF destroy doesn't work for you.
Edit:
What I also think in your case that you may not really need to destroy the signup_up button because you haven't created one yet. Think about it this way (based on the GUI that comes up on running your code) - on the landing screen of your app (the first screen that comes up), you have a login form with two entry boxes for email & pword and a login button, along with two more buttons called top_login_button and top_signup_button. So You DO NOT have a signup_button as of now (and according to your code signup_button = None it's not a button). So if a user now clicks on the top_login_button, the statement signup_button.destroy() will look for widget with the name signup_button (which is set to None by you) so it raises the error.
You code will run fine in a case where user clicks on top_signup_button before clicking on top_login_button because in that case the signup_button will be actually set to be a tk.Button object.
Related
I want it to show the user input but it is not showing. Please send help.
I have tried code from multiple posts but no luck.
I was able to make it show the 'selected' option but for no avail. Please help me
import tkinter as tk
from tkinter.ttk import *
app = tk.Tk()
# Functions and scripts
def OnSubmit():
print(str(usrnme.get()))
print(str(passw.get()))
print(str(selected.get()))
app.title("Pymark: Landing Page")
app.geometry("600x600")
app.resizable(0, 0)
desc = """
PyMark is the first benchmark created using python's native GUI creator "Tkinter" and using hashes to rank performance.
The sofware is light and can run on older CPU's like i7-4510U (the processor I use) and does not require a lot of memory.
I am still open for constructive critisism and community feedback on my work as I am a beginner programmer.
IMPORTANT: PyMark can still experience bugs thus, pull requests are encouraged!
Please continue enjoying PyMark!
"""
# Landing Page
lpframe = Frame(app)
mainheading = Label(lpframe, text="Welcome to PyMark!", font = ('Times New Roman', 20))
maindesc = Label(lpframe, text=f'{desc}', font = ('Times New Roman', 9))
lpframe.pack()
mainheading.pack(padx = 10, pady = 10)
maindesc.pack(padx = 10, pady = 10)
# Login Page
loginframe = Frame(app)
headerframe = Frame(loginframe, relief = 'groove')
loginheader = Label(headerframe, text='Login / Register: ', font = ('Times New Roman', 12))
usrnmelb = Label(loginframe, text = 'Username: ', font = ('Times New Roman', 9))
passlb = Label(loginframe, text = 'Password: ', font = ('Times New Roman', 9))
selected = tk.StringVar()
register = Radiobutton(loginframe, text='Register', value='reg', variable=selected)
login = Radiobutton(loginframe, text='Login', value='log', variable=selected)
submitbtn = Button(loginframe, text = 'Submit', command=OnSubmit)
usrnmeentr = Entry(loginframe)
passentr = Entry(loginframe)
loginframe.pack()
headerframe.pack(padx = 20, pady = 20)
loginheader.pack(padx = 20, pady = 20)
usrnmelb.pack()
usrnmeentr.pack()
passlb.pack()
passentr.pack()
register.pack()
login.pack()
submitbtn.pack(padx = 10, pady = 10)
usrnme = tk.StringVar()
passw = tk.StringVar()
usrnmeentr.focus()
app.mainloop()
I expected it to return the username, password and the selected option but it only told the selected option and nothing else.
The OnSubmit() function does not get the correct inputs to print.
Get the entryfields content with the method .get().
In your case the OnSubmit() function should look like this:
def OnSubmit():
print(str(usrnmeentr.get())) #usrnme.get() was not the name of the entry box
print(str(passentr.get()))
print(str(selected.get()))
You must link your Entry to Stringvar(), not your radio buttons
import tkinter as tk
app = tk.Tk()
app.geometry('300x300')
# Functions and scripts
def OnSubmit():
print(var.get())
var = tk.StringVar()
entry = tk.Entry(app, textvariable=var)
entry.pack()
bt = tk.Button(app, text='Show', command=OnSubmit)
bt.pack()
app.mainloop()
I want my program to run in a way that once the user presses the Info button, a label called GameInfoLabel is displayed due to a command from the Info button. Within the same condition (if the Info button is pressed), I want to add a Back button that deletes/destroys the GameInfoLabel.
I have attempted to implement this in the code below, but I'm getting the message
NameError: name 'GameInfoLabel' is not defined.
from tkinter import *
root = Tk()
root.title("Game Menu")
root.geometry("1920x1080")
root.resizable(True, True)
def QuitGameInfo():
GameInfoLabel.destroy()
BackInfoButton['state'] = NORMAL
def GameInfo():
RulesNotepad = open("GameInfo.txt",'r')
Rules = RulesNotepad.read()
GameInfoLabel = Label(root, text = Rules, fg = "blue", bg = "red", height = "14", width = "140").pack()
BackInfoButton = Button(root, text = "Back", command = QuitGameInfo).pack()
RulesNotepad.close()
button3 = Button(root, text = "Info", command = GameInfo, width = "20", height = "3").pack()
root.mainloop()
The error is due to that GameInfoLabel is a local variable inside GameInfo() and it is not accessible inside QuitGameInfo().
You can fix this error by either declaring GameInfoLabel as global or pass it to QuitGameInfo() via argument. Same apply on BackInfoButton as well.
However you need to fix another issue: both GameInfoLabel and BackInfoButton are None because they are result of pack().
Below is the modified code using global solution:
from tkinter import *
root = Tk()
root.title("Game Menu")
root.geometry("1920x1080")
root.resizable(True, True)
def QuitGameInfo():
GameInfoLabel.destroy()
#BackInfoButton['state'] = NORMAL # why ??? Should it be destroyed as well?
BackInfoButton.destroy()
def GameInfo():
global GameInfoLabel, BackInfoButton
with open("GameInfo.txt",'r') as RulesNotepad:
Rules = RulesNotepad.read()
GameInfoLabel = Label(root, text = Rules, fg = "blue", bg = "red", height = "14", width = "140")
GameInfoLabel.pack()
BackInfoButton = Button(root, text = "Back", command = QuitGameInfo)
BackInfoButton.pack()
Button(root, text = "Info", command = GameInfo, width = "20", height = "3").pack()
root.mainloop()
However I would suggest to use a frame to hold the GameInfoLabel and BackInfoButton and the frame is hidden initially. When Info button is clicked, show the frame. When Back button is clicked, hide the frame.
from tkinter import *
root = Tk()
root.title("Game Menu")
root.geometry("1920x1080")
root.resizable(True, True)
def GameInfo():
with open("GameInfo.txt",'r') as RulesNotepad:
Rules = RulesNotepad.read()
GameInfoLabel.config(text=Rules)
info_frame.pack() # show the game info frame
Button(root, text="Info", command=GameInfo, width="20", height="3").pack()
# create the game info frame but don't show it initially
info_frame = Frame(root)
GameInfoLabel = Label(info_frame, fg="blue", bg="red", height="14", width="140")
GameInfoLabel.pack()
Button(info_frame, text="Back", command=info_frame.pack_forget).pack()
root.mainloop()
As mentioned in acw1668's comment GameInfoLabel is local to the GameInfo() method. This means once this method has finished running anything declared in it ceases to exist.
The usual solution to this is passing/returning variables to functions to get results for instance your game info could return the label, however since you want to call these functions automatically when an event occurs, e.g. your button is pressed, this is not so easy.
I believe the easiest solution to your problem would be to declare the GameInfoLabel variable globally (in the global scope), this is not always the best coding practice but I'm not certain of tkinter's ability to pass variables parameters to an event handler and this can be complicated.
Also as mentioned by acw1668 you call .pack() immediately on the new label which is returned from the initialization Label(...). Pack then does not return the label so we do that separately.
This should work, give it a careful read.
from tkinter import *
root = Tk()
root.title("Game Menu")
root.geometry("1920x1080")
root.resizable(True, True)
# Declare any global UI Components
GameInfoLabel = None # Dont set a Label yet
def QuitGameInfo():
GameInfoLabel.destroy()
BackInfoButton['state'] = NORMAL
def GameInfo():
RulesNotepad = open("GameInfo.txt",'r')
Rules = RulesNotepad.read()
GameInfoLabel = Label(root, text = Rules, fg = "blue", bg = "red", height = "14", width = "140")
GameInfoLabel.pack()
BackInfoButton = Button(root, text = "Back", command = QuitGameInfo).pack()
RulesNotepad.close()
button3 = Button(root, text = "Info", command = GameInfo, width = "20", height = "3")
button3.pack()
root.mainloop()
I am having trouble gaining the outputs from this form and i cant seem to identify where its going wrong.
from tkinter import *
def Button_to_text():
firstname_info = firstname.get()
lastname_info = lastname.get()
age_info = age.get()
print(firstname_info,lastname_info,age_info)
screen = Tk()
screen.geometry("500x500")
screen.title("python_form")
heading = Label(text = "Demo Form",bg = "orange", fg="black",width = "500")
heading.pack()
firstname_text = Label(text="firstname")
lastname_text = Label(text="lastname")
age_text = Label(text="age")
firstname_text.place(x=60, y= 40)
lastname_text.place(x=60,y=80)
age_text.place(x=60,y=120)
firstname = StringVar()
lastname = StringVar()
age = IntVar()
firstname_entry = Entry(textvariable = firstname)
lastname_entry = Entry(textvariable = lastname)
age_entry = Entry(textvariable = age)
firstname_entry.place(x=160, y=40)
lastname_entry.place(x=160,y=80)
age_entry.place(x=160,y=120)
register = Button(text = "register", width= "30",height ="2", command = Button_to_text())
register.place(x=50,y=290)
I followed a tutorial and my computing teacher cant help because he doesn't know python. plus my friends cant seem to identify the issue there are also no errors coming up so I know its a logic error and i also cant work out how to step so i can check variables
thanks to anyone who can help.
There are two problems with your code:
You have to use a mainloop to keep the window being displayed continuously.
You should not use the parentheses() while passing any function to a Button as an argument.
Note: And if the function has its own parameters then you will have to use lambda while passing it to a Button. But in your case, you can simply remove the parentheses().
Here's the fixed code:
from tkinter import *
def Button_to_text():
firstname_info = firstname.get()
lastname_info = lastname.get()
age_info = age.get()
print(firstname_info, lastname_info, age_info)
screen = Tk()
screen.geometry("500x500")
screen.title("python_form")
heading = Label(text="Demo Form", bg="orange", fg="black", width="500")
heading.pack()
firstname_text = Label(text="firstname")
lastname_text = Label(text="lastname")
age_text = Label(text="age")
firstname_text.place(x=60, y=40)
lastname_text.place(x=60, y=80)
age_text.place(x=60, y=120)
firstname = StringVar()
lastname = StringVar()
age = IntVar()
firstname_entry = Entry(textvariable=firstname)
lastname_entry = Entry(textvariable=lastname)
age_entry = Entry(textvariable=age)
firstname_entry.place(x=160, y=40)
lastname_entry.place(x=160, y=80)
age_entry.place(x=160, y=120)
register = Button(text="register", width="30", height="2", command=Button_to_text)
register.place(x=50, y=290)
screen.mainloop()
Note:
As a good practice, you should always use small letters in the names of functions like this: def button_to_text():.
And you should always import tkinter as tk instead of importing all * from tkinter. It is always a good practice. The only change you will need to do in the program is that you will need to use tk. before each item belonging to tkinter. Like this: screen = tk.Tk()
why does this code fail
im trying to summon a window when the settings button is pressed that allows users to change the forground and background colours
i get the radio buttons but recive an error every time i submit the colours even though their value is not 0
how do i fix this and why does it happen?
from tkinter import *
import os
from tkinter import messagebox as mgb
import tkinter.ttk as tk2
global colour_1, colour_2
colour_1 = "pink"
colour_2 = "purple" #background
def sayclick() :
btn.configure(text = "saying")
text = txt.get()
os.system("""PowerShell -Command "Add-Type –AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak('""" + text + """ ');" """)
btn.configure(text = "say")
def colourmenu():
window = Tk()
window.title("colour menu")
selected = IntVar()
selected2 = IntVar()
rad11 = tk2.Radiobutton(window,text='blue ', value=1, variable=selected)# set 1
rad21 = tk2.Radiobutton(window,text='green', value=2, variable=selected)#
rad31 = tk2.Radiobutton(window,text='red ', value=3, variable=selected)#
rad41 = tk2.Radiobutton(window,text='black', value=4, variable=selected)#
rad12 = tk2.Radiobutton(window,text='blue ', value=1, variable=selected2)
rad22 = tk2.Radiobutton(window,text='green', value=2, variable=selected2)
rad32 = tk2.Radiobutton(window,text='red ', value=3, variable=selected2)
rad42 = tk2.Radiobutton(window,text='black', value=4, variable=selected2)
def submitbut():
if selected.get() == 0 :
mgb.showinfo("error", "error: invalid colour choise")
elif selected2.get() == 0 :
mgb.showinfo("error", "error: invalid colour choise")
else :
for n in range(1,3):
if n == 1 :
val = selected.get()
rep = 1
else :
val = selected2.get()
rep = 2
if val == 1:
colour = "blue"
elif val == 2 :
colour = "green"
elif val == 3 :
colour = "red"
else :
colour = "black"
if rep == 1 :
bg = colour
else :
fg = colour
submit = Button(window, text="submit", command=submitbut)
txt1 = Label(window, text = "background")
txt1.grid(column = 0, row = 0)
txt2 = Label(window, text = "forground")
txt2.grid(column = 1, row = 0)
rad11.grid(column=0, row=1)#set 1
rad21.grid(column=0, row=2)#
rad31.grid(column=0, row=3)#
rad41.grid(column=0, row=4)#
rad12.grid(column=1, row=1)
rad22.grid(column=1, row=2)
rad32.grid(column=1, row=3)
rad42.grid(column=1, row=4)
submit.grid(column=0, row=5)
window.mainloop()
root = Tk()
root.geometry("170x120")
root.title("tts entry box")
root.configure(background = colour_2)
lab = Label(root, text = "enter text and than press\n\"say\" to say the text", font = ("Arial Bold", 10), fg = colour_2, bg = colour_1)
lab.grid(column = 0, row = 0)
btn = Button(root, text = " say. ", font = ("Arial", 8), bg = colour_1, fg = colour_2, command = sayclick)
btn.grid(column = 0, row = 3)
btn2 = Button(root, text = "settings", font = ("Arial", 8), bg = colour_1, fg = colour_2, command = colourmenu)
btn2.grid(column = 0, row = 4)
txt = Entry(root, width = 10, bg = colour_1, fg = colour_2)
txt.grid(column = 0, row = 2)
root.mainloop()
The problem is that you have two separate Tk objects in your program. This is almost always a bad idea, and the reason it's a bad idea is that it means that any code that relies on the "default Tk object" is likely to do the wrong thing.
In particular, when you do this:
selected = IntVar()
… you're creating an IntVar that's part of the first Tk that you created.1,2 But the Radiobutton widgets are attached to a different Tk. So, they can't read those variables (that's why you start off with all of the radio buttons in indeterminate state), and they can't write to them either.3
If you want to create a new top-level window, you don't need to create a whole new Tk environment, just use a Toplevel widget:
def colormenu():
window = Toplevel()
# the rest of your code can be the same
And then, the IntVars end up as part of the same Tk as the window.
While we're at it, do you really want to put a mainloop inside the other mainloop? This is legal, but I don't think it's what you want. It's almost certainly better to just return from colormenu after the submit.grid and let the main mainloop loop. (If you were trying to make colormenu a modal dialog, that blocks interaction with the main window, this isn't the way to do it.)
1. You can explicitly specify a parent when creating an IntVar, the same way you do for a widget. For example, selected = IntVar(window) would make this problem go away. But there are additional problems with having a separate Tk here, so it's better to solve them all at once by just not having one.
2. If you ever need to have multiple Tk instances, and need to know which one a variable, widget, etc. is attached to, you can look at its _root attribute. For example, selected._root is window._root will tell you whether they're part of the same Tk or not—in this case, it's False with your code as written, but True with the change in the next paragraph.
3. If you're curious why this isn't giving you a useful and easily-debuggable error, you have to understand how tkinter actually works. Tkinter is a wrapper around the Tk library, written in a completely separate scripting language called Tcl. Each Tk root instance has its own entirely independent Tcl interpreter, with its own independent global variables. So, your selected = IntVar() is creating a Tcl global variable named PY_VAR0 inside your first Tcl interpreter. Then, your variable=selected tells Tcl to store changes to the global variable PY_VAR0 in your second Tcl interpreter. So, whenever there's a change, Tcl writes to the global variable PY_VAR0 in the second interpreter, which is perfectly legal, but perfectly useless, because your selected looks up PY_VAR0 in the first interpreter.
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()