I'm trying to make Tic Tac Toe in python using tkinter, but I'm running into an issue. I'm trying to make it so when you click on one of the squares, it displays whichever player's symbol on that square. However, with my current function playerCheck, nothing happens when I press them. I can't figure out why this is happening, so I would appreciate any help.
Keep in mind I am in no way finished.
import tkinter as tk
Player1 = "X"
Player2 = "O"
turn = None
playerNumber = None
def playerCheck(function):
if turn == Player1:
playerNumber = Player1
function("white", playerNumber)
elif turn == Player2:
playerNumber = Player2
function("white", playerNumber)
def topLeft(color, player):
topL = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(topL)).grid(row=0,column=0)
def topMiddle(color, player):
topM = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(topMiddle)).grid(row=0,column=1)
def topRight(color, player):
topR = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(topRight)).grid(row=0,column=2)
def middleLeft(color, player):
midL = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(middleLeft)).grid(row=1,column=0)
def middleMiddle(color, player):
midM = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(middleMiddle)).grid(row=1,column=1)
def middleRight(color, player):
midR = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(middleRight)).grid(row=1,column=2)
def bottomLeft(color, player):
botL = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(bottomLeft)).grid(row=2,column=0)
def bottomMiddle(color, player):
botM = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(bottomMiddle)).grid(row=2,column=1)
def bottomRight(color, player):
botR = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(bottomRight)).grid(row=2,column=2)
def gameStart():
topLeft("white", "")
topMiddle("white", "")
topRight("white", "")
middleLeft("white", "")
middleMiddle("white", "")
middleRight("white", "")
bottomLeft("white", "")
bottomMiddle("white", "")
bottomRight("white", "")
turn = Player1
def Main():
a = tk.Tk()
a.title("Tick Tack Toe")
a.geometry("250x250")
gameStart()
a.mainloop()
Main()
The argument to playerCheck() is a button, not a function. You should change the button's text and color, not try to call it.
def playerCheck(button):
global turn
button['text'] = turn
button['fg'] = "white"
if turn == Player1:
turn = Player2
else:
turn = Player1
Here is an example of a completely working tic-tac-toe made with tkinter. I used your Button approach. If you are going to make anything with tkinter it should look a lot more like the below code. I commented it all over the place to give you a bit of a guide to what everything is doing, but I did not dumb down the code. Some parts may be very hard for you to understand (like the logic in win_or_block()). That's a good thing. It will force you to research and get better.
tips:
Learn how to create and use classes, so you can separate and organize your code into meaningful chunks.
Your approach is to manually define each individual thing, even if they are the exact same thing. You should consider a more dynamic approach where you create something once and let a loop create and position a bunch of copies/instances of it.
If your code was written properly, according to the design that you laid out, you would technically have a Button that recreates itself when it is clicked. This type of circular logic is bad.
Worry less about Buttons and more about game logic. Your graphics should simply express a condition. You're on your way to making the graphics serve as the logic behind your conditions, and that is a terrible approach.
#python 3.8+
from tkinter import Tk, Frame, Button, Entry, StringVar, IntVar, Checkbutton
from statistics import mean
from random import choice
class Splash(Frame):
WIDTH = 300
HEIGHT = 190
def __init__(self, master, callback, *args, **kwargs):
Frame.__init__(self, master, *args, **kwargs)
self.callback = callback
self.message = StringVar()
self.tricky = IntVar()
#just to make some lines shorter
e = dict(font='calibri 18 bold', bg=self['bg'], border=0, justify='center', textvariable=self.message)
b = dict(font='calibri 18 bold', bg='black', fg='white')
c = dict(font='calibri 16 bold', bg=self['bg'])
Entry(self, **e).place(width=280, height=40, x=10, y=5)
Checkbutton(self, text="tricky", variable=self.tricky, **c).place(width=200, height=30, x=50, y=50)
Button(self, text='1 Player' , command=lambda: self.remove(True) , **b).place(width=200, height=45, x=50, y=90)
Button(self, text='2 Players', command=lambda: self.remove(False), **b).place(width=200, height=45, x=50, y=140)
def remove(self, auto):
self.place_forget()
self.callback(auto)
class Board(Frame):
#if you change this you need to change the font size in self.default_cell and vise-versa
WIDTH = 450
HEIGHT = 393
def __init__(self, master, callback, *args, **kwargs):
Frame.__init__(self, master, *args, **kwargs)
#cell default properties
self.default_cell = dict(
foreground = 'black',
background = 'black',
activebackground = 'black',
disabledforeground = 'black',
text = "",
font = "consolas 48 bold",
relief = 'sunken',
state = 'normal',
width = 4,
height = 1,
)
#make board
for i in range(9):
cell = Button(self, **self.default_cell)
cell.config(command=lambda c=cell, i=i: callback(c, i))
cell.grid(row=int(i//3), column=i%3, sticky='nswe')
def reset(self):
for cell in self.winfo_children():
cell.config(**self.default_cell)
#used to stop cell clicks while splash screen is visible
def lock(self):
for cell in self.winfo_children():
cell.config(state='disabled')
class Game(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
#current player
self.player = 0
#True: against computer - False: against 2nd human
self.auto = False
#stores moves
self.moves = [0]*9
#player colors
self.color = ['red', 'green']
# [crossed swords, flag outline]
self.marks = [chr(9876), chr(9872)]
#positions
self.edge = {1, 7, 3, 5}
self.corner = {0, 6, 2, 8}
#True = hard | False = easy
self.tricky = True
'''
numbers that can't average together with 0 to equal each other
where [n, n, n] is any given winning combination in tic-tac-toe
consider the mean of: [1, 2, 0] vs [1, 1, 1]
against the mean of: [1, 4, 0] vs [1, 1, 1]
'''
self.pids = [1, 4]
#init board
self.board = Board(self, self.move)
self.board.grid(row=0, column=0, sticky='nswe')
#init "game over" screen and place() properties
self.splash = Splash(self, callback=self.reset, bg='gray92')
self.splashprops = dict(
x = (Board.WIDTH-Splash.WIDTH)/2,
y = (Board.HEIGHT-Splash.HEIGHT)/2,
width = Splash.WIDTH,
height = Splash.HEIGHT
)
self.show_splash("Connect 3 And Conquer")
'''
This method is tricky. It is used to check:
1: if the current player has won (id=current_id, n=4)
2: if the computer can win (id=player2_id, n=3)
3: if the computer can block a win (id=player1_id, n=3)
'''
def win_or_block(self, id, n=3):
best = -1
try:
for a in range(3):
#vertical
m = self.moves[a::3]
l = list(filter(lambda i: i>0, m))+[id]
if len(l) == n and mean(l) == id:
best = (m.index(0) * 3) + a
break
#horizontal
m = self.moves[a*3:a*3+3]
l = list(filter(lambda i: i>0, m))+[id]
if len(l) == n and mean(l) == id:
best = m.index(0) + (a * 3)
break
#back slash
if best < 0:
m = self.moves[0::4]
l = list(filter(lambda i: i>0, m))+[id]
if len(l) == n and mean(l) == id:
best = m.index(0) * 4
#forward slash
if best < 0:
m = self.moves[2::2][0:3]
l = list(filter(lambda i: i>0, m))+[id]
if len(l) == n and mean(l) == id:
best = (m.index(0) + 1) * 2
except ValueError:
#m.index(0) does not exist, current player has won
best = 0
return best
def best(self, index):
best = -1
#computer checks if it can win, and if not, then if it can block
for i in range(1, -1, -1):
best = self.win_or_block(self.pids[i])
if best > -1:
break
#if the computer cannot win or there is nothing to block
if best < 0:
avail = {i for i, v in enumerate(self.moves) if v == 0}
c = list(self.corner.intersection(avail)) #corners
e = list(self.edge.intersection(avail)) #edges
#choose the middle or mirror opposite of the last move
if self.tricky:
b = 4 if 4 in avail else abs(index - 8)
if b in avail:
best = b
#attempt a random choice in this order: corner, center, edge
if best < 0:
if len(c):
best = choice(c)
elif 4 in avail:
best = 4
else:
best = choice(e)
return best
def move(self, button, index):
#mark the square
button.config(bg=self.color[self.player], text=self.marks[self.player], state='disabled')
#record the move
self.moves[index] = self.pids[self.player]
#game over screens
if self.win_or_block(self.pids[self.player], 4) > -1: #check win
self.show_splash(f'Player {self.player+1} Has Conquered!')
return
elif self.moves.count(0) == 0: #check "no more moves"
self.show_splash('Stalemate!')
return
#derive next player ~ Player1 = 0, Player2 = 1
self.player = (self.player + 1)%2
if self.auto and self.player == 1:
#invoke the button with the child index that corresponds to the "best" move
self.board.winfo_children()[self.best(index)].invoke()
def show_splash(self, msg):
self.board.lock()
self.splash.message.set(msg)
self.splash.place(**self.splashprops)
def reset(self, auto):
self.tricky = bool(self.splash.tricky.get())
self.auto = auto
self.player = 0
self.moves = [0]*9
self.board.reset()
if __name__ == '__main__':
app = Game()
app.title("Connect 3 And Conquer")
#lock down the window size
app.minsize(Board.WIDTH, Board.HEIGHT)
app.maxsize(Board.WIDTH, Board.HEIGHT)
app.mainloop()
aside:
I understand you are new. Don't take my criticisms to heart. The point is to make you better. Anybody could come in here and tell you how to make poor code work. My agenda is to stop you from writing poor code in the first place - by giving you an excellent example and explaining where you went wrong.
Cheers
Related
i have 2 classes and when i run the first one, it works fine but when it gets to the second class i get an error saying AttributeError: 'Question2' object has no attribute 'correct'. how do i make it so that the functions work in both of the class? is there something wrong with my indent? please help me fix this code, thanks:
Edit: i have a problem with using self, if i remove self from the functions it wouldnt work, if i indent it to not be a part of the class, it still wont work, the self gets turns white
class Question1:
def __init__ (self, master):
x = random.randint(5, 12)
y = random.randint(5, 12)
self.master = master
self.user_choice = StringVar()
self.user_choice.set("")
self.frame = Frame(master, padx=200, pady=200)
self.frame.grid()
self.q = Label(self.frame, text="What is {} + {} ?".format(x, y))
self.q.grid(row=0)
self.ans = Entry(self.frame, width=50, textvariable=self.user_choice)
self.ans.grid(row=1)
self.answer = x+y
self.sub = Button(self.frame, text="submit", command=self.correct)
self.sub.grid(row=3)
def correct(self):
global p
if int(self.user_choice.get()) == self.answer:
cor = Label(self.frame,text="Correct!")
cor.grid(row=5, pady=20)
p += 1
if p >= 3:
Question2(self.master)
else:
self.sub.destroy()
nex = Button(self.frame, text="Next", command=self.necs)
nex.grid(row=4)
else:
inc = Label(self.frame,text="incorrect")
inc.grid(row=5, pady=20)
self.sub.destroy()
nex = Button(self.frame, text="Next", command=self.necs)
nex.grid(row=4)
self.frame.destroy()
Question1(self.master)
def necs(self):
self.frame.destroy()
Question1(self.master)
class Question2:
def __init__(self, master):
x = random.randint(2, 2)
y = random.randint(2, 3)
self.master = master
self.user_choice = StringVar()
self.user_choice.set("")
self.frame = Frame(master, padx=200, pady=200)
self.frame.grid()
self.q = Label(self.frame, text="What is {} x {} ?".format(x, y))
self.q.grid(row=0)
self.ans = Entry(self.frame, width=50, textvariable=self.user_choice)
self.ans.grid(row=1)
self.answer = x * y
self.sub = Button(self.frame, text="submit", command=self.correct)
self.sub.grid(row=3)
You can do that by inheriting the properties of Question1 to Question2:
That can be:
class Question2(Question1):
#you can access that by:
self.correct()
Other way is you can define a global function outside both the classes and you can easily access it.
Example:
#somewhere globally:
def correct():
#some code
class Question1():
correct()
class Question2():
correct()
I think you can develop more such ideas of using a function which will be required by multiple classes.
As #JenilDave answered, you need to define function outside class, inherit from other class.explicitly call class.
i.e. for last case:
class Question1:
def correct():
<codes>
class Question2:
q1 = Question1()
q1.correct()
or
Question1.correct(<Question1 instance>)
But since your 'correct' function are heavily dependent to Question1, you can't use either way, and reconstruct your codes.
Working example below:
Instead of generating question Class per questions, send lists of questions to one class.
Every time you succeed third time, you'll move on to next questions by poping list you've provided before.
When Lists are empty, pop() causes IndexError and program closes.
...
Since I can't get what variable 'p' stands for, I'm guessing it's number of successes(passes).
Full Code:
import random
from tkinter import Frame, Label, Entry, Button, StringVar, Tk
class QuestionFrame(Frame):
def __init__(self, master, question_answer):
super().__init__(master)
self.x, self.y = 0, 0
self.master = master
self.entries = question_answer
self.question, self.answer = self.entries.pop(0)
self.success = 0
self.user_choice = StringVar()
self.frame = Frame(master)
self.frame.grid()
self.quest_label = Label(self.frame)
self.ans = Entry(self.frame, width=50, textvariable=self.user_choice)
self.sub = Button(self.frame)
self.quest_label.grid(row=0)
self.ans.grid(row=1)
self.sub.grid(row=3)
self.reload_question()
def reload_question(self):
self.x, self.y = random.sample(range(5, 12), 2)
next_quest = f"What is {self.question.format(self.x, self.y)} ?"
self.quest_label.configure(text=next_quest)
self.ans.delete(0, 'end')
self.sub.configure(text="submit", command=self.correct)
def next(self):
print(self.success)
if self.success == 3:
# loads next entry
try:
self.question, self.answer = self.entries.pop(0)
except IndexError:
self.master.destroy()
else:
self.success = 0
self.reload_question()
else:
self.reload_question()
def correct(self):
self.sub.configure(text="Next", command=self.next)
if int(self.user_choice.get()) == self.answer(self.x, self.y):
self.quest_label['text'] = "Correct!"
self.success += 1
else:
self.quest_label['text'] = "Incorrect!"
if __name__ == '__main__':
# Passing questions with list of (question, answer) tuples.
tests = [("{} x {}", lambda x, y: x*y),
("{} - {}", lambda x, y: x-y)]
root = Tk()
root.title(f'Some fancy title')
window = QuestionFrame(root, tests)
window.mainloop()
Working on a number guessing assignment for an informatics course and cannot for the life of me on this program bind this key. Using previous programs and class example I am able to bind this key to perform certain functions however not in this particular one. Therefore, I am assuming there is something super small wrong and im just overlooking it. Any help is appreciated.
from tkinter import *
import random
class Application(Frame):
def __init__(self, master): #sets up gui elements
Frame.__init__(self, master)
self.grid()
self.create_widgets()
self.number = random.randint(0, 9)
def create_widgets(self):
# creates instructions
Label(self, text = "I'm thinking of a number between 0 and 9.").grid(row = 0, column = 0, sticky = W)
Label(self, text = "Try and guess it!").grid(row = 1, column = 0, sticky = W)
# create guess label and entry
Label(self, text = "Your guess:").grid(row = 2, column = 0, sticky = W)
self.guess_ent = Entry(self)
self.guess_ent.grid(row = 2, column = 1, sticky = W)
# creates button to initiate run function
self.bttn=Button(self, text = "Submit", command = self.run)
self.bttn.grid(row = 3, column = 1, sticky = W)
#binds return key
self.bttn.bind('<KeyPress>', self.enter)
self.bttn.focus_set()
# creates feedback text box for run function
self.text = Text(self, width = 75, height = 10, wrap = WORD)
self.text.grid(row = 4, column = 0, columnspan = 4)
def run(self):
#gets random number
guess = int(self.guess_ent.get())
#if to test guesses and give appropriate feedback
if guess != self.number:
print_text = "You guessed {0}.".format(guess)
if guess > self.number:
print_text += " That's too high. Guess lower..."
elif guess < self.number:
print_text += " That's too low. Guess higher..."
self.text.delete(0.0, END)
self.text.insert(0.0, print_text)
self.guess_ent.delete(0, END)
else:
print_text = "That's the right number! You did it!!"
self.text.delete(0.0, END)
self.text.insert(0.0, print_text)
def enter(self, event):
if event.keysym == "Return":
self.run()
# main
root = Tk()
root.title("Number Guesser")
app = Application(root)
root.mainloop()
The return key in tkinter is also Return, hence your code should be :
self.bttn.bind('<Return>', self.enter)
You are binding the key to a button which does not get focus until pressed or tabbed into, making it almost impossible to notice the trigger of the binding, because your button and the bind call the same method.
Bind to the Entry widget such that you can trigger the binding while in the widget:
self.guess_ent.bind('<Return>', self.enter)
I'm making a game that finding seven right buttons(It has a fixed answer) among 12 buttons by using tkinter. There are a total of 12 buttons, and only if all seven of them are clicked will win the game.
I'm curious about how to make the window to see which button is activated or inactivated, and how to make a function to determine whether one wins or loses. (when seven specific buttons are activated, it wins.)
++
game1=tkinter.Tk()
game1.title("Test")
game1.geometry("600x450")
button1 = Button(game1, text=' 1 ', fg='black', bg='red',
height=3, width=10)
button1.place(x=0,y=300)
button2 = Button(game1, text=' 2 ', fg='black', bg='red',
height=3, width=10)
button2.place(x=100,y=300)
game1.mainloop()
This is the first time using tkinter on python so actually I stopped after writing this really basic code.
The player can choose seven buttons until player itself clicks the "finish" button. (after click that button, player cannot modify anything.)
At first, I thought if I declare "num" and +=1 on that when the right buttons are clicked, but this trial failed because the player can choose whether one activates or inactivates until until player itself clicks the "finish" button. So I thought that this code needs the way to check the final statements of the buttons.
Is there any ways to use something like "if" statements on tkinter? (if players choose right seven buttons, so it is found that they're activated --> then player wins.)
EDIT - I've updated the code:
import tkinter as tk
import tkinter.ttk as ttk
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
from random import sample
tk.Tk.__init__(self, *args, **kwargs)
self.title("Buttons")
self.resizable(width=False, height=False)
row_count = 3
column_count = 4
self.winning_buttons_count = 7
assert 0 < self.winning_buttons_count <= row_count * column_count
winning_buttons_numbers = sample(range(0, row_count * column_count), k=self.winning_buttons_count)
self.selected_buttons_count = 0
self.selected_button_color = "gray"
self.correct_button_color = "green"
self.incorrect_button_color = "red"
self.missed_button_color = "orange"
self.default_button_color = tk.Button().cget("bg")
def on_press(button):
color = button.cget("bg")
if color == self.default_button_color and self.selected_buttons_count < self.winning_buttons_count:
button.configure(bg=self.selected_button_color)
button.configure(relief=tk.SUNKEN)
self.selected_buttons_count += 1
elif color == self.selected_button_color:
button.configure(bg=self.default_button_color)
button.configure(relief=tk.RAISED)
self.selected_buttons_count -= 1
def check_win():
selected_winning_count = 0
for button in self.buttons:
is_selected = button.cget("bg") == self.selected_button_color and \
button.cget("relief") == tk.SUNKEN
is_winning = button.number in winning_buttons_numbers
if is_selected:
if is_winning:
button.configure(bg=self.correct_button_color)
selected_winning_count += 1
else:
button.configure(bg=self.incorrect_button_color)
else:
if is_winning:
button.configure(bg=self.missed_button_color)
if selected_winning_count == self.winning_buttons_count:
self.finish_button.configure(text="You won!")
else:
self.finish_button.configure(text="Incorrect.")
self.buttons = []
for row in range(row_count):
for column in range(column_count):
button = tk.Button(self, text=" " * 8)
button.grid(row=row, column=column)
button.number = (row * column_count) + column
button.configure(command=lambda b=button: on_press(b))
self.buttons.append(button)
vertical_line = ttk.Separator(self, orient=tk.VERTICAL)
vertical_line.grid(row=0, column=column_count+1, rowspan=row_count, sticky="ns", padx=(8, 8))
self.finish_button = tk.Button(self, text="Did I win?", command=check_win)
self.finish_button.grid(row=row_count//2, column=column_count+2)
def main():
application = Application()
application.mainloop()
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
I need help with a program which uses tkinter. So I try to use a button to cycle trough some pictures, but there are two cycles and when i press one button either disappears or goes back to the first one (it's kinda hard to explain). I was asking myself if I could use some threading here and I need help since I've never used it before.
This is the part of the code:
square1 = Image.open("Square1.jpg")
square1r = ImageTk.PhotoImage(square1)
self.square1img = Label(self.windowSq, image=square1r)
self.square1img.image = square1r
self.square1img.place(x=30, y=100)
square1 = Image.open("Square1a.jpg")
square1r = ImageTk.PhotoImage(square1)
self.square1img = Label(self.windowSq, image=square1r)
self.square1img.image = square1r
self.square1img.place(x=435, y=100)
next = Button(self.windowSq, text="Next", font=self.customFont, relief=GROOVE, command=self.next, cursor='hand2')
next.place(x=185, y=380)
self.num = 0
next1 = Button(self.windowSq, text="Next", font=self.customFont, relief=GROOVE, command=self.next1, cursor='hand2')
next1.place(x=600, y=380)
self.num1 = 0
def next(self):
self.num = self.num + 1
if self.num == 1:
self.square1img.destroy()
square2 = Image.open("Square2.jpg")
square2r = ImageTk.PhotoImage(square2)
self.square2img = Label(self.windowSq, image=square2r)
self.square2img.image = square2r
self.square2img.place(x=30, y=100)
elif self.num == 2:
self.square2img.destroy()
square3 = Image.open("Square3.jpg")
square3r = ImageTk.PhotoImage(square3)
self.square3img = Label(self.windowSq, image=square3r)
self.square3img.image = square3r
self.square3img.place(x=30, y=100)
elif self.num == 3:
self.square3img.destroy()
square4 = Image.open("Square4.jpg")
square4r = ImageTk.PhotoImage(square4)
self.square4img = Label(self.windowSq, image=square4r)
self.square4img.image = square4r
self.square4img.place(x=30, y=100)
elif self.num == 4:
self.square4img.destroy()
square5 = Image.open("Square5.jpg")
square5r = ImageTk.PhotoImage(square5)
self.square5img = Label(self.windowSq, image=square5r)
self.square5img.image = square5r
self.square5img.place(x=30, y=100)
elif self.num == 5:
self.square5img.destroy()
square1 = Image.open("Square1.jpg")
square1r = ImageTk.PhotoImage(square1)
self.square1img = Label(self.windowSq, image=square1r)
self.square1img.image = square1r
self.square1img.place(x=30, y=100)
self.num = 0
self.windowSq.after(50000, self.next)
def next1(self):
self.num1 = self.num1 + 1
if self.num1 == 1:
self.square1img.destroy()
square2 = Image.open("Square2a.jpg")
square2r = ImageTk.PhotoImage(square2)
self.square2img = Label(self.windowSq, image=square2r)
self.square2img.image = square2r
self.square2img.place(x=435, y=100)
elif self.num1 == 2:
self.square2img.destroy()
square3 = Image.open("Square3a.jpg")
square3r = ImageTk.PhotoImage(square3)
self.square3img = Label(self.windowSq, image=square3r)
self.square3img.image = square3r
self.square3img.place(x=435, y=100)
elif self.num1 == 3:
self.square3img.destroy()
square4 = Image.open("Square4a.jpg")
square4r = ImageTk.PhotoImage(square4)
self.square4img = Label(self.windowSq, image=square4r)
self.square4img.image = square4r
self.square4img.place(x=435, y=100)
elif self.num1 == 4:
self.square4img.destroy()
square5 = Image.open("Square5a.jpg")
square5r = ImageTk.PhotoImage(square5)
self.square5img = Label(self.windowSq, image=square5r)
self.square5img.image = square5r
self.square5img.place(x=435, y=100)
elif self.num1 == 5:
self.square5img.destroy()
square1 = Image.open("Square1a.jpg")
square1r = ImageTk.PhotoImage(square1)
self.square1img = Label(self.windowSq, image=square1r)
self.square1img.image = square1r
self.square1img.place(x=435, y=100)
self.num1 = 0
self.windowSq.after(50000, self.next1)
The whole program is in a class (if you are wondering...)
class Window(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.master = master
self.master.resizable(0, 0)
master.title("Arcade Games")
master.geometry("800x600+560+240")
You have a lot of redundant code above. The idea is to first store the images in a list and then cycle through the list. You can have 2 buttons that call 2 different functions (one for each list), 2 lists of images, and 2 counters to keep your place in each list, and then change the image on a Label from whichever list you want (I use a button as below, and note that only one button is created-never destroyed, and just the image is changed each time). Or you can use one class, and 2 instances of the class, passing a different list of images to be loaded to each instance. This is just a simple proof of concept program. Click on the button/image to change it.
import sys
if sys.version_info[0] < 3:
import Tkinter as tk ## Python 2.x
else:
import tkinter as tk ## Python 3.x
class ChangeImage():
def __init__(self, root):
self.photos=[]
self.load_images()
self.image_num=0
self.btn = tk.Button(root, image=self.photos[self.image_num], command=self.next_image)
self.btn.grid(row=0)
tk.Button(root, text="Exit", bg="orange", command=root.quit).grid(row=1)
def next_image(self):
self.image_num += 1
if self.image_num >= len(self.photos):
self.image_num=0
## pipe the next image to be displayed to the button
self.btn["image"]=self.photos[self.image_num]
def load_images(self):
""" copy data images to a list that is an instance variable
"""
ladybug_gif_b64='''\
R0lGODlhIAAgALMAAP///wAAADAwMP99Hf8AAP+lAP//AMopUwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAACH5BAAAAAAALAAAAAAgACAAAwTHEMhJq714hp3lDh0GiqH2UWOVAt96pUIsBLKglWg87Dwv
4xMBj0Asxgg+XKxwLBJrxUGsI5TKnARoVHoLDp5XbNP5cwmNAqwa/aOc13ByrfKOw2UGw1SSxrb+
AWIxeXsAaX92UDQ1Nh6BdneMhQIHkHGSjYaVlmt4epmacp19YAKEoJRspKWrjBapWWGqcm1uB5tj
ok4HZa+3m5wEt5kuhpTAcb+FVL/NzspAfDHPysslMJjEIS0oLygnOMVd0SwcHeDk6errEQA7
'''
grape_gif='''\
R0lGODlhIAAgALMAAAAAAAAAgHCAkC6LV76+vvXeswD/ANzc3DLNMubm+v/6zS9PT6Ai8P8A////
/////yH5BAEAAAkALAAAAAAgACAAAAS00MlJq7046803AF3ofAYYfh8GIEvpoUZcmtOKAO5rLMva
0rYVKqX5IEq3XDAZo1GGiOhw5rtJc09cVGo7orYwYtYo3d4+DBxJWuSCAQ30+vNTGcxnOIARj3eT
YhJDQ3woDGl7foNiKBV7aYeEkHEignKFkk4ciYaImJqbkZ+PjZUjaJOElKanqJyRrJyZgSKkokOs
NYa2q7mcirC5I5FofsK6hcHHgsSgx4a9yzXK0rrV19gRADs=
'''
house='''R0lGODdhFQAVAPMAAAQ2PESapISCBASCBMTCxPxmNCQiJJya/ISChGRmzPz+/PxmzDQyZDQyZDQy
ZDQyZCwAAAAAFQAVAAAElJDISau9Vh2WMD0gqHHelJwnsXVloqDd2hrMm8pYYiSHYfMMRm53ULlQ
HGFFx1MZCciUiVOsPmEkKNVp3UBhJ4Ohy1UxerSgJGZMMBbcBACQlVhRiHvaUsXHgywTdycLdxyB
gm1vcTyIZW4MeU6NgQEBXEGRcQcIlwQIAwEHoioCAgWmCZ0Iq5+hA6wIpqislgGhthEAOw==
'''
## could also be a list of files passed to the class
for photo in (ladybug_gif_b64, grape_gif, house):
self.photos.append(tk.PhotoImage(data=photo))
root=tk.Tk()
CI=ChangeImage(root)
root.mainloop()
This question already has answers here:
python tkinter how to bind key to a button
(3 answers)
Closed 4 months ago.
ok i am using this code for educational purposes and if i go 45+54 and hit enter key i dont get any answer but if use the = on the screen not on my keyboard it works. i am so stuck and stressed out because i have done so much research but not able to find my answer. all i ask for the help is that am i missing a piece of code that is stopping me to use the equals key or the enter key on the numpad. please help here this is the code:
from tkinter import *
import tkinter
# Calculator is a class derived from Frame. Frames, being someone generic,
# make a nice base class for whatever you what to create.
class Calculator(Frame):
# Create and return a packed frame.
def frame(this, side):
w = Frame(this)
w.pack(side=side, expand=YES, fill=BOTH)
return w
# Create and return a button.
def button(this, root, side, text, command=None):
w = Button(root, text=text, command=command)
w.pack(side=side, expand=YES, fill=BOTH)
return w
# Enter a digit.
need_clr = False
def digit(self, digit):
if self.need_clr:
self.display.set('')
self.need_clr = False
self.display.set(self.display.get() + digit)
# Change sign.
def sign(self):
need_clr = False
cont = self.display.get()
if len(cont) > 0 and cont[0] == '-':
self.display.set(cont[1:])
else:
self.display.set('-' + cont)
# Decimal
def decimal(self):
self.need_clr = False
cont = self.display.get()
lastsp = cont.rfind(' ')
if lastsp == -1:
lastsp = 0
if cont.find('.',lastsp) == -1:
self.display.set(cont + '.')
# Push a function button.
def oper(self, op):
self.display.set(self.display.get() + ' ' + op + ' ')
self.need_clr = False
# Calculate the expressoin and set the result.
def calc(self):
try:
self.display.set(eval(self.display.get()))
self.need_clr = True
except:
showerror('Operation Error', 'Illegal Operation')
self.display.set('')
self.need_clr = False
def Enter(self):
self.display.set('Enter')
def keyPressed(self,event):
if event.keysym == 'Enter':
self.enter()
def __init__(self):
Frame.__init__(self)
self.option_add('*Font', 'Verdana 12 bold')
self.pack(expand=YES, fill=BOTH)
self.master.title('Simple Calculator')
# The StringVar() object holds the value of the Entry.
self.display = StringVar()
e = Entry(self, relief=SUNKEN, textvariable=self.display)
e.pack(side=TOP, expand=YES, fill=BOTH)
# This is a nice loop to produce the number buttons. The Lambda
# is an anonymous function.
for key in ("123", "456", "789"):
keyF = self.frame(TOP)
for char in key:
self.button(keyF, LEFT, char,
lambda c=char: self.digit(c))
keyF = self.frame(TOP)
self.button(keyF, LEFT, '-', self.sign)
self.button(keyF, LEFT, '0', lambda ch='0': self.digit(ch))
self.button(keyF, LEFT, '.', self.decimal)
# The frame is used to hold the operator buttons.
opsF = self.frame(TOP)
for char in "+-*/=":
if char == '=':
btn = self.button(opsF, LEFT, char, self.calc)
else:
btn = self.button(opsF, LEFT, char,
lambda w=self, s=char: w.oper(s))
# Clear button.
clearF = self.frame(BOTTOM)
self.Enter_button = self.button(clearF, LEFT, 'Enter', self.Enter)
self.bind_all('<Key>', self.keyPressed)
# Make a new function for the - sign. Maybe for . as well. Add event
# bindings for digits to call the button functions.
# This allows the file to be used either as a module or an independent
# program.
if __name__ == '__main__':
Calculator().mainloop()
To call a the same function as a button press on a keypress you have to bind keypress to you GUI.
Example
try:
# for Python2
from Tkinter import *
except ImportError:
# for Python3
from tkinter import *
class GUI(Frame):
# Create and return a packed frame.
def frame(self, side):
w = Frame(self)
w.pack(side=side, expand=YES, fill=BOTH)
return w
# Create and return a button.
def button(self, root, side, text, command=None):
w = Button(root, text=text, command=command)
w.pack(side=side, expand=YES, fill=BOTH)
return w
def hello(self):
self.display.set('hello')
def keyPressed(self,event):
#test to see whether enetr is pressed
if event.keysym == 'Return':
self.hello()
def __init__(self):
Frame.__init__(self)
self.option_add('*Font', 'Verdana 12 bold')
self.pack(expand=YES, fill=BOTH)
self.master.title('Simple GUI')
# The StringVar() object holds the value of the Entry.
self.display = StringVar()
e = Entry(self, relief=SUNKEN, textvariable=self.display)
e.pack(side=TOP, expand=YES, fill=BOTH)
# Clear button.
clearF = self.frame(BOTTOM)
self.hello_button = self.button(clearF, LEFT, 'Hello', self.hello)
#bind keypresses
self.bind_all('<Key>', self.keyPressed)
if __name__ == '__main__':
GUI().mainloop()
for this specific example the folowing code shoulod work:
try:
# for Python2
from Tkinter import *
except ImportError:
# for Python3
from tkinter import *
# Calculator is a class derived from Frame. Frames, being someone generic,
# make a nice base class for whatever you what to create.
# Calculator is a class derived from Frame. Frames, being someone generic,
# make a nice base class for whatever you what to create.
class Calculator(Frame):
# Create and return a packed frame.
def frame(this, side):
w = Frame(this)
w.pack(side=side, expand=YES, fill=BOTH)
return w
def keyPressed(self,event):
#test to see whether enetr is pressed
if event.keysym == 'Return':
self.calc()
# Create and return a button.
def button(this, root, side, text, command=None):
w = Button(root, text=text, command=command)
w.pack(side=side, expand=YES, fill=BOTH)
return w
# Enter a digit.
need_clr = False
def digit(self, digit):
if self.need_clr:
self.display.set('')
self.need_clr = False
self.display.set(self.display.get() + digit)
# Change sign.
def sign(self):
need_clr = False
cont = self.display.get()
if len(cont) > 0 and cont[0] == '-':
self.display.set(cont[1:])
else:
self.display.set('-' + cont)
# Decimal
def decimal(self):
self.need_clr = False
cont = self.display.get()
lastsp = cont.rfind(' ')
if lastsp == -1:
lastsp = 0
if cont.find('.',lastsp) == -1:
self.display.set(cont + '.')
# Push a function button.
def oper(self, op):
self.display.set(self.display.get() + ' ' + op + ' ')
self.need_clr = False
# Calculate the expressoin and set the result.
def calc(self):
try:
self.display.set(eval(self.display.get()))
self.need_clr = True
except:
showerror('Operation Error', 'Illegal Operation')
self.display.set('')
self.need_clr = False
def __init__(self):
Frame.__init__(self)
self.option_add('*Font', 'Verdana 12 bold')
self.pack(expand=YES, fill=BOTH)
self.master.title('Simple Calculator')
# The StringVar() object holds the value of the Entry.
self.display = StringVar()
e = Entry(self, relief=SUNKEN, textvariable=self.display)
e.pack(side=TOP, expand=YES, fill=BOTH)
# This is a nice loop to produce the number buttons. The Lambda
# is an anonymous function.
for key in ("123", "456", "789"):
keyF = self.frame(TOP)
for char in key:
self.button(keyF, LEFT, char,
lambda c=char: self.digit(c))
keyF = self.frame(TOP)
self.button(keyF, LEFT, '-', self.sign)
self.button(keyF, LEFT, '0', lambda ch='0': self.digit(ch))
self.button(keyF, LEFT, '.', self.decimal)
# The frame is used to hold the operator buttons.
opsF = self.frame(TOP)
for char in "+-*/=":
if char == '=':
btn = self.button(opsF, LEFT, char, self.calc)
else:
btn = self.button(opsF, LEFT, char,
lambda w=self, s=char: w.oper(s))
# Clear button.
clearF = self.frame(BOTTOM)
self.button(clearF, LEFT, 'Clr', lambda w=self.display: w.set(''))
self.bind_all('<Key>', self.keyPressed)
# Make a new function for the - sign. Maybe for . as well. Add event
# bindings for digits to call the button functions.
# This allows the file to be used either as a module or an independent
# program.
if __name__ == '__main__':
Calculator().mainloop()