繁体   English   中英

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

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

我创建了一个程序,让一名骑士绕着棋盘移动,从一个随机位置开始,在不触及同一个方格的情况下触及每个方格。 我试图通过在骑士移动时将正方形(这是一个按钮)的颜色更改为红色来使用 tkinter 来显示此动作。

棋盘由 tkinter 个按钮组成,它们与“正方形”class 相关。程序在创建网格时设置正确的 colors,但在执行过程中不会更改它们。

这是简化的代码(按照指示提供)。 简化后的代码并不是全部代码,只是创建棋盘并将骑士放置在随机位置的实例。 当骑士被放置时,按钮的颜色应该改变。

    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()

我试过使用 self.board_btn_object.change(bg="red") and.update and.after.... 没有任何方法可以改变颜色。

如果我更改代码并绑定左键单击以将按钮更改为红色,则可以正常工作; 但是,我希望它在 KNIGHT 放置在那里时发生变化。

你只是把一切都复杂化了。 创建一个单元格 class 并在其中保留 x,y 和 iftouched 的信息。 通过这种方式,您可以轻松地将新功能添加到单元格中。 创建一个板并在其中创建一个数组。 创建单元格实例并放入该数组。 无论你做什么,你都应该在这个板子里做。 定义规则、移动功能等。GUI 应该只是这个假想板的幻觉。 当事情变得复杂时,您只需根据您的电路板更新您的用户界面!

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()

这是它的外观和输出

创建一个单元格 class 并保留您制作的变量的信息。 通过这种方式,您可以轻松地将新功能添加到单元格中。 创建一个板并在其中创建一个数组。 创建单元格实例并放入该数组。

暂无
暂无

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

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