简体   繁体   English

tkinter 按钮颜色不会改变(非点击事件)

[英]tkinter button color won't change (non-click event)

I created a program to move a knight around a chess board touching every square without touching the same one twice, starting from a random location.我创建了一个程序,让一名骑士绕着棋盘移动,从一个随机位置开始,在不触及同一个方格的情况下触及每个方格。 I am attempting to show this action using tkinter by changing the color of the square (which is a button) to red as the knight moves.我试图通过在骑士移动时将正方形(这是一个按钮)的颜色更改为红色来使用 tkinter 来显示此动作。

The Chess Board is made of tkinter buttons and they relate to the "Square" class. The program sets the correct colors when creating the grid, but won't change them during execution.棋盘由 tkinter 个按钮组成,它们与“正方形”class 相关。程序在创建网格时设置正确的 colors,但在执行过程中不会更改它们。

Here is the reduced code (as instructed to provide).这是简化的代码(按照指示提供)。 The reduced code is not the entire code, just the instance of creating the board and placing the knight in a random location.简化后的代码并不是全部代码,只是创建棋盘并将骑士放置在随机位置的实例。 When the knight is placed, the button color should change.当骑士被放置时,按钮的颜色应该改变。

    from tkinter import *
    from tkmacosx import Button
    import random
    import sys

    WIDTH = 800
    HEIGHT = 1000
    GRID_SIZE = 8


    class Square:
        board = []
        def __init__(self, x, y, touched=False):
            self.touched = touched
            self.board_btn_object = None
            self.x = x
            self.y = y
        
    
        def create_btn_object(self, location):
            btn = Button (
                location,
                width=100,
                height=100,
                text= f"{self.x}, {self.y}", 
                bg=None
            )
            self.board_btn_object = btn

            Square.board.append(self)
    
        @property
        def is_touched(self):
            self.touched = True
            self.board_btn_object.configure(bg="red")
    
        @staticmethod
        def randomlocation():
            return random.choice(Square.board)


        def __repr__(self):
            return f"Square({self.x}, {self.y}) touched={self.touched}"


    class Knight:
        def __init__(self, x, y):
            self.x = x
            self.y = y


    def main():
        root = Tk()
        root.configure(bg='blue')
        root.geometry(f'{WIDTH}x{HEIGHT}')
        root.title("chess chaser")
        root.resizable(False, False)

        top_frame = Frame(
            root,
            bg = "red",
            width = WIDTH,
            height = height_prct(10)
        )
        top_frame.place(x=0, y=0)

        bottom_frame = Frame(
            root,
            bg="black",
            width = WIDTH,
            height = height_prct(10)
        )
        bottom_frame.place(x=0, y=height_prct(90))

        center_frame = Frame(
            root,
            bg = "green",
            width = WIDTH,
            height = height_prct(80)
        )
        center_frame.place(
            x=0,
            y=height_prct(10)
        )

        make_board(center_frame)
        top_menu(top_frame)
    
        root.mainloop()


    def height_prct(percentage):
         return (HEIGHT / 100) * percentage


    def width_prct(percentage):
        return (WIDTH / 100) * percentage

    def top_menu(top_frame):

        run = Button (
            top_frame,
            width = 100,
            height = 50,
            text=f"Run",
            command = play_game
        )
        run.place(x=30, y=10)


    def make_board(center_frame):
        for x in range(GRID_SIZE):
            for y in range(GRID_SIZE):
                b = Square(x, y)
                b.create_btn_object(center_frame)
                b.board_btn_object.grid(
                    column=x, row=y
                )
                if (x+y) %2 ==0:
                    b.board_btn_object.configure(bg="grey50")
        return


    def play_game():
        knight = place_knight()
        sys.exit("Done")


    def place_knight():
        coords = Square.randomlocation()
        coords.is_touched
        x = coords.x
        y = coords.y
        knight = Knight(x, y)
        return knight


    if __name__ == "__main__":
        main()

I have tried using self.board_btn_object.change(bg="red") and.update and.after.... nothing works to change the color.我试过使用 self.board_btn_object.change(bg="red") and.update and.after.... 没有任何方法可以改变颜色。

If I change code and bind left click to change the button to red, it works fine;如果我更改代码并绑定左键单击以将按钮更改为红色,则可以正常工作; however, I want it to change when the KNIGHT is positioned there.但是,我希望它在 KNIGHT 放置在那里时发生变化。

You are just complicated everything.你只是把一切都复杂化了。 Create a cell class and keep information of x,y and iftouched in it.创建一个单元格 class 并在其中保留 x,y 和 iftouched 的信息。 This way you can add new capabilities into cells easily.通过这种方式,您可以轻松地将新功能添加到单元格中。 Create a board and make an array inside it.创建一个板并在其中创建一个数组。 Create cell instances and place into that array.创建单元格实例并放入该数组。 You should do inside this board whatever you do.无论你做什么,你都应该在这个板子里做。 Define rules, move capabilities etc. GUI simply should be an illusion of this imaginary board.定义规则、移动功能等。GUI 应该只是这个假想板的幻觉。 When things get complicated you just update your user interface according to your board!当事情变得复杂时,您只需根据您的电路板更新您的用户界面!

import tkinter as tk
import random

GRID_SIZE = 8

#this is cell which going to keep information
class cell:
    def __init__(self,x,y,IsTouched=False):
        self.x= x
        self.y = y
        self.touched = IsTouched

class board:
    def __init__(self):
        self.initializeBoard()
        self.knight = [0,0]
        self.placeKnightRandomly()
        
    def moveKnight(self,x,y):
        #if knight can move in the board, return True so that
        #we can show in the GUI.
        if(self.board[x][y].touched):
            return False
        else:
            self.knight = [x,y]
            print(f"Knight new position:{x},{y}")
            return True
    
    def initializeBoard(self):
        #This function creates board from zero.
        #if you want to reset board, simple run this function.
        self.board = []
        for row in range(GRID_SIZE):
            line = []
            for column in range(GRID_SIZE):
                line.append(cell(row,column))
            self.board.append(line)

    def placeKnightRandomly(self):
        #place knight randomly
        x = random.randint(0,7)
        y = random.randint(0,7)
        self.knight = [x,y]
        self.board[x][y].touched = True
        print("knight:",x,y)


class GUI:
    def __init__(self):
        self.mw = tk.Tk()
        self.mw.geometry("800x800")

        self.board = board()

        self.buttonFrame = tk.Frame(self.mw)
        self.buttonFrame.place(relx=0,rely=0,relheight=1,relwidth=1)

        self.updateButtons()
        self.mw.mainloop()

    def updateButtons(self):
        for child in self.buttonFrame.winfo_children():
            child.destroy()
        self.buttonsList = []
        for lines in self.board.board:
            
            buttons = []

            for column in lines:
                x = column.x
                y = column.y
                btn = tk.Button(self.buttonFrame,text=f"{x},{y}",width=12,height=5)
                if(self.board.board[x][y].touched):
                    btn.configure(bg="red")

                #lets connect a buttons to functions. Send x and y as parameters.
                btn.configure(command=lambda x = x,y=y:self.touchInto(x,y) )
                btn.grid(row=x,column=y)

                buttons.append(btn)

            self.buttonsList.append(buttons)
                
    def touchInto(self,x,y):
        #when you clicked button, this function going to run
        if(self.board.moveKnight(x,y)):
            self.board.board[x][y].touched = True
            self.buttonsList[x][y].configure(bg="red")
        else:
            print("cannot move!")



if __name__ == "__main__":
    GUI()

这是它的外观和输出

Create a cell class and keep information of your made varibales.创建一个单元格 class 并保留您制作的变量的信息。 This way you can add new capabilities into cells easily.通过这种方式,您可以轻松地将新功能添加到单元格中。 Create a board and make an array inside it.创建一个板并在其中创建一个数组。 Create cell instances and place into that array.创建单元格实例并放入该数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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