How do you create a streamlined gui in python using multiple function? - python

I am trying to create a gui which would for example end the program once the user clicks a button, however, since the main portion of the program is located in the main() function, I cannot find a way to to end the program inside another function.
This is my code:
import turtle
import random
from tkinter import *
from tkinter import messagebox
def main():
windowScreen = Tk()
windowScreen.title("Our cinema Application!")
lbl = Label(windowScreen, text="Welcome to our cinema Application!",font=("Arial bold",50))
lbl.grid(column=0,row=0)
btn1 = Button(windowScreen, text="View Available Movie", bg="green", )
btn1.grid(column=0,row=1)
btn2 = Button(windowScreen, text="Purchase Tickets", bg="green", command=movie)
btn2.grid(column=0,row=2)
btn3 = Button(windowScreen, text="Exit the Application", bg="red", command=action1, activebackground="white")
btn3.grid(column=0,row=3)
windowScreen.mainloop()
print("Welcome to Dan & Fred's Cinema!")
def action1():
messagebox.showinfo("Exit Application","Thank you for visiting and come again!")
mainloop().exitonclick()
exit()

Your program is almost correct, just remove mainloop().exitonclick().
exitonclick is a function of turtle and would be used to close turle window, so it wont have any effect on tkinter window.
You can either make windowScreen a global variable (as #Tim Robert suggested) and add windowScreen.destroy() in action1 function or have a nested function to achive the same.
Using nested function, your code would look like this:
def main():
def action1():
messagebox.showinfo("Exit Application","Thank you for visiting and come again!")
windowScreen.destroy()
windowScreen = Tk()
windowScreen.title("Our cinema Application!")
btn3 = Button(windowScreen, text="Exit the Application", bg="red", command=action1, activebackground="white")
btn3.grid(column=0,row=3)
windowScreen.mainloop()

Related

Trying to use a function to destroy tkinter frame that was created in another function. Unsuccessfully

I'm very new to python programming and I've been unable to find out how to get this to function properly. I'm using frames to show a login screen prior to loading the main inventory frame. I intend to record changes to inventory per user, so this is necessary for the program to function properly.
The program calls the Loginscreen() and LoginFrameGenerate() functions to generate the top menu and the frame including labels and entry fields. (Using Tkinter)
The "Log In" button, once pressed, calls the loginfun() function.
The loginfun() function is supposed to use an if statement to check the username and password and if they are correct, remove the login screen frame. Once the login screen frame has been removed, the mainframe and menu functions are called.
Unfortunately, the login screen frame will not go away when using the destroy() command. I can't move forward until I can get this working. Any guidance would be greatly appreciated.
I tried the function without re-initializing the frame inside the loginfun() function, but it generates a name error. I no longer get the name error, but the frame doesn't get destroyed. I've searched google and stack overflow for hours and the only thing I could find regarding Tkinter destroy() was in reference to classes. I'm beginning to think I've been coding this wrong and I should have made each frame a separate class.
from tkinter import *
import tkinter.messagebox
import sys
root = Tk()
root.iconbitmap('Favicon.ico')
testusername = "Admin"
testpassword = "Pass"
CurrentUser = StringVar()
Pass = StringVar()
root.state("zoomed")
def Exitbtnclick():
sys.exit(0)
def logout():
MainFrame=Frame(root)
MainFrame.destroy()
loginScreen
loginFrameGenerate
def loginScreen():
loginMenu = Menu(root)
root.configure(menu=loginMenu)
FileMenu=Menu(loginMenu)
loginMenu.add_cascade(label="File", menu=FileMenu)
FileMenu.add_cascade(label="Exit",command=Exitbtnclick)
def loginFrameGenerate():
#THIS CREATES THE LOGIN FRAME
logframe = Frame(root)
logframe.grid()
UL = Label(logframe, text="Username:", font="Arial 10 bold")
UL.grid(row=0, column=0, sticky="E")
UE = Entry(logframe, textvariable=CurrentUser)
UE.grid(row=0,column=1)
PL = Label(logframe, text="Password:", font="Arial 10 bold")
PL.grid(row=1, column=0, sticky="E")
PE = Entry(logframe, textvariable=Pass)
PE.grid(row=1,column=1)
loginbtn = Button(logframe, text="Log In", command=loginfun)
loginbtn.grid(row=3,columnspan=2)
def loginfun():
#THIS FUNCTION IS CALLED WHEN THE "LOG IN" BUTTON IS PRESSED
global testusername
global testpassword
logframe = Frame(root)
if (CurrentUser.get() == testusername) and (Pass.get() == testpassword):
logframe.destroy() #THIS IS THE PART THAT DOES NOT WORK
initializeMainMenu
initializeMainFrame
else:
tkinter.messagebox.showinfo("Error!", "Invalid Username/Password")
return
def initializeMainMenu():
mainMenu = Menu(root)
root.configure(menu=mainMenu)
FileMenu = Menu(mainMenu)
UserMenu = Menu(mainMenu)
ItemsMenu = Menu(mainMenu)
ReportMenu = Menu(mainMenu)
mainMenu.add_cascade(label="File", menu=FileMenu)
mainMenu.add_cascade(label="Users", menu=UserMenu)
mainMenu.add_cascade(label="Items", menu=ItemsMenu)
mainMenu.add_cascade(label="Reports", menu=ReportMenu)
FileMenu.add_separator()
FileMenu.add_command(label="Log Out/Switch User", command=logout)
FileMenu.add_command(label="Exit", command=Exitbtnclick)
UserMenu.add_command(label="Add/Remove Users",command=random)
def initializeMainFrame():
##Main Inventory Screen To Be Filled in once the user is logged in
MainFrame = Frame(root)
MainFrame.grid()
loginScreen()
loginFrameGenerate()
root.mainloop()

How to add a reset button that clears my code?

I'm making a basic TicTacToe UI in python, and I believe that a fundamental item to this code is a reset button which resets your codes back to the default. is there any other way to do this?
I've Tried to define a function which resets the text of the button back to " " but I don't think that's a great idea because of a lot of other complexities within the cod.
from tkinter import *
root = Tk()
def changetext():
BTN1["text"] = "X"
BTN1 = Button(root, text=" ", command=changetext)
BTN1.pack()
root.mainloop()
So I want to add a button here that says "Reset Text" and it resets all the codes to defaults.
The easiest way to reset the game would be to
Reset the UI as you suggest, with a single dedicated reset_UI() function
Reset the board state by creating a new game board object, and discarding the old one
This of course means that you'll need to wrap all your variables and functions in a board class Board, so that there aren't a billion global variables you have to worry about resetting. The only thing that should persist between resets are your UI buttons, which can be created in your main() function before initializing the game board.
Here's code demonstrating how something like that could be done (plus a few other things):
import tkinter as tk
def toggle(btn):
if btn["text"] == "X":
btn["text"] = " "
else:
btn["text"] = "X"
def reset(buttons):
for btn in buttons.values():
btn["text"] = " "
root = tk.Tk()
buttons = {}
for row in range(3):
for col in range(3):
button = tk.Button(root, text=" ", width=1, height=1)
button.config(command=lambda btn=button: toggle(btn))
button.grid(row=row, column=col)
buttons[row, col] = button
reset_button = tk.Button(root, text="Reset", command=lambda: reset(buttons))
reset_button.grid(columnspan=3)
root.mainloop()

Problem with calling functions with tkinter

from tkinter import *
from random import *
root = Tk()
#A function to create the turn for the current player. The current player isnt in this code as it is not important
def turn():
window = Tk()
dice = Button(window, text="Roll the dice!", bg= "white", command=lambda:diceAction(window))
dice.pack()
window.mainloop()
#a function to simulate a dice. It kills the function turn.
def diceAction(window):
result = Tk()
y = randint(1, 6)
quitButton = Button(result, text="Ok!", bg="white", command=result.destroy)
quitButton.pack()
window.destroy()
result.mainloop()
#A function to create the playing field and to start the game
def main():
label1 = Button(root, text="hi", bg="black")
label1.pack()
while 1:
turn()
print("Hi")
turn()
main()
root.mainloop()
My problem is that the code in the while function after the first turn() the code isnt executed until i close the root window(which i dont want because it represents the playing field). You can copy this code and execute it yourself if you want.
I have no idea what causes this and havent found anything online. Sorry for the long code but i wrote it so that it is executeable.
I don't know why this particular problem is occurring, but there are a couple of things in your code that are considered bad practice.
Instead of creating multiple instances of Tk(), you should use Toplevel widgets for any pop-up windows needed. Also, it's better to use root.mainloop() to run the program rather than a while loop.
I've made some edits to your code so that it uses a Toplevel widget and discards of the while loop.
from tkinter import *
from random import *
#A function to create the turn for the current player. The current player isnt in this code as it is not important
def turn(prev=None):
# destroy the previous turn
if prev:
prev.destroy()
# pop up with dice
window = Toplevel()
dice = Button(window, text="Roll the dice!", bg= "white")
dice.config(command=lambda b=dice, w=window:diceAction(b, w))
dice.pack()
#a function to simulate a dice, reconfigures the pop-up
def diceAction(button, window):
# roll dice
y = randint(1, 6)
# use dice result here?
print(y)
# reconfigure button, the command now starts a new turn
button.config(text='ok', command=lambda w=window:turn(prev=w))
root = Tk()
# I hijacked this button to use as a start button
label1 = Button(root, text="hi", bg="black", command=turn)
label1.pack()
root.mainloop()
I don't know if this is what you need, but it functions as the code in the question would if it worked.
Sorry I couldn't help with the cause of the error.

Problems with 2 different GUI windows

So my first GUI window is meant for taking input from user :
from tkinter import *
from main import *
root = Tk()
root.configure(background="orange")
root.wm_title("Python Project")
label_1 = Label(root, text="Project Name",bg="orange",fg="black")
label_2 = Label(root, text="Site URL Link",bg="orange",fg="black")
entry_1 = Entry(root)
entry_2 = Entry(root)
label_1.grid(row=0,sticky=W)
label_2.grid(row=3333,sticky=W)
entry_1.grid(row=0,column=1,padx=50,ipadx=100)
entry_2.grid(row=3333,column=1,ipadx=100)
def callback():
a1 = entry_1.get()
a2 = entry_2.get()
mmm(a1,a2,root) # main program
button1 = Button(root,text="Run",command=callback)
button2=Button(root,text="Quit",command=root.quit)
button1.grid(row=3334,ipadx=15,padx=50,column=1)
button2.grid(row=3335,column=1,ipadx=15,padx=50)
root.mainloop()
And then i use another GUI window someone in this forum made to show my results :
from tkinter import *
root = Tk()
textbox = Text(root)
textbox.pack()
def redirector(inputStr):
textbox.insert(INSERT, inputStr)
sys.stdout.write = redirector # whenever sys.stdout.write is called, redirector is called.
sys.stderr.write = redirector
root.mainloop()
Now every time i run the first GUI , both GUIs open although there is no way the code reached the second GUI code yet... What is the problem here?
Also the second GUI is supposed to print from a class , but i have a bunch of error when I try to just put it there . What changes I need to make so I can make this 2nd GUI work with a class?

Using the variable from entry/button in another function in Tkinter

When I press the button, I want it to get the Entry and -for future things- use it in another function.
import tkinter
def ButtonAction():
MyEntry = ent.get() #this is the variable I wanna use in another function
den = tkinter.Tk()
den.title("Widget Example")
lbl = tkinter.Label(den, text="Write Something")
ent = tkinter.Entry(den)
btn = tkinter.Button(den, text="Get That Something", command = ButtonAction )
lbl.pack()
ent.pack()
btn.pack()
den.mainloop()
print MyEntry #something like this maybe. That's for just example
I will use this thing as a search tool. Entry window will appear, get that "entry" from there and search it in files like:
if MyEntry in files:
#do smth
I know I can handle the problem with using globals but from what I've read it's not recommended as a first solution.
Structure the program using class.
import tkinter
class Prompt:
def button_action(self):
self.my_entry = self.ent.get() #this is the variable I wanna use in another function
def __init__(self, den):
self.lbl = tkinter.Label(den, text="Write Something")
self.ent = tkinter.Entry(den)
self.btn = tkinter.Button(den, text="Get That Something", command=self.button_action)
self.lbl.pack()
self.ent.pack()
self.btn.pack()
den = tkinter.Tk()
den.title("Widget Example")
prompt = Prompt(den)
den.mainloop()
You can access the input using prompt.my_entry later.

Categories