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.
Related
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()
It's pretty simple, I wish to show the value of the two dice combined in a "scorebox" somewhere in the GUI. I have tried to look everywhere, but can't come up with a simple solution anywhere. Anyone able to help a python noob? :)
(The code is copied from a YouTube tutorial, so not my code.)
import tkinter as tk
import random
#creating the GUI itself
root = tk.Tk()
root.geometry('600x400')
root.title('Roll Dice')
label = tk.Label(root, text='', font=('Helvetica', 260))
#dice function
def roll_dice():
dice = ['\u2680', '\u2681', '\u2682', '\u2683', '\u2684', '\u2685']
label.configure(text=f'{random.choice(dice)} {random.choice(dice)}')
label.pack()
#button to press to start rolling the dice
button = tk.Button(root, text='Roll Dice', foreground='black', command=roll_dice)
button.pack()
root.mainloop()
You can simply map the text inside a dictionary and then use indexing on the key to get the scores, and then just add the scores.
dice = {'\u2680':1, '\u2681':2, '\u2682':3, '\u2683':4, '\u2684':5, '\u2685':6}
scorebox = tk.Label(root, font=('Helvetica', 20)) # Make a scoresheet label
def roll_dice():
first,second = random.choice(list(dice)), random.choice(list(dice)) # Two random rolls
score_text = dice[first] + dice[second] # Corresponding texts
label.configure(text=f'{first} {second}') # Change the label
scorebox.configure(text=score_text)
label.pack()
scorebox.pack()
Why is the dictionary defined outside the function? So that it is just defined once and does not overwrite unnecessarily inside the function.
I would like to display some numbers, as fast as possible in Tkinter. The Program, I am trying to do, gets many numbers send and should show those.
Here is an similar environment, where tinter has to change a label very quickly.
from tkinter import *
import time
window = Tk()
lbl13 = Label(window, text="-")
lbl13.grid(column=0, row=0)
x = 0
while 1:
lbl13.config(text = str(x))
time.sleep(2)
x +=1
window.mainloop()
The Tkinter window doesn't even open on my computer. Is that because i have too weak hardware? What could I change that this Program also runs on my Computer. Thank you for every answer!
The infinite while loop will keep the program from getting to the line where you call window.mainloop(). You should call window.update() repeatedly instead of window.mainloop() at the end:
from tkinter import *
import time
window = Tk()
lbl13 = Label(window, text="-")
lbl13.grid(column=0, row=0)
x = 0
while 1:
lbl13.config(text = str(x))
window.update()
x +=1
Using after and a proper mainloop is probably a more more flexible way to achieve what you want; it is also reusable in different contexts, and can be used in an application that does more than trivially increment a number on a label:
maybe something like this:
import tkinter as tk
if __name__ == '__main__':
def increment():
var.set(var.get() + 1)
label.after(1, increment)
window = tk.Tk()
var = tk.IntVar(0)
label = tk.Label(window, textvariable=var)
label.pack()
increment()
window.mainloop()
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()
I'm relatively new to python, so please bear with me.
My question has two aspects:
First, I'm trying to make a GUI that randomly pops different sentences to the user, every time in a new frame.
Second, I want the user to be able to close the GUI without stopping the script, like if it was running in the background.
here is my code:
import Tkinter as tk
import random
number = random.randint(0,13)
sentence = {contains 13 sentences
}
window = tk.Tk()
window.output = tk.Label(text = sentence[number])
window.title("I Always See You")
window.geometry("300x150")
def next():
rand= random.randint(0, 13)
window2 = tk.Tk()
window2.output = tk.Label(text = sentence[rand])
window2.output.pack(side="top", fill="x", expand=True)
window2.title("I Always See You")
window2.geometry("300x150")
window.output.pack(side="top", fill="x", expand=True)
choice()
window.after(1000, next)
window.mainloop()
My problem: when my second frame pops, there isn't any text showing, and if it does have something popping, it appears in the first frame.
also, how can you insert a random float in .after() ?
Thank you so much for your help!
cheers
You do not see the text in the second window because Tkinter cannot handle two main windows. You need to use the Toplevel class for the others. In addition, you haven't specified the parent of the label in next, so it will probably be packed inside window instead of window2.
In addition, you need 14 sentences because randint, unlike randrange includes both end points.
To set a random time in after, just use randint because it expects an integer number of ms.
To achieve what you want I suggest you to create a main window that will be withdraw (it will run in the background). Then popup Toplevels with random sentences. You need to call again after inside the next function if you want the windows to keep poping up. To prevent the after to be cancelled if the user closes the Toplevel, I called the after method from the withdrawn main window:
import Tkinter as tk
import random
number = random.randint(0,13)
sentence = {i: str(i) for i in range(14)}
def next():
rand=random.randint(0, 13)
window2 = tk.Toplevel(root)
window2.output = tk.Label(window2, text=sentence[rand])
window2.output.pack(side="top", fill="x", expand=True)
window2.title("I Always See You")
window2.geometry("300x150")
tps = random.randint(1000, 10000)
root.after(tps, next)
root = tk.Tk()
root.withdraw() # hide root window
window = tk.Toplevel(root)
window.output = tk.Label(window, text=sentence[number])
window.title("I Always See You")
window.geometry("300x150")
window.output.pack(side="top", fill="x", expand=True)
tps = random.randint(1000, 10000)
root.after(tps, next)
root.mainloop()