I'm trying to build a login screen for practice and I'm having trouble with it. The general idea is that pressing the Login button closes the current window and opens another in a separate file. However, when I run the main file it opens the GUI window created in the second file. I'm not sure what would be causing it to do this.
import tkinter as tk
import loginEntry
HEIGHT = 200
WIDTH = 500
def login_function():
root.destroy()
loginEntry.NewScreen()
def register_function():
print("Register!")
root = tk.Tk()
root.title("Login Screen")
root.resizable(False, False)
canvas = tk.Canvas(root, height = HEIGHT, width = WIDTH)
canvas.pack()
frame = tk.Frame(root, bg='grey')
frame.place(relx=0.1, rely=0.25, relwidth=0.8, relheight=0.5)
login = tk.Button(frame, text="Login", command=login_function)
login.place(relx=0.05, rely=0.25, relwidth=0.425, relheight=0.5,)
register = tk.Button(frame, text="Register", command=register_function)
register.place(relx=0.525, rely=0.25, relwidth=0.425, relheight=0.5,)
introduction = tk.Label(root, text="Hello and welcome to DogNet, please login below.", font='bold 12')
introduction.place(relx=0.5, anchor='center', rely=0.1)
root.mainloop()
and then the second file
import tkinter as tk
def NewScreen():
root = tk.Tk()
canvas = tk.Canvas(root, bg='black')
canvas.pack()
root.mainloop()
NewScreen()
This is because, in your second file, you are calling the definition when it is imported.
import tkinter as tk
def NewScreen():
root = tk.Tk()
canvas = tk.Canvas(root, bg='black')
canvas.pack()
root.mainloop()
NewScreen() #< here you call the definition
This means that the series of events that happen in your program are as follows.
First file starts
Second file is imported
Definition "NewScreen" is called
tkinter mainloop starts which puts your program into a loop and stops the program from going on to any new lines until the loop is closed
Related
I am a newbie trying to use tkinter to build a GUI for an application. So far, I have a frame that I'd like to put several buttons into. However, every time I attempt to position this button, it isn't placed properly, being put outside of the frame itself. I wouldn't like to use the place function because of the several buttons I have to dynamically generate coming from an excel sheet so I was hoping to use the grid function instead.
Here is what I have so far
from tkinter import *
from customtkinter import *
window = Tk()
window.geometry("1920x1080")
window.state("zoomed")
window.title("My Company's Description Printer")
main_frame = CTkFrame(window, width=1920, height=1080, fg_color="grey21")
main_frame.place(x=0, y=0)
title = Label(main_frame,
text="My Company",
bg="grey21",
fg="white",
font=("Trajan Pro", 20)).place(x=626, y=30)
button_frame = CTkCanvas(main_frame,
width=800,
height=600,
highlightthickness=3,
highlightbackground="black",
relief="ridge",
bg="grey19").place(x=60, y=110)
test_button = CTkButton(button_frame, text="test").grid(row=0, column=0)
window.mainloop()
Example of code being ran
As you can see, the button is being placed in the top left corner of the entire window rather than the top left corner of the black bordered button frame. Any help would be appreciated. Thank you so much.
Note that button_frame is None because it is the result of .place(...), so the button (test_button is None as well due to same reason) is a child of the root window instead of the instance of CTkCanvas. .place(...) should be called in separate line.
Also .create_window() is used instead of tkinter layout manager to put widget into a canvas:
...
button_frame = CTkCanvas(main_frame,
width=800,
height=600,
highlightthickness=3,
highlightbackground="black",
relief="ridge",
bg="grey19")
# call .place(...) in separate line
button_frame.place(x=60, y=110)
test_button = CTkButton(button_frame, text="test") # don't use .grid(row=0, column=0)
# use .create_window() to put widget into canvas
button_frame.create_window(0, 0, window=test_button, anchor="nw")
I've started learning Tkinter on Python few weeks ago and wanted to create a Guess Game. But unfortunately I ran into a problem, with this code the text for the rules ( in the function Rules; text='Here are the rules... ) doesn't appear on the window ( rule_window).
window = Tk()
window.title("Guessing Game")
welcome = Label(window,text="Welcome To The Guessing Game!",background="black",foreground="white")
welcome.grid(row=0,column=0,columnspan=3)
def Rules():
rule_window = Tk()
rule_window = rule_window.title("The Rules")
the_rules = Label(rule_window, text='Here are the rules...', foreground="black")
the_rules.grid(row=0,column=0,columnspan=3)
rule_window.mainloop()
rules = Button(window,text="Rules",command=Rules)
rules.grid(row=1,column=0,columnspan=1)
window.mainloop()
Does anyone know how to solve this problem?
In your code you reset whatever rule_window is to a string (in this line: rule_window = rule_window.title(...))
Try this:
from import tkinter *
window = Tk()
window.title("Guessing Game")
welcome = Label(window, text="Welcome To The Guessing Game!", background="black", foreground="white")
welcome.grid(row=0, column=0, columnspan=3)
def Rules():
rule_window = Toplevel(window)
rule_window.title("The Rules")
the_rules = Label(rule_window, text="Here are the rules...", foreground="black")
the_rules.grid(row=0, column=0, columnspan=3)
rules = Button(window, text="Rules", command=Rules)
rules.grid(row=1, column=0, columnspan=1)
window.mainloop()
When you want to have 2 windows that are responsive at the same time you can use tkinter.Toplevel().
In your code, you have initialized the new instances of the Tkinter frame so, instead of you can create a top-level Window. What TopLevel Window does, generally creates a popup window kind of thing in the application. You can also trigger the Tkinter button to open the new window.
from tkinter import *
from tkinter import ttk
#Create an instance of tkinter window
root= Tk()
root.geometry("600x450")
#Define a function
def open_new():
#Create a TopLevel window
new_win= Toplevel(root)
new_win.title("My New Window")
#Set the geometry
new_win.geometry("600x250")
Label(new_win, text="Hello There!",font=('Georgia 15 bold')).pack(pady=30)
#Create a Button in main Window
btn= ttk.Button(root, text="New Window",command=open_new)
btn.pack()
root.mainloop()
So I have this GUI ith Tkinter that switch screens when I click on a button and the new screen has a back button to go back to the main screen. And if you close the other screen it takes you back to the main one again and if you close the main screen the app closes as it should. However, when switching for the main screen to another screen it works perfectly nothing wrong bt it give this error anyways:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1885, in __call__
return self.func(*args)
File "C:\Users\User\Desktop\Coding\Python\GmailSenderApp\GmailSenderApp.py", line 30, in <lambda>
button = tk.Button(root, text="Send Gmail without Attachments", font=('Courier', 14), command=lambda: screen1())
File "C:\Users\User\Desktop\Coding\Python\GmailSenderApp\GmailSenderApp.py", line 7, in screen1
Screen1.root.mainloop()
AttributeError: partially initialized module 'Screen1' has no attribute 'root' (most likely due to a circular import)
Here is the code for the main screen and second screen:
Main:
import tkinter as tk
import Screen1
def screen1():
root.destroy()
Screen1.root.mainloop()
HEIGHT = 500
WIDTH = 600
root = tk.Tk()
root.resizable(False, False)
root.title('Gmail Sender App')
icon = tk.PhotoImage(file='icon.png')
root.iconphoto(False, icon)
canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
canvas.pack()
background_label = tk.Label(root, bg='#ffbe80')
background_label.place(relwidth=1, relheight=1)
title_label = tk.Label(root, bg='#80c1ff', text="Gmail Sender App", font=('Courier', 14))
title_label.place(width=root.winfo_screenwidth(), height=40, y=0, x=-375)
button = tk.Button(root, text="Send Gmail without Attachments", font=('Courier', 14), command=lambda: screen1())
button.place(width=400, height=40, x=root.winfo_width() / 2, y=root.winfo_height() / 2)
button2 = tk.Button(root, text="Send Gmail with Attachments", font=('Courier', 14))
button2.place(width=400, height=40, x=root.winfo_width() / 2, y=root.winfo_height() / 1.25)
root.mainloop()
Second Screen:
import tkinter as tk
import GmailSenderApp
def back():
root.destroy()
GmailSenderApp.root.mainloop()
HEIGHT = 500
WIDTH = 600
root = tk.Tk()
root.resizable(False, False)
root.title('Gmail Sender App')
icon = tk.PhotoImage(file='icon.png')
root.iconphoto(False, icon)
canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
canvas.pack()
background_label = tk.Label(root, bg='#ffbe80')
background_label.place(relwidth=1, relheight=1)
title_label = tk.Label(root, bg='#80c1ff', text="Gmail Sender App", font=('Courier', 14))
title_label.place(width=root.winfo_screenwidth(), height=40, y=0, x=-375)
button = tk.Button(root, text="Back", font=('Courier', 14), command=lambda: back())
button.place(width=400, height=40, x=root.winfo_width() / 2, y=root.winfo_height() / 2)
root.mainloop()
So what am I doing wrong here?
also NOTE: that when clicking on the button to go to the screen again crashes the app
BTW Thanks in Advance
The circular error is probably caused because when you import a file all of the code that are in the global scope get executed and that code probably required a function from the file you initially ran.
I tried running your code although it didn't run properly for me I got an idea of what you are trying to achieve. You are trying to implement a tab feature but are opening a new window every time a tab is switched to. So, I'd recommend using the tabs that is built in with tkinter
from tkinter import ttk
tabs = ttk.Notebook(root)
Screen1 = ttk.Frame(tabs) # defining a new tab
tabs.add(Screen1, text='Screen1') # adding the new tab to the root
GmailSenderApp = ttk.Frame(tabs)
tabs.add(GmailSenderApp, text='GmailSenderApp')
Now you wont need a new file for each tab so keep all of the code in one file and while placing things like buttons instead of placing them in root place them directly to a tab.
For example I want to add a button to the Screen1 tab:
button = tk.Button(Screen1, text="Back", font=('Courier', 14), command=lambda: back())
button.place(width=400, height=40, x=root.winfo_width() / 2, y=root.winfo_height() / 2)
To sum it up the changes you have to make is add the first section of code that I've written bring all your code to one file and replace the first parameter for things like button and title from root to the tab that the belong to.
If something's not clear feel free to ask me.
So to begin with here is my code:
from Tkinter import *
def hello():
print "Hello"
root = Tk()
root.attributes('-fullscreen', 1)
icons = []
icons.append(PhotoImage(file="Icons\start.gif"))
icons.append(PhotoImage(file="Icons\quit.gif"))
icons.append(PhotoImage(file="Icons\save.gif"))
icons.append(PhotoImage(file="Icons\load.gif"))
icons.append(PhotoImage(file="Icons\Next.gif"))
screensizex = root.winfo_screenwidth()
screensizey = root.winfo_screenheight()
mainframe = Frame(root, height=(screensizey-(screensizey/20)), width=screensizex, bg="#50a9ad")
mainframe.grid(row=0)
menuframe = Frame(root, height=(screensizey/20), width=screensizex)
menuframe.grid(row=1, sticky="w")
startmenu = Menubutton ( menuframe, text="Start", image=icons[0], compound = LEFT, relief=RAISED,
direction="above")
startmenu.grid(row=0, column=0)
startmenu.place(relx=0.03, rely=0.5, anchor=CENTER)
startmenu.menu = Menu(startmenu, tearoff=0)
startmenu["menu"] = startmenu.menu
startmenu.configure(font=("Arial", 8, "bold"))
startmenu.menu.add_command(label="Next Day", image = icons[4], compound = LEFT, command=hello)
startmenu.menu.add_separator()
startmenu.menu.add_command(label="Save", image = icons[2], compound = LEFT, command=hello)
startmenu.menu.add_command(label="Load", image = icons[3], compound = LEFT, command=hello)
startmenu.menu.add_separator()
startmenu.menu.add_command(label="Quit", image = icons[1], compound = LEFT, command=root.quit)
startmenu.menu.configure(font=("Arial", 8))
root.mainloop()
And here is what I get:
GUI
As you can see the menu "Floats" above the menu button instead of just being above it.
I am not sure of what causes that but I can't figure out how to fix it. I am sure it's something pretty simple but I am a beginner with Python....
Thanks in advance for your help.
The problem seems to be with putting the menu button on the absolute bottom. Here is near minimal code, with menu button one 'line' up from bottom, that works with 3.6 (tk 8.6) on Win10
import tkinter as tk
root = tk.Tk()
root.attributes('-fullscreen', 1)
tk.Button(root, text='Close', command=root.destroy).pack()
mb = tk.Menubutton(root, text='Menu', direction='above')
#mb.pack(side='bottom')
tk.Label(root, text='Filler2').pack(side='bottom')
mb.pack(side='bottom')
tk.Label(root, text='Filler1').pack(side='bottom')
menu = tk.Menu(mb, tearoff=0)
menu.add_command(label='Popup', command=lambda:print('hello'))
mb['menu'] = menu
Popup is on top of Filler1. Move the bottom down to the bottom (by commenting and uncommenting pack lines) and popup is in same place, leaving a gap. I tried using a ttk Menubutton instead and got the same behavior. I then went to the official Tk docs and discovered the 'flush' direction which puts the box 'over' the button. For tk, this means means 'on top of so as to cover the button'. For ttk, it means 'flush against the top, leaving the button exposed', which is what you want. So the solution, as least on Windows with tk 8.6 is to create the button with
mb = ttk.Menubutton(root, text='Menu', direction='flush')
I am making a simple GUI that starts with a main menu them the user can click a button to proceed to a new window which has a picture of a keyboard and the user can press key on their keyboard to play the paino. Right now I cant figure out how to make a button that when pressed closes the main menu (labeled mainMenu()) and open the game menu (playGame).
import tkinter
from tkinter import *
class mainMenu:
def _init_(self, master):
frame = Frame(master)
frame.pack()
self.quitButton = Button(frame, text = "Quit", command = frame.quit)
self.quitButton.pack(side = LEFT)
self.proceedButton = Button(frame, text = "Play", command = playGame)
self.proceedButton.pack(side = LEFT)
def playGame(self):
frame.quit
gameMenu()
def gameMenu(self):
root = Tk()
b = mainMenu(root)
topFrame = Frame(root)
topFrame.pack()
bottomFrame = Frame(root)
bottomeFrame.pack(side = BOTTOM)
photo = PhotoImage(file = "piano.png")
label = Label(root, image = photo)
label.pack()
root.mainloop()
You'll have to forgive me for removing your class but I've never personally worked with classes in python before. However I seem to have you code working to some degree.
import tkinter
from tkinter import *
def playGame():
frame.quit
gameMenu()
def gameMenu():
b = mainMenu(root)
topFrame = Frame(root)
topFrame.pack()
bottomFrame = Frame(root)
bottomFrame.pack(side = BOTTOM)
photo = PhotoImage(file = "piano.png")
label = Label(root, image = photo)
label.pack()
root=Tk()
frame = Frame(root)
frame.pack()
quitButton = Button(frame, text = "Quit", command = frame.quit)
quitButton.pack(side = LEFT)
proceedButton = Button(frame, text = "Play", command = playGame)
proceedButton.pack(side = LEFT)
root.mainloop()
The main problem you had was that you were using both root and master. When declaring the main window in tkinter you normally use either root = Tk() or master = Tk() either one is acceptable, personally I use master. This variable contains the main window that everything else is placed into. You also hadn't put Tk() into any variable, meaning that when you hit root.mainloop() there was nothing to enter the main loop, this was because you were trying to declare root = Tk() inside gameMenu, which wasn't getting called in your program.
If you want to open windows within tkinter it's probably easier to write something like this:
from tkinter import *
master = Tk() #Declaring of main window
def ProceedButtonCommand(mainframe, master): #Command to attach to proceed button
mainframe.destroy()
DrawSecondScreen(master) #This line is what lets the command tied to the button call up the second screen
def QuitButtonCommand(master):
master.destroy()
def DrawFirstScreen(master):
mainframe = Frame(master) #This is a way to semi-cheat when drawing new screens, destroying a frame below master frame clears everything from the screen without having to redraw the window, giving the illusion of one seamless transition
ProceedButton = Button(mainframe, text="Proceed", command=lambda: ProceedButtonCommand(mainframe, master)) #Lambda just allows you to pass variables with the command
QuitButton = Button(mainframe, text = "Quit", command=lambda: QuitButtonCommand(master))
mainframe.pack()
ProceedButton.pack()
QuitButton.pack()
def DrawSecondScreen(master):
mainframe = Frame(master)
Label1 = Label(mainframe, text="Temp")
mainframe.pack()
Label1.pack()
DrawFirstScreen(master)
master.mainloop() #The mainloop handles all the events that occur in a tkinter window, from button pressing to the commands that a button runs, very important
This little script just draws a screen with two buttons, one draws a new screen with the text "temp" on it and the other button closes the master window.
In the future it's probably a better idea to ask a friend who is experienced in programming to help with this kind of stuff. Get talking on some computing forums, I'm sure you'll find a group of sharing and fixing code quickly.