简体   繁体   中英

Unable to change Tkinter frame color

I am trying to create something simple using Tkinter. In it, I am creating a series of frames and then using frame.grid() putting them inside of another frame. I am able to retrieve the frame and print out information about it, but I am unable to change the color.

I have looked through other posts and was unable to find a solution. I have tried:

  • Updating the color using .config(bg=color) / .configure(bg=color)
  • Updating the color using frame['bg']=
  • Placing the function before or after the creation of the frames.

I am able to edit the color of the frames when I am calling a function through the <Button-1> event, but when I am running a different function, it is unable to change the colors.

I am using Replit, here is the important code:

window = tk.Tk()
window.wm_attributes('-fullscreen',True)
window.config(bg='#111111')

height = window.winfo_screenheight()
width = window.winfo_screenwidth()

#window.geometry(f'{height}x{height}')

rows = height//gridSize
columns = height//gridSize

frame = tk.Frame(master=window, bg='#111111', width=height, height=height, pady=10)
frame.pack(side=tk.BOTTOM)

def getNumLiveNeighbors(cellRow, cellColumn):
    numLiveNeighbors = 0
    # print(cellRow, cellColumn)
    r = -2
    for i in range(3):
        c = -2
        r += 1
        for a in range(3):
            c += 1
            if(r==0)and(c==0):
                continue
            nRow, nCol = cellRow+r, cellColumn+c
            if(((nRow<0)or(nRow>=gridSize))or(nCol<0)or(nCol>=gridSize)):
                continue
            neighbor = frame.grid_slaves(row=nRow, column = nCol)[0]
            if(neighbor['bg']=='#ffffff'):
                numLiveNeighbors += 1
            #neighbor.config(bg='#252525')
    return numLiveNeighbors

def toggleColor(event):
    widget = event.widget
    if(widget['bg']=='#ffffff'):
        widget.config(bg='#222222')
    else:
        widget.config(bg='#ffffff')
    info = widget.grid_info()
    print(getNumLiveNeighbors(info['row'], info['column']))
    print(event.x, event.y)
    return

for i in range(gridSize):
    window.columnconfigure(i, weight = 1)
    window.rowconfigure(i, weight = 1)

for i in range(gridSize):
    cellGrid[i] = {}
    for j in range (gridSize):
        box = tk.Frame(master=frame, bg='#222222', relief=tk.RAISED, width=columns, height=columns)
        cellGrid[i][j] = box
        box.bind('<Button-1>', toggleColor)
        box.grid(row=i,column=j,sticky='nsew')

def runGame(event):
    frameCount = 0
    print('Running game!')
    while(True):
        print(f'Frame #{frameCount}')
        frameCount += 1
        for row in range(gridSize):
            for col in range(gridSize):
                time.sleep(0.5)
                cell = frame.grid_slaves(row=row, column=col)[0]
                numNeighbors = getNumLiveNeighbors(row, col)
                print(numNeighbors)
                if(numNeighbors<2):
                    print('Less than 2, do nothing')
                    #cell.config(bg='#222222')
                elif(numNeighbors==3):
                    print('3 Neighbors, make cell alive!')
                    cell['bg']='#ffffff'
                elif(numNeighbors>3):
                    print('Greater than 3 neighbors, kill the cell')
                    cell['bg']='#222222'
                print(cell['bg'])

window.bind('<Return>', runGame)

If thats too much to read I can break it down a bit more and explain what I'm doing with each function/line.

The main goal of this was to create a cellular automata like Conway's Game of Life, but I've been stuck trying to update the color of the "cells".

You CANNOT use an infinite loop like that. Tk, like all GUI frameworks, is event driven. When you create a window or make a change, that doesn't actually do any drawing. It just sends a message. That message will be dispatched and acted upon when you get back to the main loop. In your case, you never exit your loop, so your handler never returns, the main loop never runs, and your UI freezes.

Instead of an infinite loop with time.sleep(0.5) , you need to use window.after to request a timer callback. Do one generation and return (after calling window.after again). That way, the main loop stays in control, and all will be well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM