Reputation: 135
I am making a Tic Tac Toe game in Python Tkinter but the buttons are rectangles, and I want them to all be 100x100 pixels in size. I tried using:
a1 = Button(root, text="", font="Helvetica 16 bold", command=a1, height=10, width=10)
(ignore the empty string and a1
) and yet it does not resize it into a square. I have written most of the code and don't want to use frames to resize them. What should I do?
Upvotes: 6
Views: 28104
Reputation: 11
There is a pitfall with the marked answer when working with classes. Make sure you store the image in an instance variable by using self
to prevent it going out of scope.
This does not work:
(no error message, but the button does not react to any interaction, not even hovering)
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
pixel = tk.PhotoImage()
tk.Button(self, text="Exit", image=pixel, compound="c", width=100, height=25, command=self.destroy).pack()
if __name__ == "__main__":
app = App()
app.mainloop()
This works:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.pixel = tk.PhotoImage()
tk.Button(self, text="Exit", image=self.pixel, compound="c", width=100, height=25, command=self.destroy).pack()
if __name__ == "__main__":
app = App()
app.mainloop()
Upvotes: 1
Reputation: 196
The best way to do this is to use Photoimage method.
img = Photoimage()
b1 = Button(win, text="NA", image=img, height=100, width=100)
This above code creates a button with invisible image
Upvotes: -1
Reputation: 91
If you are adding the button with the place method, you can use the expression:
myButton.place(x = 0, y = 0, width = 200, height = 30)
With this, the button is created with a size of 200x30 px
within its parent object at the position x = 0, y = 0
Upvotes: 9
Reputation: 1279
Here is finished code with an adaptive algorithm (so it learns from its mistakes). In answer to your question, I have used a canvas and create rectangles then bound a click to it.
DRAW_WEIGHT = 1 # The value for a round where there was a draw
COMPUTER_WIN_WEIGHT = 5 # The value for a round where there was a computer win
COMPUTER_LOSE_WEIGHT = -5 # The value for a round where there was a computer loss
LOG = True # Rounds be logged to improve move knowledge
import ctypes, math, threading, random, os, time, os.path
from tkinter import *
def end (mode, at = None):
global active, facts
active = False
if mode == 0: l.config (text = "Draw")
elif mode == 1:
if player == -1: l.config (text = "You lose")
else: l.config (text = "Player 1 wins")
else:
if player == -1: l.config (text = "Well done! You win!")
else: l.config (text = "Player 2 wins")
if player == -1:
log [-1].append (mode)
if LOG:
with open ("Learn.log", "w") as f: f.write ("\n".join ([" ".join ([str (j) for j in i]) for i in log]))
else:
with open ("Learn.log", "w") as f: f.write ("\n".join ([" ".join ([str (j) for j in i]) for i in log [ : -1]]))
if at:
if at [0] == 0: c.create_line (at [1] * 200 + 100, 0, at [1] * 200 + 100, 600, width = 5, fill = "blue")
elif at [0] == 1: c.create_line (0, at [1] * 200 + 100, 600, at [1] * 200 + 100, width = 5, fill = "blue")
elif at [0] == 2: c.create_line (0, 0, 600, 600, width = 5, fill = "blue")
else: c.create_line (600, 0, 0, 600, width = 5, fill = "blue")
c.create_text (300, 250, text = "Game Over", fill = "red", font = ("times", 75))
c.create_text (300, 325, text = "Click to play again", fill = "red", font = ("times", 30))
c.bind ("<Button-1>", restart)
def restart (event = None):
global places, player
c.delete (ALL)
places = [0 for i in range (9)]
for i in range (2): c.create_line (200 + 200 * i, 0, 200 + 200 * i, 600, width = 2)
for i in range (2): c.create_line (0, 200 + 200 * i, 600, 200 + 200 * i, width = 2)
if player == -1:
l.config (text = "Click on a square to go there")
c.bind ("<Button-1>", lambda event: threading.Thread (target = click, args = (event,)).start ())
else:
player = True
l.config (text = "Player 1's turn")
c.bind ("<Button-1>", lambda event: threading.Thread (target = p2click, args = (event,)).start ())
def check (mode = False):
toGo = (-1,)
for i in range (3):
now = [places [i + j * 3] for j in range (3)]
if now.count (1) == 3:
toGo = (0, i)
break
if toGo [0] == -1:
for i in range (3):
now = [places [j + i * 3] for j in range (3)]
if now.count (1) == 3:
toGo = (1, i)
break
if toGo [0] == -1:
now = [places [i + i * 3] for i in range (3)]
if now.count (1) == 3: toGo = (2,)
if toGo [0] == -1:
now = [places [2 + i * 3 - i] for i in range (3)]
if now.count (1) == 3: toGo = (3,)
if toGo [0] == -1:
for i in range (3):
now = [places [i + j * 3] for j in range (3)]
if now.count (2) == 3:
toGo = (0, i)
break
if toGo [0] == -1:
for i in range (3):
now = [places [j + i * 3] for j in range (3)]
if now.count (2) == 3:
toGo = (1, i)
break
if toGo [0] == -1:
now = [places [i + i * 3] for i in range (3)]
if now.count (2) == 3: toGo = (2,)
if toGo [0] == -1:
now = [places [2 + i * 3 - i] for i in range (3)]
if now.count (2) == 3: toGo = (3,)
if toGo [0] == -1:
if mode: end (0)
else: return True
else: end (1, toGo)
else: end (2, toGo)
return False
def click (event):
global log, active, facts
c.bind ("<Button-1>", lambda event: None)
start = time.clock ()
l.config (text = "Calculating...")
x, y = math.floor (event.x / 200), math.floor (event.y / 200)
if x == 3: x -= 1
if y == 3: y -= 1
if places [x + y * 3] == 0:
if places.count (0) == 9:
log.append ([x + y * 3])
active = True
else: log [-1].append (x + y * 3)
places [x + y * 3] = 1
c.create_line (x * 200 + 25, y * 200 + 25, x * 200 + 175, y * 200 + 175, width = 2)
c.create_line (x * 200 + 25, y * 200 + 175, x * 200 + 175, y * 200 + 25, width = 2)
toGo, movesChecked = -1, 0
if places.count (0) == 0: check (True)
else:
if check ():
for i in range (3):
movesChecked += 1
now = [places [i + j * 3] for j in range (3)]
if now.count (2) == 2 and now.count (0) == 1:
toGo = i + now.index (0) * 3
break
if toGo == -1:
for i in range (3):
movesChecked += 1
now = [places [j + i * 3] for j in range (3)]
if now.count (2) == 2 and now.count (0) == 1:
toGo = now.index (0) + i * 3
break
if toGo == -1:
movesChecked += 1
now = [places [i + i * 3] for i in range (3)]
if now.count (2) == 2 and now.count (0) == 1: toGo = now.index (0) + now.index (0) * 3
if toGo == -1:
movesChecked += 1
now = [places [2 + i * 3 - i] for i in range (3)]
if now.count (2) == 2 and now.count (0) == 1: toGo = 2 + now.index (0) * 3 - now.index (0)
if toGo == -1:
for i in range (3):
movesChecked += 1
now = [places [i + j * 3] for j in range (3)]
if now.count (1) == 2 and now.count (0) == 1:
toGo = i + now.index (0) * 3
break
if toGo == -1:
for i in range (3):
movesChecked += 1
now = [places [j + i * 3] for j in range (3)]
if now.count (1) == 2 and now.count (0) == 1:
toGo = now.index (0) + i * 3
break
if toGo == -1:
movesChecked += 1
now = [places [i + i * 3] for i in range (3)]
if now.count (1) == 2 and now.count (0) == 1: toGo = now.index (0) + now.index (0) * 3
if toGo == -1:
movesChecked += 1
now = [places [2 + i * 3 - i] for i in range (3)]
if now.count (1) == 2 and now.count (0) == 1: toGo = 2 + now.index (0) * 3 - now.index (0)
if toGo == -1:
useful = [0, 0, 0, 0, 0, 0, 0, 0, 0]
for rot in range (4):
for i in range (len (log) - 1):
movesChecked += 1
this = rotate (log [i], rot)
if len (log [i]) > len (log [-1]):
if log [-1] == this [ : len (log [-1])]:
if this [-1] == 0: value = DRAW_WEIGHT
elif this [-1] == 1: value = COMPUTER_WIN_WEIGHT
else: value = COMPUTER_LOSE_WEIGHT
useful [this [len (log [-1])]] += value
toGo = useful.index (max (useful))
while places [toGo] != 0:
movesChecked += 1
useful [toGo] = min (useful) - 1
toGo = useful.index (max (useful))
places [toGo] = 2
log [-1].append (toGo)
c.create_oval (toGo % 3 * 200 + 25, math.floor (toGo / 3) * 200 + 25, toGo % 3 * 200 + 175, math.floor (toGo / 3) * 200 + 175, width = 2)
facts = [round ((time.clock () - start) * 1000, 1), movesChecked]
facts.append (round (facts [1] / facts [0]))
if check ():
l.config (text = "Your turn")
c.bind ("<Button-1>", lambda event: threading.Thread (target = click, args = (event,)).start ())
else:
l.config (text = "This square has already been taken.")
c.bind ("<Button-1>", lambda event: threading.Thread (target = click, args = (event,)).start ())
def nerdyFacts ():
t = Toplevel ()
t.focus_force ()
t.resizable (False, False)
if os.path.isfile ("icon.ico"): t.iconbitmap ("icon.ico")
if len (facts) > 0: Label (t, text = "Just a few facts about the last move should you wish to know them:\n%sms taken to process request\n%s possible moves checked\n%s moves checked per ms" % tuple (facts)).pack ()
else: Label (t, text = "No facts to display.").pack ()
def rotate (data, mode):
if mode == 0: replace = [i for i in range (9)]
elif mode == 1: replace = [2, 5, 8, 1, 4, 7, 0, 3, 6]
elif mode == 2: replace = [8, 7, 6, 5, 4, 3, 2, 1, 0]
else: replace = [6, 3, 0, 7, 4, 1, 8, 5, 2]
return [replace [i] for i in data [ : -1]] + [data [-1]]
def remove ():
global log
if ctypes.windll.user32.MessageBoxW (0, "Do you really want to delete all of my data.\nIn doing so, I will not be able to make such informed moves.\nOn average, I say it takes about 20 rounds for me to start getting better.\nThis is only recommended if the program takes a long time to make moves.", "Naughts and crosses", 4) == 6:
if active: del log [ : -1]
else: log = []
with open ("Learn.log", "w") as f: f.write ("")
t.destroy ()
ctypes.windll.user32.MessageBoxW (0, "Data reset.", "Naughts and crosses", 0)
def p2click (event):
global player
x, y = math.floor (event.x / 200), math.floor (event.y / 200)
if x == 3: x -= 1
if y == 3: y -= 1
if places [x + y * 3] == 0:
places [x + y * 3] = int (player) + 1
if player:
c.create_line (x * 200 + 25, y * 200 + 25, x * 200 + 175, y * 200 + 175, width = 2)
c.create_line (x * 200 + 25, y * 200 + 175, x * 200 + 175, y * 200 + 25, width = 2)
else: c.create_oval (x * 200 + 25, y * 200 + 25, x * 200 + 175, y * 200 + 175, width = 2)
l.config (text = "Player %s's turn" % str (int (player) + 1))
player = not player
if places.count (0) == 0: check (True)
else: check ()
def start (players):
global player
if players == 1:
player = -1
t = Label (root, text = "Data information", font = ("times", 12))
t.pack ()
t.bind ("<Button-1>", lambda event: threading.Thread (target = dataLog).start ())
else: player = True
restart ()
def dataLog ():
global t
t = Toplevel ()
t.resizable (False, False)
t.focus_force ()
if os.path.isfile ("icon.ico"): t.iconbitmap ("icon.ico")
if active: l = log [ : -1]
else: l = log
if len (l) == 0: Label (t, text = "I have no data to analyse.\nTherefore, I cannot display any extra information.").pack ()
else:
wins, loses, draws = 0, 0, 0
for i in l:
if i [-1] == 0: draws += 1
elif i [-1] == 1: loses += 1
else: wins += 1
wins, loses, draws = round (wins * 100 / len (l)), round (loses * 100 / len (l)), round (draws * 100 / len (l))
last = math.ceil (len (l) / 2)
last_wins, last_loses, last_draws = 0, 0, 0
if last > 50: last = 50
for i in l [len (l) - last : ]:
if i [-1] == 0: last_draws += 1
elif i [-1] == 1: last_loses += 1
else: last_wins += 1
last_wins, last_loses, last_draws = round (last_wins * 100 / last), round (last_loses * 100 / last), round (last_draws * 100 / last)
Label (t, text = "I have %s round/s of data to analyse.\n(%s virtual rounds)\n\nOf these:\n%s%s are user wins\n%s%s are computer wins\n%s%s are draws\n\nIn the last %s round/s:\n%s%s are user wins\n%s%s are computer wins\n%s%s are draws\n" % (len (l), len (l) * 4, wins, "%", loses, "%", draws, "%", last, last_wins, "%", last_loses, "%", last_draws, "%")).pack ()
Button (t, text = "Clear data", command = lambda: threading.Thread (target = remove).start ()).pack ()
active, facts = False, ()
if os.path.isfile ("Learn.log"):
with open ("Learn.log") as f:
read = f.read ()
if read != "": log = [[int (j) for j in i.split (" ")] for i in read.split ("\n")]
else: log = []
else: log = []
try: ctypes.windll.shcore.SetProcessDpiAwareness (True)
except: pass
root = Tk ()
root.title ("Naughts and crosses")
root.resizable (False, False)
if os.path.isfile ("icon.ico"): root.iconbitmap ("icon.ico")
l = Label (root, text = "", font = ("times", 20))
l.bind ("<Button-1>", lambda event: nerdyFacts ())
l.pack ()
c = Canvas (root, width = 600, height = 600, bg = "white")
c.pack ()
c.create_text (300, 200, text = "How many players are there?", font = ("times", 30))
p1 = (c.create_rectangle (150, 350, 250, 450, fill = "blue"),
c.create_text (200, 400, text = "1", font = ("times", 40), fill = "red"))
p2 = (c.create_rectangle (350, 350, 450, 450, fill = "red"),
c.create_text (400, 400, text = "2", font = ("times", 40), fill = "blue"))
for i in p1: c.tag_bind (i, "<ButtonRelease-1>", lambda event: start (1))
for i in p2: c.tag_bind (i, "<ButtonRelease-1>", lambda event: start (2))
root.mainloop ()
In general, I say it should take you playing about 50 matches before it gets better (or you can use the data below which is rounds I have played and save it to a file called learn.log
):
1 0 7 4 8 6 2 3 1
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
3 2 0 6 4 5 8 2
1 0 8 2 7 4 6 2
1 0 8 3 6 7 2 5 4 2
1 2 6 0 7 4 8 2
1 3 6 0 7 4 8 2
4 0 8 1 2 5 6 2
8 0 2 5 4 6 3 1 7 0
3 0 7 1 2 4 8 5 6 2
0 1 4 8 6 3 2 2
0 2 8 4 6 3 7 2
0 3 4 8 2 1 6 2
0 4 8 1 7 6 2 5 3 0
0 4 3 6 2 1 7 5 8 0
8 0 2 5 6 7 4 2
8 1 4 0 2 5 6 2
8 2 0 4 6 3 7 2
8 3 4 0 6 7 2 2
8 4 0 1 7 6 2 5 3 0
8 4 2 5 3 0 1 6 7 0
8 4 0 1 7 6 2 5 3 0
8 4 6 7 1 0 2 5 3 0
8 4 1 0 6 7 2 5 3 0
0 4 8 1 7 6 2 5 3 0
0 4 8 1 7 6 2 5 3 0
0 4 2 1 7 3 6 5 1
1 4 0 2 6 3 8 5 1
6 0 2 4 8 5 7 2
2 0 4 6 3 5 8 1 7 0
2 0 6 4 8 5 7 2
2 1 4 6 8 5 7 0 3 0
2 1 4 6 8 5 0 2
2 3 4 6 0 1 8 2
2 4 0 1 7 3 5 8 6 0
2 4 5 8 0 1 7 3 6 0
2 4 1 0 8 5 6 3 1
2 4 6 0 8 5 7 2
2 4 6 1 7 8 5 0 1
2 4 6 1 7 8 0 3 5 0
2 4 6 1 7 8 0 3 5 0
6 1 4 2 0 3 8 2
6 2 8 7 0 3 4 2
6 3 4 2 8 7 0 2
6 4 7 8 0 3 2 5 1
6 4 3 0 8 7 1 2 5 0
6 4 2 0 8 5 7 2
6 4 2 1 7 8 5 0 1
6 4 2 1 7 8 0 3 5 0
8 4 0 1 7 6 2 5 3 0
4 1 2 6 8 5 0 2
4 2 6 0 1 7 8 3 5 0
2 4 7 0 8 5 6 2
4 2 6 0 1 7 3 5 8 0
2 4 7 1 8 5 6 2
2 5 3 0 7 1 6 8 4 2
0 4 7 1 6 3 8 2
8 4 3 0 6 7 1 2 5 0
7 0 2 1 8 5 6 2
0 4 7 2 6 3 8 2
3 1 8 0 2 5 6 7 4 2
7 1 2 0 8 5 6 2
3 2 8 0 1 4 6 7 5 0
2 6 0 1 3 4 7 5 8 0
1 4 3 0 8 2 6 7 5 0
3 2 8 0 7 1 1
1 4 5 0 8 2 6 7 3 0
3 2 8 0 4 1 1
0 5 4 8 2 1 6 2
4 2 0 8 5 3 7 1 6 0
8 4 3 0 2 5 6 7 1 0
3 2 5 4 7 6 1
6 4 5 0 8 2 7 2
6 4 8 7 2 1 1
1 4 5 0 8 2 6 7 3 0
3 2 7 0 1 4 6 8 1
7 2 3 0 4 1 1
1 4 3 0 8 2 6 7 5 0
7 2 0 1 6 3 8 2
0 6 5 1 4 3 8 2
4 2 6 0 1 7 3 5 8 0
8 4 3 0 5 2 6 1 1
4 2 0 8 5 3 7 1 6 0
6 4 5 1 7 8 0 3 2 0
2 6 8 5 4 0 3 1 7 0
3 2 8 0 4 1 1
4 2 8 0 1 7 3 5 6 0
1 4 8 0 2 5 3 6 7 0
0 7 5 1 4 3 8 2
1 4 6 0 8 7 5 2 3 0
2 6 7 0 3 1 5 8 4 2
2 7 4 6 8 5 0 2
2 8 7 0 4 1 6 2
1 4 6 0 8 7 5 2 3 0
4 2 7 1 0 8 6 5 1
1 4 6 0 8 7 2 5 3 0
7 2 0 3 8 6 4 2
0 8 2 1 7 3 6 4 5 0
1 4 6 0 8 7 2 5 3 0
0 8 1 2 5 3 7 4 6 0
0 8 7 1 4 2 5 3 6 0
0 8 4 1 6 3 2 2
0 4 8 1 7 6 2 5 3 0
5 0 3 4 8 2 1 6 1
1 4 5 0 8 2 6 7 3 0
3 2 5 4 6 0 1 8 1
3 2 5 4 6 0 1 8 1
4 2 5 3 0 8 7 1 6 0
0 4 8 1 7 6 2 5 3 0
4 2 0 8 5 3 6 1 7 0
0 4 8 1 7 6 2 5 3 0
0 4 8 1 7 6 2 5 3 0
0 4 6 3 5 1 7 8 2 0
0 4 5 1 7 2 6 3 8 2
0 4 5 2 6 3 8 7 1 0
0 4 5 2 6 3 7 8 1 0
0 4 8 1 7 6 2 5 3 0
0 4 5 2 1 6 1
3 2 8 0 1 4 6 7 5 0
5 0 6 1 2 8 4 2
5 0 6 2 1 3 7 4 8 2
3 2 8 0 1 4 6 7 5 0
5 1 0 2 6 3 8 7 4 2
0 4 8 1 7 6 2 5 3 0
5 6 0 8 7 4 3 2 1
5 6 0 8 7 4 2 1 3 0
5 6 2 8 7 0 3 4 1
7 0 2 6 3 4 8 5 1 0
6 4 8 7 1 2 3 0 5 0
5 6 1 8 7 4 0 2 1
4 0 8 6 3 5 1 7 2 0
2 4 0 1 7 6 3 8 5 0
4 0 2 6 3 5 1 7 8 0
0 4 8 1 7 6 2 5 3 0
4 0 2 6 3 5 8 1 7 0
4 0 6 2 1 7 5 3 8 0
5 6 0 8 7 4 2 1 3 0
6 4 8 7 1 2 0 3 5 0
0 4 6 3 5 8 1 2 7 0
0 4 8 1 7 6 2 5 3 0
6 4 3 0 8 7 1 2 5 0
1 8 6 2 5 4 0 3 7 0
1 8 4 7 6 2 5 3 0 0
0 4 8 1 7 6 2 5 3 0
4 0 6 2 1 7 8 3 5 0
4 0 1 7 2 6 8 3 1
4 0 2 6 3 5 8 1 7 0
4 0 8 6 3 5 2 7 1 0
0 4 8 1 7 6 2 5 3 0
4 0 3 5 2 6 8 1 7 0
4 0 6 2 1 7 8 3 5 0
0 4 1 2 6 3 8 5 1
0 4 2 1 7 3 5 8 6 0
0 4 1 2 6 3 8 5 1
0 4 1 2 6 3 5 8 7 0
5 6 4 3 0 8 7 1 2 0
0 4 1 2 6 3 5 8 7 0
0 4 2 1 7 3 5 8 6 0
0 4 5 2 6 3 8 7 1 0
0 4 3 6 2 1 7 5 8 0
0 4 7 5 3 6 2 1 8 0
0 4 2 1 7 3 5 8 6 0
0 4 8 1 7 6 2 5 3 0
4 0 8 6 3 5 2 7 1 0
4 0 6 2 1 7 8 3 5 0
4 0 1 7 3 5 8 2 6 0
8 4 0 7 1 2 6 3 5 0
0 4 1 2 6 3 5 8 7 0
0 4 2 1 7 3 5 8 6 0
4 0 6 2 1 7 5 3 8 0
0 4 1 2 6 3 5 8 7 0
6 4 2 3 5 8 0 1 7 0
4 0 1 7 2 6 8 3 1
0 4 8 1 7 6 2 5 3 0
8 4 0 7 1 2 6 3 5 0
0 4 8 1 7 6 2 5 3 0
4 0 8 6 3 5 2 7 1 0
0 4 5 2 6 3 8 7 1 0
6 4 5 1 7 8 0 3 2 0
3 2 8 0 1 4 6 7 5 0
4 0 8 6 3 5 1 7 2 0
6 4 1 0 8 7 2 5 3 0
7 0 2 6 3 4 8 5 1 0
4 0 8 6 3 5 7 1 2 0
4 0 6 2 1 7 8 3 5 0
0 4 6 3 5 8 2 1 7 0
0 4 5 2 6 3 7 8 1 0
4 0 1 7 8 2 5 3 6 0
3 2 4 5 8 0 6 1 1
4 0 8 6 3 5 2 7 1 0
4 0 1 7 2 6 3 8 1
8 4 0 7 1 2 5 6 1
3 2 1 0 7 4 5 8 1
3 2 0 6 8 4 1
3 4 0 6 2 1 7 5 8 0
3 4 2 6 8 5 0 1 7 0
3 4 6 0 2 8 1
4 0 1 7 3 5 2 6 8 0
3 4 6 0 7 8 1
2 4 6 5 3 0 1 8 1
3 4 2 6 0 1 7 8 5 0
3 4 2 6 8 5 0 1 7 0
3 4 7 6 2 0 8 5 1 0
1 4 2 0 8 5 3 7 6 0
4 0 1 7 2 6 3 8 1
4 0 8 6 3 5 1 7 2 0
0 4 8 1 7 6 2 5 3 0
0 4 1 2 6 3 5 8 7 0
5 4 3 0 8 2 6 1 1
5 4 3 0 8 2 1 6 1
5 4 0 2 6 3 8 7 1 0
7 4 0 8 1 2 6 5 1
4 0 8 6 3 5 1 7 2 0
0 4 8 1 7 6 2 5 3 0
1 4 7 6 2 0 3 8 1
1 4 0 2 6 3 5 7 8 0
0 4 8 1 7 6 2 5 3 0
0 4 1 2 6 3 5 8 7 0
3 4 1 6 5 2 1
3 4 1 6 2 0 8 5 7 0
8 4 2 5 3 0 1 6 7 0
3 4 0 6 1 2 1
3 4 1 6 2 0 8 5 7 0
1 4 7 6 2 0 8 3 1
1 4 6 0 8 7 3 2 5 0
4 0 1 7 6 2 5 3 8 0
1 4 5 0 7 8 1
1 4 5 0 8 2 6 7 3 0
5 4 1 2 6 8 0 3 7 0
0 4 2 1 7 3 5 8 6 0
4 0 1 7 2 6 8 3 1
4 0 1 7 6 2 3 5 8 0
0 4 8 1 7 6 2 5 3 0
7 4 1 2 6 8 5 0 1
4 0 1 7 8 2 5 3 6 0
0 4 1 2 6 3 5 8 7 0
4 0 1 7 3 5 2 6 8 0
4 0 1 7 2 6 3 8 1
4 0 8 6 3 5 1 7 2 0
4 0 1 7 6 2 5 3 8 0
4 0 6 2 1 7 5 3 8 0
0 4 2 1 7 3 5 8 6 0
0 4 6 3 2 5 1
2 4 6 5 3 0 8 7 1 0
4 0 1 7 2 6 8 3 1
4 0 2 6 3 5 8 1 7 0
0 4 8 1 7 6 2 5 3 0
3 4 5 8 1 0 1
2 4 5 8 0 1 7 6 3 0
7 4 8 6 5 2 1
4 0 6 2 1 7 5 3 8 0
5 4 8 2 6 7 1 3 0 0
4 0 3 5 7 1 8 2 1
4 0 2 6 3 5 8 1 7 0
0 4 1 2 6 3 5 8 7 0
4 0 1 7 2 6 8 3 1
0 4 6 3 5 8 1 2 7 0
0 4 3 6 2 1 8 7 1
0 4 3 6 2 1 7 5 8 0
3 4 1 6 8 2 1
3 4 1 6 2 0 8 5 7 0
3 4 0 6 2 1 7 5 8 0
4 0 1 7 6 2 3 5 8 0
0 4 1 2 6 3 8 5 1
0 4 1 2 6 3 5 8 7 0
0 4 1 2 6 3 5 8 7 0
0 4 1 2 5 6 1
0 4 1 2 6 3 5 8 7 0
4 0 1 7 2 6 8 3 1
4 0 2 6 3 5 1 7 8 0
0 4 1 2 6 3 5 8 7 0
1 4 0 2 6 3 5 7 8 0
2 4 1 0 8 5 3 7 6 0
4 0 1 7 2 6 8 3 1
8 4 0 7 1 2 6 3 5 0
4 0 1 7 2 6 8 3 1
4 0 1 7 6 2 8 3 5 0
4 0 1 7 3 5 6 2 8 0
4 0 6 2 1 7 8 3 5 0
4 0 1 7 2 6 8 3 1
4 0 2 6 3 5 1 7 8 0
4 0 1 7 6 2 3 5 8 0
4 0 3 5 7 1 2 6 8 0
0 4 8 1 7 6 5 2 1
6 4 0 3 2 5 1
2 4 0 1 7 6 5 8 3 0
2 4 0 1 7 6 8 5 3 0
0 4 8 1 7 6 2 5 3 0
1 4 7 6 2 0 3 8 1
5 4 1 2 3 6 1
5 4 1 2 6 8 0 3 7 0
0 4 1 2 6 3 5 8 7 0
0 4 1 2 6 3 5 8 7 0
1 4 0 2 5 6 1
Upvotes: -1
Reputation: 385970
One simple method is to give the button an invisible 1x1 pixel image. When you do that, the width
and height
attributes are interpreted as pixels (or more accurately, screen units, which could also mean points, inches, or centimeters).
If you do this, you can set compound
to the value "c" to mean that the button should show both text and the image, with both being centered on the window.
For example:
import Tkinter as tk
...
pixel = tk.PhotoImage(width=1, height=1)
button = tk.Button(root, text="", image=pixel, width=100, height=100, compound="c")
...
Upvotes: 18
Reputation: 15226
The way I would want to make sure a button is a specific size in pixels is by placing that button inside of a frame and making sure the frame is set to a specific size and the button is set to fill that frame.
This can easily be converted to work in your program and it makes sure the buttons are set to exactly 100 x 100.
This is the only way I am aware of to be sure of the size of a button in pixels. There may be other options.
First we will need 2 list. One to hold the frames and one to hold the buttons. This will allow us to store the frames and buttons in an easy way that we can work with later.
frames_list = []
btn_list = []
I am not sure off the top of my head on how to condense your check_win()
function so I will only make a minor change to it so it will work with the lists. We need to replace each instance of a1
, a2
, a3
, and so on with its counterpart in the buttons list with the index value that is going to be created with the for loop later.
def check_win():
# Horizontal wins
if btn_list[0]["text"] == btn_list[1]["text"] == btn_list[2]["text"] == "X" or btn_list[0]["text"] == btn_list[1]["text"] == btn_list[2]["text"] == "O":
print("{} wins".format(btn_list[0]["text"]))
elif btn_list[3]["text"] == btn_list[4]["text"] == btn_list[5]["text"] == "X" or btn_list[3]["text"] == btn_list[4]["text"] == btn_list[5]["text"] == "O":
print("{} wins".format(btn_list[3]["text"]))
elif btn_list[6]["text"] == btn_list[7]["text"] == btn_list[8]["text"] == "X" or btn_list[6]["text"] == btn_list[7]["text"] == btn_list[8]["text"] == "O":
print("{} wins".format(btn_list[6]["text"]))
# Vertical wins
elif btn_list[0]["text"] == btn_list[3]["text"] == btn_list[6]["text"] == "X" or btn_list[0]["text"] == btn_list[3]["text"] == btn_list[6]["text"] == "O":
print("{} wins".format(btn_list[0]["text"]))
elif btn_list[1]["text"] == btn_list[4]["text"] == btn_list[7]["text"] == "X" or btn_list[1]["text"] == btn_list[4]["text"] == btn_list[7]["text"] == "O":
print("{} wins".format(btn_list[1]["text"]))
elif btn_list[2]["text"] == btn_list[5]["text"] == btn_list[8]["text"] == "X" or btn_list[2]["text"] == btn_list[5]["text"] == btn_list[8]["text"] == "O":
print("{} wins".format(btn_list[2]["text"]))
# Diagonal wins
elif btn_list[0]["text"] == btn_list[4]["text"] == btn_list[8]["text"] == "X" or btn_list[0]["text"] == btn_list[4]["text"] == btn_list[8]["text"] == "O":
print("{} wins".format(btn_list[0]["text"]))
elif btn_list[2]["text"] == btn_list[4]["text"] == btn_list[6]["text"] == "X" or btn_list[2]["text"] == btn_list[4]["text"] == btn_list[6]["text"] == "O":
print("{} wins".format(btn_list[2]["text"]))
# If no one wins
else:
change_turn()
Then we need to change the process_turn()
function to include the index value of each button in the buttons list so add an argument to it like this.
def process_turn(ndex): # index argument being sent by buttons
btn_list[ndex].config(text=turn) # changed text at index of list.
check_win()
Finally we need to create all the buttons with the correct index in the command and we can do this with a for loop. Well 2 for loops.
The first loop will start the row count and the 2nd for loop will work the column count. This creates our 3 by 3 grid. The ndex
variable is used to keep track of the index that each button needs to configure on the buttons list.
def create_frames_and_buttons():
ndex = 0
i = 0
x = 0
for i in range(3):
for x in range(3):
frames_list.append(Frame(root, width = 100, height = 100))
frames_list[ndex].propagate(False)
frames_list[ndex].grid(row = i, column = x, sticky = "nsew", padx = 2, pady = 2) # add any padding you would like to space out the frames/buttons
btn_list.append(Button(frames_list[ndex], text="", font="Helvetica 16 bold",
command = lambda ndex=ndex: process_turn(ndex)))
btn_list[ndex].pack(expand=True, fill=BOTH)
x += 1
ndex += 1
i += 1
root.resizable(width=False, height=False)
create_frames_and_buttons()
All put together you have this code that has the exact 100x100 pixel sizing you wanted.
Take a look at the below example:
from tkinter import *
root = Tk()
frames_list = []
btn_list = []
turn = "X"
turnLabel = Label(root, text=turn, font="Helvetica 16 bold")
turnLabel.grid(row=3, columnspan=3)
def change_turn():
global turn
if turn == "O":
turn = "X"
turnLabel.config(text=turn)
elif turn == "X":
turn = "O"
turnLabel.config(text=turn)
def check_win():
# Horizontal wins
if btn_list[0]["text"] == btn_list[1]["text"] == btn_list[2]["text"] == "X" or btn_list[0]["text"] == btn_list[1]["text"] == btn_list[2]["text"] == "O":
print("{} wins".format(btn_list[0]["text"]))
elif btn_list[3]["text"] == btn_list[4]["text"] == btn_list[5]["text"] == "X" or btn_list[3]["text"] == btn_list[4]["text"] == btn_list[5]["text"] == "O":
print("{} wins".format(btn_list[3]["text"]))
elif btn_list[6]["text"] == btn_list[7]["text"] == btn_list[8]["text"] == "X" or btn_list[6]["text"] == btn_list[7]["text"] == btn_list[8]["text"] == "O":
print("{} wins".format(btn_list[6]["text"]))
# Vertical wins
elif btn_list[0]["text"] == btn_list[3]["text"] == btn_list[6]["text"] == "X" or btn_list[0]["text"] == btn_list[3]["text"] == btn_list[6]["text"] == "O":
print("{} wins".format(btn_list[0]["text"]))
elif btn_list[1]["text"] == btn_list[4]["text"] == btn_list[7]["text"] == "X" or btn_list[1]["text"] == btn_list[4]["text"] == btn_list[7]["text"] == "O":
print("{} wins".format(btn_list[1]["text"]))
elif btn_list[2]["text"] == btn_list[5]["text"] == btn_list[8]["text"] == "X" or btn_list[2]["text"] == btn_list[5]["text"] == btn_list[8]["text"] == "O":
print("{} wins".format(btn_list[2]["text"]))
# Diagonal wins
elif btn_list[0]["text"] == btn_list[4]["text"] == btn_list[8]["text"] == "X" or btn_list[0]["text"] == btn_list[4]["text"] == btn_list[8]["text"] == "O":
print("{} wins".format(btn_list[0]["text"]))
elif btn_list[2]["text"] == btn_list[4]["text"] == btn_list[6]["text"] == "X" or btn_list[2]["text"] == btn_list[4]["text"] == btn_list[6]["text"] == "O":
print("{} wins".format(btn_list[2]["text"]))
# If no one wins
else:
change_turn()
def process_turn(ndex):
btn_list[ndex].config(text=turn)
check_win()
def create_frames_and_buttons():
ndex = 0
i = 0
x = 0
for i in range(3):
for x in range(3):
frames_list.append(Frame(root, width = 100, height = 100))
frames_list[ndex].propagate(False)
frames_list[ndex].grid(row = i, column = x, sticky = "nsew", padx = 2, pady = 2)
btn_list.append(Button(frames_list[ndex], text="", font="Helvetica 16 bold",
command = lambda ndex=ndex: process_turn(ndex)))
btn_list[ndex].pack(expand=True, fill=BOTH)
x += 1
ndex += 1
i += 1
root.resizable(width=False, height=False)
create_frames_and_buttons()
root.mainloop()
results:
Upvotes: 4