Tkinter wit while loop (python 3) - python

First I created a window with some buttons and I defined their commands. It all works fine until I add the while loop to check if any button was pressed and then move to the next step. But then the window doesn't show up and the loop is running forever. I would also like to know if there is a better alternative to my code.
from tkinter import *
Round = 0
def blackC():
global Round
print ('0')
x = 0
Round += 1
def brownC():
global Round
print ('1')
x = 1
Round +=1
def redC():
global Round
print ('2')
x = 2
Round += 2
def win():
window = Tk()
window.geometry ('500x500')
window.title('HELLO')
blackB = Button(text = 'BLACK', command=blackC, width=7, height=3, bd=5)
blackB.place(x=1, y=1)
brownB = Button(text = 'BROWN', command=brownC, width=7, height=3, bd=5)
brownB.place(x=86, y=1)
redB = Button(text = 'RED', command=redC, width=7, height=3, bd=5)
redB.place(x=172, y=1)
window.mainloop()
while (Round == 0):
win()
while (Round < 3):
if (Round == 1):
y = x * 10
print ('y')
elif (Round == 2):
y += x
print ('y')

I don't know what exactly you mean by moving to the next step, but you definitely misunderstand how tkninter works. You are missing the parenthesis in the mainloop window.mainloop().
And you don't want to call it in the cycle, because mainloop is a function which is cycle. So you just run it once a time a then it runs infinitely. So your code have to just run once a time function win().
from tkinter import *
Round=0
def button(type):
global Round
print (str(type))
x = type
Round += type
def win():
window = Tk()
window.geometry ('500x500')
window.title('HELLO')
blackB = Button(text = 'BLACK', command=lambda: button(0), width=7, height=3, bd=5)
blackB.place(x=1, y=1)
brownB = Button(text = 'BROWN', command=lambda: button(1), width=7, height=3, bd=5)
brownB.place(x=86, y=1)
redB = Button(text = 'RED', command=lambda: button(2), width=7, height=3, bd=5)
redB.place(x=172, y=1)
window.mainloop
win()
You have asked for better code, so I have rewritten your buttons func for a one, which just takes an parametr of type and call it as a lambda function (take a look: http://www.diveintopython.net/power_of_introspection/lambda_functions.html.
For a larger projects it is better to have tkinter window as a class, but in this is it enough.

Related

Tkinter while loop guess game

# Tkinter guessing game
from tkinter import *
import random
window = Tk()
# Bot Generator
bot = random.randint(1, 20+1)
print(bot)
def submit():
tries = 5
while tries >= 0:
e1 = (int(guessE.get()))
if e1 == bot:
print("You win")
break
elif e1 != bot:
print("Try again")
tries -= 1
break
def clear():
guessE.delete(0, "end")
# Guess Label
guessL = Label(window, text="Guess a number (between 1 and 20}")
guessL.place(x=75, y=50)
# Guess Entry
guessE = Entry(window, width=25, bg="lightgrey")
guessE.place(x=95, y= 80)
# Submit Button
submitBtn = Button(window, width=10, height=2, text="Submit", command=submit)
submitBtn.place(x=85, y=115)
# Clear Button
clearBtn = Button(window, width=10, height=2, text="Clear", command=clear)
clearBtn.place(x=175, y=115)
window.geometry("350x350")
window.resizable(0, 0)
window.attributes("-topmost", True)
window.mainloop()
I am trying to create a guessing game with Tkinter, I have created all the entries and labels, the clear button is working. I am struggling with creating a while loop, I need the program to stop accepting submitted entries once 5 tries have been used. Any ideas on how I can solve this?
Like already mentioned by #Paul Rooney, i also think that a while loop is a bad design for this. However, here is a working example with a global variable and some minor changes (disabling entry and button when 0 tries are reached):
# Tkinter guessing game
from tkinter import *
import random
window = Tk()
# Bot Generator
bot = random.randint(1, 20+1)
print(bot)
# define outside of function to not overwrite each time
tries = 5
def submit():
global tries # to make tries a global variable
while tries > 0: # this matches your tries amount correctly
e1 = (int(guessE.get()))
if e1 == bot:
print("You win")
break
elif e1 != bot:
print("Try again")
tries -= 1
break
# print status, disable the widgets
if tries == 0:
print("No more tries left")
guessE.configure(state="disabled")
submitBtn.configure(state="disabled")
def clear():
guessE.delete(0, "end")
# Guess Label
guessL = Label(window, text="Guess a number (between 1 and 20}")
guessL.place(x=75, y=50)
# Guess Entry
guessE = Entry(window, width=25, bg="lightgrey")
guessE.place(x=95, y= 80)
# Submit Button
submitBtn = Button(window, width=10, height=2, text="Submit", command=submit)
submitBtn.place(x=85, y=115)
# Clear Button
clearBtn = Button(window, width=10, height=2, text="Clear", command=clear)
clearBtn.place(x=175, y=115)
window.geometry("350x350")
window.resizable(0, 0)
window.attributes("-topmost", True)
window.mainloop()

after_cancel doesn't work in python tkinter

I made a simple countdown in my trivia game and every time that I go to the next slide it doesn't cancel the previous countdown timer and overlaps with the previous one.
I searched about that on the web and found the after_cancel function that cancels the timer after I go to the next slide and then I recreate it. But it still overlaps even after I added this function.
I think that I didn't give the after_cancel the correct arguments.
from tkinter import *
window = Tk()
window.attributes('-fullscreen',True)
WaitState = StringVar()
count = 10
button_label = StringVar()
def clear():
WaitState.set(1)
for widgets in window.winfo_children():
widgets.destroy()
def clear_time():
clear()
time_up_label = Label(
window,
text="Time is up",
bg = "#6378ff",
fg="#000000",
font=("Arial", 100,"bold"))
time_up_label.place(relx = 0.5,rely = 0.5,anchor = 'center')
continue_but = Button(
window,
text="Continue",
font=("Knewave",25,"bold"),
bg="#942222",
width=11,
height=5,
command=clear)
continue_but.place(relx = 1.0,rely = 1.0,anchor =SE)
continue_but.wait_variable(WaitState)
def button_countdown(i, label):
if i > 0:
i -= 1
label.set(i)
window.after_id = window.after(1000, lambda: button_countdown(i, label))
else:
window.after_cancel(window.after_id)
clear_time()
for index in range(5):
continue_but = Button(
window,
text="Continue",
font=("Knewave",25,"bold"),
bg="#942222",
width=11,
height=5,
command=clear)
continue_but.place(relx = 1.0,rely = 1.0,anchor =SE)
button_label.set(count)
timer_label = Label(
window,
textvariable=button_label,
bg="#6378ff",
fg="#ff0000",
font=("Arial",46,"bold"))
timer_label.pack()
button_countdown(count, button_label)
continue_but.wait_variable(WaitState)
window.mainloop()

When I click on button 2 after pressing on button 1 it does not work

When I click on button 2 after pressing on button 1 it does not work.
I am making an auto clicker for fun, as a side project.
import tkinter as tk
from pynput.mouse import Button, Controller
import time
Height = 700
Width = 800
mouse = Controller()
flag = True
def click_function():
while flag == True:
time.sleep(.001)
mouse.click(Button.left, 1)
def endclick_function():
flag = False
root = tk.Tk()
canvas = tk.Canvas(root, height=Height, width=Width)
canvas.pack()
frame = tk.Frame(root,bg='black')
frame.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.5)
button = tk.Button(frame, text="Start" , bg='white', fg='black', font=50, command=click_function)
button.place(relx=0, rely=0, relwidth=0.5, relheight=0.5)
button2 = tk.Button(frame, text="Stop" , bg='white', fg='black', font=50, command=lambda: endclick_function)
button2.place(relx=.5, rely=0, relwidth=0.5, relheight=0.5)
label = tk.Label(frame, text='Time to Sleep:', bg='white', font=50)
label.place(relx=0, rely =0.5, relwidth=0.5, relheight=0.25)
label2 = tk.Label(frame, text='How many times to click:', bg='white', font=50)
label2.place(relx=0, rely =0.75, relwidth=0.5, relheight=0.25)
entry = tk.Entry(frame, bg='white')
entry.place(relx=0.5, rely =0.5, relwidth=0.5, relheight=0.25)
entry2 = tk.Entry(frame,text='Time to Sleep(ms):', bg='white')
entry2.place(relx=0.5, rely =0.75, relwidth=0.5, relheight=0.25)
root.mainloop()
you have to declare flag global if you want to change it
also as Joe Ferndz pointed out, the flag is never set back to True
def click_function():
global flag
flag = True # of course, only if you want to use clicker more than once
while flag == True:
time.sleep(.001)
mouse.click(Button.left, 1)
def endclick_function():
global flag
flag = False
Something I just noticed
in button2, command=lambda:end_f
remove lambda
this is basically saying
def l():
return end_f
button2['command'] = l
and since the command (l) is executed at the click on the button,
it only returns the function, does not execute it
When you click the first button, the flag is set to True. However, when you click on second button, the flag gets set to False. Later when you come back to first button, the flag is False so it never goes into the while loop.
Do you want to try and implement this an alternate way?
def click_function():
while flag == True:
time.sleep(.001)
mouse.click(Button.left, 1)
def endclick_function():
flag = False

How to change colour for each sorting algorithms step in tkinter

This is my main code that creates a GUI. The user can enter the numbers or generate random numbers and it will sort it. However, i want it to change colour with each step taken in the sorting algorithm, and then change to a green colour once the array has been sorted.
import random
from tkinter import *
import Swap
numberArray = list()
def arrayList(number):
arrayListEntry.delete(0, END)
numberArray.append(number)
e.config(text=str(numberArray))
print numberArray
def randomiser():
for i in range(10):
numberArray.append(random.randint(1,100))
e.config(text=str(numberArray))
print numberArray
# Main selection sort function
def selectionSort(numberList):
for i in range(len(numberList)):
minimumIndex = i
print("\nMinimum index: " + str(minimumIndex))
for l in range(i + 1, len(numberList)):
if numberList[minimumIndex] > numberList[l]:
minimumIndex = l
print(numberArray)
Swap.startSwap(numberList, i, minimumIndex)
e.config(text=str(numberArray))
root.update()
root.after(1000)
e.config(text=str(numberArray))
width = 300
height = 250
root = Tk()
frame = Frame(root, width=width, height=height)
frame.grid(row=3, column=0, columnspan=3)
e = Label(root, text="Arraylist")
e.grid(row=1, column=1)
arrayListLabel = Label(root, text="Array List")
arrayListEntry = Entry(root)
arrayListButton = Button(root, text="Enter", command=lambda: arrayList(arrayListEntry.get()))
arrayListButton.grid(row=0, column=3)
sortButton = Button(root, text="Sort", command=lambda: selectionSort(numberArray))
sortButton.grid(row=2, column=1)
randomButton = Button(root, text="Randomise", command=lambda: randomiser())
randomButton.grid(row=3, column=1)
arrayListLabel.grid(row=0, column=0)
arrayListEntry.grid(row=0, column=1)
root.mainloop()
This is my swap method in another class, ignore the last line as that is only for the console for me to see what is happening
# Swap function for swaping the index in the array
def startSwap(array, firstIndex, secondIndex):
swapObject = array[firstIndex]
array[firstIndex] = array[secondIndex]
array[secondIndex] = swapObject
print("Number " + str(array[firstIndex]) + " swapped with number " + str(array[secondIndex]) + " in array\n")
I removed the frame widget as it was complicating the task of changing the color of the entire background.
I made the following changes inside the startSwap() function to change the colors at every step of the algorithm
First I created a list of color names:
colors = ['red', 'blue', 'orange', 'yellow']
Next, I randomly set the foreground color from the colors list. You can add other colors to increase randomness of color selection.
e.config(fg=random.choice(colors))
Finally when the the list of numbers are sorted, set the foreground color to green inside of the selectionSort() function
e.config(fg='green')
Here's the entire working code:
import random
from tkinter import *
#import Swap
root = Tk()
# define label before using it
e = Label(root, text="Arraylist")
e.grid(row=1, column=1, padx=10, pady=10)
numberArray = list()
def arrayList(number):
arrayListEntry.delete(0, END)
numberArray.append(number)
e.config(text=str(numberArray))
#print numberArray
def randomiser():
for i in range(10):
numberArray.append(random.randint(1,100))
e.config(text=str(numberArray))
#print numberArray
def startSwap(array, firstIndex, secondIndex):
# color list
colors = ['red', 'blue', 'orange']
# set a random color from the colors list
e.config(fg=random.choice(colors))
swapObject = array[firstIndex]
array[firstIndex] = array[secondIndex]
array[secondIndex] = swapObject
# Main selection sort function
def selectionSort(numberList):
for i in range(len(numberList)):
minimumIndex = i
for l in range(i + 1, len(numberList)):
if numberList[minimumIndex] > numberList[l]:
minimumIndex = l
#Swap.startSwap(numberList, i, minimumIndex)
startSwap(numberList, i, minimumIndex)
e.config(text=str(numberArray))
root.update()
root.after(1000)
e.config(text=str(numberArray))
# once numbers are sorted, set foreground as green
e.config(fg='green')
arrayListLabel = Label(root, text="Array List")
arrayListEntry = Entry(root)
arrayListButton = Button(root, text="Enter", command=lambda: arrayList(arrayListEntry.get()))
arrayListButton.grid(row=0, column=3, padx=10, pady=10)
sortButton = Button(root, text="Sort", command=lambda: selectionSort(numberArray))
sortButton.grid(row=2, column=1, pady=10)
randomButton = Button(root, text="Randomise", command=lambda: randomiser())
randomButton.grid(row=3, column=1, pady=10)
arrayListLabel.grid(row=0, column=0, padx=10, pady=10)
arrayListEntry.grid(row=0, column=1)
root.mainloop()
Lastly, I added some padding to the Label and Button widgets.

Tkinter StringVar() only accepts the most recent input

I'm trying to make a small application that displays words from a list one-by-one. Below is my code:
from Tkinter import *
master = Tk()
master.title('Serial Position Effect')
myArray = ['book','chair','door']
def cycle(myArray, k):
t.set(myArray[k])
t = StringVar()
w = Label(master, height=3, width=15, font=('Helvetica', 118), textvariable = t)
for n in range(0,3):
cycle(myArray, n)
w.pack()
master.mainloop()
I was expecting the label to show book, chair, and door, but it only showed door on the window. I tried to modify the for loop like:
for n in range(0,3):
for x in range(0,10000):
cycle(myArray, n)
Because I thought the problem was that the program was cycling through the words too quickly. But with this modified code, the application, again, only showed door after a short delay. (The delay was probably because it was counting up to 10000.)
Finally I approached this a little differently - a little less efficient but I thought by coding it like this I would be able to identify the problem in my original code:
from Tkinter import *
master = Tk()
master.title('Serial Position Effect')
#myArray = ['book','chair','door']
#def cycle(myArray, k):
# t.set(myArray[k])
t = StringVar()
w = Label(master, height=3, width=15, font=('Helvetica', 118), textvariable = t)
for n in range(0,10000)
t.set('book')
for n in range(0,10000)
t.set('chair')
for n in range(0,10000)
t.set('door')
w.pack()
master.mainloop()
Again, the window only displayed door.
I'm new to GUI programming with Python and Tkinter. I would really appreciate it if someone could help me out with this issue.
Thanks (=
The window won't even show up until you call mainloop, so calling set thousands of times won't have any visible effect, except for the very last call. You should use after to register callback functions that change the label some seconds in the future.
from Tkinter import *
master = Tk()
master.title('Serial Position Effect')
myArray = ['book','chair','door']
def cycle(myArray, k):
t.set(myArray[k])
t = StringVar()
w = Label(master, height=3, width=15, font=('Helvetica', 118), textvariable = t)
w.pack()
cycle(myArray,0)
master.after(1000, lambda: cycle(myArray, 1))
master.after(2000, lambda: cycle(myArray, 2))
master.mainloop()
You can also have the after-registered function call after itself, if you want the words to cycle forever.
from Tkinter import *
master = Tk()
master.title('Serial Position Effect')
myArray = ['book','chair','door']
cur_idx = -1
def cycle():
global cur_idx
cur_idx = (cur_idx + 1) % len(myArray)
t.set(myArray[cur_idx])
master.after(1000, cycle)
t = StringVar()
w = Label(master, height=3, width=15, font=('Helvetica', 118), textvariable = t)
w.pack()
cycle()
master.mainloop()

Categories

Resources