from tkinter import *
import random
master = Tk()
w = Canvas(master, width=400, height=400)
w.pack()
w.config(background = "white")
class gridTile:
def __init__(self,width,height,c1,c2,colour,val):
self.width = width
self.height = height
self.c1 = c1
self.c2 = c2
self.colour = colour
self.val = val
def draw(self):
w.create_rectangle(self.c1, self.c2, self.width + self.c1,
self.height + self.c2, fill = self.colour)
grid = [["a","b","c","d"],["1a","1b","1c","1d"],["2a","2b","2c","2d"],["3a","3b","3c","3d"]]
When I tested this in a separate environment it worked perfectly, when scaled up it doesn't work.
print(grid[(3)(3)])
grid_size = 4
count = 0
size = 60
for i in range(0,3):
print(i)
for j in range(0,3):
print(j)
count += 1
print (grid[[i][j]])
This range should be included within grid
grid[[i][j]] = gridTile(size,size,i*(size +10),j*(size + 10),"black",count)
def end():
sqry = random.randint(0,3)
sqrx = random.randint(0,3)
grid[[sqry][sqrx]].colour = "white"
for i in range(0,2):
x = random.randint(0,3)
y = random.randint(0,3)
mainloop()
Error:
<module>
grid[[i][j]] = gridTile(size,size,i*(size +10),j*(size + 10),"black",count)
IndexError: list index out of range
I’m on mobile but it seems like a 2D array. In order to access the value do grid[x][y] instead of tuples or arrays.
Please correct me if I’m misunderstanding something.
Let's look at grid[[i][j]]. The inside of that expression is [i][j]. If i = 2 and j = 3, for example, that expands to [2][3]. In other words, it creates a list [2] and then tries to get the item at index 3 from it.
That's not going to work. grid[i][j] is the correct syntax. But for real, don't do that for i in range(...) stuff. Like Matiiss said, you'd really want to write something like:
for sublist in grid:
for item in sublist:
print(item)
count += 1
Related
This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed 8 months ago.
When searching for the answer to this I found a similar post online, which I will link bellow, and their code is what I have been working from.
Array of buttons in python
After reading this I decided I would copy it in to a file and try get it to work and I ended up with this...
from tkinter import *
class testClass:
def main(self):
root = Tk()
frame=Frame(root)
frame.grid(row=0,column=0)
self.btn= [[0 for x in range(20)] for x in range(60)]
for x in range(60):
for y in range(20):
self.btn[x][y] = Button(frame,command= lambda: self.color_change(x,y))
self.btn[x][y].grid(column=x, row=y)
root.mainloop()
def color_change(self,x,y):
self.btn[x][y].config(bg="red")
testMain = testClass()
testMain.main()
However this has taken me back to a very similar place to where I was before. I can only change the color of the most recently made button. How would I fix this?
Here is my old code before I found the last post encase that helps too:
from tkinter import *
main = Tk()
wd = Frame(main, width = "500", height = "500", bg = "brown")
wd.pack( padx = 5, pady = 5)
tile = []
def onClick():
tile[-1].config(bg = "green")
#I have no idea how I would find where the button I clicked is in the array. Might not be possible the way I have done it.
for index in range(8):
for counter in range(8):
if index in range(2, 5):
tile.append(Button(wd, width = 2, height = 1, command = onClick))
tile[-1].grid(padx = 0.5, pady = 0.5, row = index, column = counter)
elif index in range(0, 2):
tile.append(Button(wd, width = 2, height = 1, text = "O", fg = "red", command = onClick))
tile[-1].grid(padx = 0.5, pady = 0.5, row = index, column = counter)
elif index in range(6, 8):
tile.append(Button(wd, width = 2, height = 1, text = "O", fg = "blue", command = onClick))
tile[-1].grid(padx = 0.5, pady = 0.5, row = index, column = counter)
main = mainloop()
try using from functools import partial; command = partial(self.color_change, x, y) instead of lambda function for command argument of a button. –
matszwecja
1 min ago
Yup This works! Thanks so much!
I am attempting to make Minesweeper in python using Tkinter. I have completed all of the initial logic but I am having trouble with the squares with zero surrounding bombs. The program is meant to open all of the surrounding squares when a square with zero surrounding bombs is clicked. The problem here is that it somehow creates an infinite loop. This may be due to the fact that I am calling the function click multiple times using a for loop but I am not sure if this is correct or how to fix it.
My code so far:
import tkinter as tk
from random import choices
from math import floor
##•
def openSurroundings(i):
trash = [i+1, i+8, i+9, i+10, i-1, i-8, i-9, i-10]
for a in trash:
if a<81:
click(floor(a/9), a-((a//9)*9))
def click(row, col):
text = numbers[row][col]
widget = buttons[row][col]
widget.grid_forget()
clickSurrounding = False
if text == 0:
text = ''
clickSurrounding = True
lab = tk.Label(window, text = text, height = 2, width = 5)
lab.grid(row = row, column = col)
if clickSurrounding == True:
openSurroundings((row*9)+col)
def placeBombs():
global widgets, bombs
numOfBombs = 10
widgets = list(range(1, (len(buttons)**2)+1))
bombs = choices(widgets, k = numOfBombs)
def findNumbers():
global numbers
numbers = []
lis_num = []
for i in widgets:
if i in bombs:
lis_num.append('•')
continue
else:
trash = [i+1, i+8, i+9, i+10, i-1, i-8, i-9, i-10]
num = 0
for a in trash:
if a > 0 and a in bombs:
num += 1
lis_num.append(num)
for i in range(0, len(lis_num), 9):
numbers.append(lis_num[i:i + 9])
window = tk.Tk()
window.title('Minesweeper')
sideLen = 9
row_index = 0
cell_index = 0
buttons = []
while row_index != sideLen:
button_row = []
while cell_index != sideLen:
button = tk.Button(window, width=5, height = 2, command=lambda row_index=row_index, cell_index=cell_index: click(row_index, cell_index))
button_row.append(button)
button.grid(row=row_index, column=cell_index)
cell_index += 1
buttons.append(button_row)
cell_index = 0
row_index += 1
placeBombs()
findNumbers()
Hi I am making a tkinter program but have run into this issue.
I am trying to use the grid method to center a load of buttons in the middle of the screen(The amount of buttons will vary dynamically) However I cant keep the buttons to a reasonable size I have followed the advice of someone who had a similar problem however I cant figure out what I am doing differently as it hasn't solved my issue.
Here is my code (it uses a directory pathway so it won't work for the reader but maybe you can spot what I am doing wrong)
ef open_win3():
global third_window
third_window = Toplevel()
third_window.config(height = 1800,width = 1800, bg = "chocolate1")
create_thirdwindow_button()
def create_thirdwindow_button():
bf = Frame(third_window,bg = "blue")
bf.grid(row=0, column=0,sticky="NESW")
bf.rowconfigure(0,weight = 1)
bf.columnconfigure(0,weight =1)
third_window.grid_rowconfigure(0, weight=1)
third_window.grid_columnconfigure(0, weight=1)
count = 0
x = 1
y = 0
mypath = "C:\\Users\\link\\OneDrive\\Desktop\\python stuff\\screenshot example\\Snapshots by catagory"
for g in listdir(mypath):
count += 1
for I in listdir(mypath):
btp = mypath +"\\"+str(I)
print(btp)
screenshot_snap = Button(bf,text = str(I),width = 1,height = 1, bg = "chocolate3",activebackground = "white",padx= 10,pady =10)
screenshot_snap.grid(sticky = "NESW")
screenshot_snap.grid_rowconfigure(0, weight=1)
screenshot_snap.grid_columnconfigure(0, weight=1)
x += 10
if y < count:
y += 1
Thanks a lot for any help!
Im making one of my first programs, using python, tkinter and pillow.
This program is supposed to randomly select one of four tile images, create an image and repeat 25 times
Making a 5x5 Board using a grid to position the images in a square.
This is not what happened when i ran my code though
One or two columns and 4 rows are usually generated and not every coordinate is filled with an image.
And only the corner of the images are visible for some reason?
The images center seems to be placed in the top left corner of their grid.
A output might look something like this
X = coordinate filled with an image
O = coordinate filled with bg colour
X X
O X
O X
When i want it to look like this
X X X X X
X X X X X
X X X X X
X X X X X
X X X X X
The code thats supposed to place the images looks like this
while n < 25:
n = n + 1
number = random.randint(1,4)
if number == 1:
TILE_FLOWER.grid(row = x, column = y)
TILE_FLOWER.create_image(16,16, image = TILE_FLOWER_IMG)
elif number == 2:
TILE_GRASS.grid(row = x, column = y)
TILE_GRASS.create_image(16,16, image = TILE_GRASS_IMG)
elif number == 3:
TILE_STONE.grid(row = x, column = y)
TILE_STONE.create_image(16,16, image = TILE_STONE_IMG)
elif number == 4:
TILE_WATER.grid(row = x, column = y,)
TILE_WATER.create_image(16,16, image = TILE_WATER_IMG)
if x == 5:
x = 0
y = y + 1
else:
x = x + 1
win.mainloop()
The code defining my canvases looks like this
They're the same size as the images i want to draw on them.
TILE_FLOWER = Canvas(win, height = 80, width = 80)
TILE_GRASS = Canvas(win, height = 80, width = 80)
TILE_STONE = Canvas(win, height = 80, width = 80)
TILE_WATER = Canvas(win, height = 80, width = 80)
And lastly the code defining the images looks like this
TILE_FLOWER_IMG = PhotoImage(file = 'Path1.png')
TILE_GRASS_IMG = PhotoImage(file = 'Path2.png')
TILE_STONE_IMG = PhotoImage(file = 'Path3.png')
TILE_WATER_IMG = PhotoImage(file = 'Path4.png')
Hope what i've written makes sense!
And i would be super thankful if someone could help me fix this mess :)
You need to create new Label or Canvas in each cell of the 5x5 grid:
import tkinter as tk
import random
root = tk.Tk()
imagelist = [
tk.PhotoImage(file='Path1.png'),
tk.PhotoImage(file='Path2.png'),
tk.PhotoImage(file='Path3.png'),
tk.PhotoImage(file='Path4.png'),
]
for i in range(25):
image = random.choice(imagelist)
tk.Label(root, image=image, width=80, height=80, bg='white').grid(row=i//5, column=i%5)
'''
# or using Canvas
canvas = tk.Canvas(root, width=80, height=80, bg='white')
canvas.create_image(40, 40, image=image)
canvas.grid(row=i//5, column=i%5)
'''
root.mainloop()
Or using single Canvas:
canvas = tk.Canvas(root, width=400, height=400, bg='white')
canvas.pack()
for i in range(25):
image = random.choice(imagelist)
row = i // 5
col = i % 5
canvas.create_image(40+col*80, 40+row*80, image=image)
I'm trying to change the button colour to black when clicked then change it back to white when clicked again. I'm trying to make Game Of Life for a school project.
I tried if statements but it doesn't change back to white, maybe I missed something simple. Here is the code:
from tkinter import *
class GUI(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
master.title("Window") #Window title
self.pack()
master.geometry("1280x720") #Window size
self.button={}#Dictionary for buttons
self.create_button()
def create_button(self):
indexList =[i for i in range(1000)]
self._button = Button(self, bg='white')
print(self._button.cget('bg'))
xPos = 0
yPos = 0
for index in indexList:
if(yPos == 40):
xPos = xPos + 20
yPos = 0
if(xPos == 10):
yPos = 8
self._button = Button(self, height=2, width=4, command = lambda
i = index: self.changecolour(i))
self.button[index] = self._button
self._button.grid(row=xPos, column =yPos)
yPos = yPos + 1
def changecolour(self,index):
aList = []
for i in range(1000):
aList.append([i,0])
for i in aList:
if index == i[0]:
if 0 == i[1]:
self.button[index].configure(bg = 'black')
i[1] = 1
else:
self.button[index].configure(bg = 'white')
i[1] = 0
root = Tk()
game_gui = GUI(master=root)
game_gui.mainloop()
As you can see it changes the button colour to black and it should change it back to white when clicked again, but it seems to just ignore the if statement.
I think this is the problem:
aList is not a global list
aList is created in changecolour() as a local list each time the subroutine is run
this means that when you do i[1] = 1 or i[1] = 0 it only changes the local list- aList. When the subroutine is run again, a new aList is created as a new local list.
to solve the problem define aList in the main program and make it a global list:
from tkinter import *
class GUI(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
master.title("Window") #Window title
self.pack()
master.geometry("1280x720") #Window size
self.button={}#Dictionary for buttons
self.create_button()
def create_button(self):
indexList =[i for i in range(1000)]
self._button = Button(self, bg='white')
print(self._button.cget('bg'))
xPos = 0
yPos = 0
for index in indexList:
if(yPos == 40):
xPos = xPos + 20
yPos = 0
if(xPos == 10):
yPos = 8
self._button = Button(self, height=2, width=4, command = lambda
i = index: self.changecolour(i))
self.button[index] = self._button
self._button.grid(row=xPos, column =yPos)
yPos = yPos + 1
def changecolour(self,index):
#aList IS NO LONGER CREATED HERE
for i in range(1000):
aList.append([i,0])
for i in aList:
if index == i[0]:
if 0 == i[1]:
self.button[index].configure(bg = 'black')
i[1] = 1
else:
self.button[index].configure(bg = 'white')
i[1] = 0
global aList #MAKE IT A GLOBAL LIST
aList = [] #CREATE THE EMPTY aList LIST
root = Tk()
game_gui = GUI(master=root)
game_gui.mainloop()