为什么随着时间的流逝,我的Tkinter窗口会变得越来越滞后

时间:2019-11-15 14:57:17

标签: python tkinter

from tkinter import *
import random

tk = Tk()
tk.wm_title("Battleship")
switch = True
game_over = False
labels = []


class player:
    def __init__(self):
        self.switchuser = False
        self.placedships = []
        self.bombed = []
        self.sunk = []
        self.ship_sizes = [5, 4, 3, 3, 2]
        self.direction = 'v'
        self.player_ocean = []
        temp = []
        for i in range(10):
            for y in range(10):
                temp += [0]
            self.player_ocean += [temp]
            temp = []
        self.selectedCoord = [0, 0]  # [0] = x coord, [1] = y coord
        self.attack_selection = [0, 0]
        self.hits = []
        self.misses = []

    def selectPlacement(self, event, key):
        '''
           initialise column and row index
           condition for different directions
           check if ship placed is off grid or clashes with another ship
           place ship
           add to self.placedships
           remove ship from availiable ships to cycle to next ship
        '''
        clear = True
        col = self.selectedCoord[0]
        row = self.selectedCoord[1]
        print(self.selectedCoord)
        if self.direction == 'v':
            v_range_start = row - self.ship_sizes[0] + 1
            if v_range_start >= 0:  # check if ship will be off the grid
                for cell in range(v_range_start, row + 1):  # check if the ship clashes with existing ships
                    if [cell, col] in self.placedships:
                        clear = False
                        break
                if clear == True:
                    for y in range(v_range_start, row + 1):
                        self.player_ocean[y][col] = 1
                        self.placedships.append([y, col])
                    self.ship_sizes.remove(self.ship_sizes[0])
                    refresh_ocean('place')




        elif self.direction == 'h':
            h_range_end = col + self.ship_sizes[0]
            if 10 > h_range_end:
                for cell in range(col, h_range_end):
                    if [row, cell] in self.placedships:
                        clear = False
                        break
            if clear == True:
                for x in range(col, h_range_end):
                    self.player_ocean[row][x] = 1
                    self.placedships.append([row, x])
                self.ship_sizes.remove(self.ship_sizes[0])
                refresh_ocean('place')

    def selectAttack(self, event):
        col = self.attack_selection[0]
        row = self.attack_selection[1]
        if [row, col] in ai.ai_placedships:
            if [row, col] not in self.hits:
                self.hits.append([row, col])
                print('hit')
        else:
            if [row, col] not in self.misses:
                self.misses.append([row, col])
        # if str(type(event)) == 'tkinter.Event':
        #     return True

        refresh_ocean('attackselection')
        ai.ai_attack()


# forming tkinter window

def baseGrid():
    gridLabel_player = Label(tk,
                             text="Your grid \nA       B       C       D       E       F       G       H       I       J ")
    gridLabel_player.grid(row=0, column=0)
    gridLabel_ai = Label(tk,
                         text="AI's grid \nA       B       C       D       E       F       G       H       I       J ")
    gridLabel_ai.grid(row=0, column=1)
    tk.player_canvas = Canvas(tk, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
    tk.ai_canvas = Canvas(tk, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
    tk.player_canvas.grid(row=1, column=0, padx=50)
    tk.ai_canvas.grid(row=1, column=1, padx=50)
    for x in range(10):
        for y in range(10):
            tk.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
            tk.ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')


def moveShip(event, key):
    print(player1.selectedCoord)
    if event.keysym == 'Down':
        if key == 'place':
            if player1.selectedCoord[1] != 9:
                player1.selectedCoord[1] += 1
        elif key == 'attackselection':
            if player1.attack_selection[1] != 9:
                player1.attack_selection[1] += 1
    elif event.keysym == 'Up':
        if key == 'place':
            if player1.selectedCoord[1] != 0:
                player1.selectedCoord[1] -= 1
        elif key == 'attackselection':
            if player1.attack_selection[1] != 0:
                player1.attack_selection[1] -= 1
    elif event.keysym == 'Left':
        if key == 'place':
            if player1.selectedCoord[0] != 0:
                player1.selectedCoord[0] -= 1

        elif key == 'attackselection':
            if player1.attack_selection[0] != 0:
                player1.attack_selection[0] -= 1
    elif event.keysym == 'Right':
        if key == 'place':
            if player1.selectedCoord[0] != 9:
                player1.selectedCoord[0] += 1
        elif key == 'attackselection':
            if player1.attack_selection[0] != 9:
                player1.attack_selection[0] += 1

    for y in range(10):
        for x in range(10):
            if key == 'place':
                if [y, x] == player1.selectedCoord or [x, y] in player1.placedships:
                    player1.player_ocean[x][y] = 1
                else:
                    player1.player_ocean[x][y] = 0
            # elif key == 'attackselection':
            #     if [y,x] == player1.attack_selection or [x,y] in player1.hits:
            #         ai.ai_ocean[x][y] = 1
            #     else:
            #         ai.ai_ocean[x][y] = 0

    refresh_ocean(key)


def changedir(event):
    if player1.direction == 'v':
        player1.direction = 'h'
    elif player1.direction == 'h':
        player1.direction = 'v'


def refresh_ocean(key):
    print('function call')
    for y in range(10):
        for x in range(10):
            colour = 'white'
            if key == 'place':
                if [y, x] in player1.placedships:
                    colour = 'green'
                if [x, y] == player1.selectedCoord:
                    colour = 'yellow'
                tk.player_canvas.itemconfig(
                    tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30, fill=colour))

            elif key == 'attackselection':
                # print('miss',ai.AI_miss,'\nhits',ai.destroyed_cords,'\nships',player1.placedships)
                if [y, x] in player1.placedships:
                    tk.player_canvas.itemconfig(
                        tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='green')
                if [y, x] in ai.AI_miss:
                    tk.player_canvas.itemconfig(
                        tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='gray')

                if [y, x] in ai.destroyed_cords:
                    tk.player_canvas.itemconfig(
                        tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='red')
                if [y, x] in player1.hits:
                    colour = 'red'
                if [y, x] in player1.misses:
                    colour = 'gray'
                if [x, y] == player1.attack_selection:
                    colour = 'yellow'

                tk.ai_canvas.itemconfig(
                    tk.ai_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill=colour)

            # else:
            #     tk.player_canvas.itemconfig(
            #         tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30, fill='white'))
def attackGui():
    tk.bind("<Key>", lambda event: moveShip(event, 'attackselection'))
    tk.bind("<Return>", lambda event: player1.selectAttack(event))



class Ai(player):
    def __init__(self):
        #  = [[[9,0], [9, 1], [9, 2], [9, 3], [9, 4]], [[9, 5], [9, 6]]]
        # player1.placedships = [[[9, 0], [8, 0], [7, 0], [6, 0], [5, 0]], [[4, 0], [3, 0]]]
        self.destroyed_ships = []
        self.destroyed_cords = []
        self.AI_miss = []
        self.fmove_check = True
        self.mdirection = 1
        self.ai_placedships = []
        self.directions = ['v', 'h']
        self.ship_sizes = [5, 4, 3, 3, 2]
        self.currentcoord = [0,0]
    def ai_attack(self):
        def first_move(self):
            self.missed = 0
            self.AIx = random.randint(0, 9)
            self.AIy = random.randint(0, 9)
            self.AIsel_cords = [self.AIy, self.AIx]
            while self.AIsel_cords in self.AI_miss or self.AIsel_cords in self.destroyed_cords:
                self.AIx = random.randint(0, 9)
                self.AIy = random.randint(0, 9)
                self.AIsel_cords = [self.AIy, self.AIx]
                self.currentcoord = self.AIsel_cords

            if self.AIsel_cords in player1.placedships:
                # self.ship_check = ship
                self.destroyed_cords.append(player1.placedships.pop(player1.placedships.index(self.AIsel_cords)))
                self.fmove_check = False
            else:
                self.AI_miss.append(self.AIsel_cords)

        def fol_move(self):

            checked = False
            self.entered = False
            # direction check
            if self.mdirection > 4:
                self.mdirection = 1

            # up
            elif self.mdirection == 1 and self.AIy - 1 >= 0:
                self.entered = True
                self.AIy -= 1
                self.currentcoord[0] -= 1
                # to find whether the cords are part of a ship
                if [self.AIy, self.AIx] in player1.placedships:
                    # if [self.AIx, self.AIy] in self.ship_check:
                    #     self.destroyed_cords.append(ship.pop(ship.index([self.AIx, self.AIy])))
                    # else:
                    #     self.destroyed_cords +=
                    self.destroyed_cords.append(
                        player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
                    checked = True
                # add the cords that are not part of a ship into AI_miss
                else:
                    self.AI_miss.append([self.AIy, self.AIx])
                    self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
                    self.mdirection += 1
                    self.missed += 1
            # left
            elif self.mdirection == 2 and self.AIx - 1 >= 0:
                self.entered = True
                self.AIx -= 1
                self.currentcoord[1] -= 1
                # to find whether the cords are part of a ship
                if [self.AIy, self.AIx] in player1.placedships:
                    self.destroyed_cords.append(
                        player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
                    checked = True
                # add the cords that are not part of a ship into AI_miss
                else:
                    self.AI_miss.append([self.AIy, self.AIx])
                    self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
                    self.mdirection += 1
                    self.missed += 1
            # down
            elif self.mdirection == 3 and self.AIy + 1 <= 9:
                self.entered = True
                self.AIy += 1
                self.currentcoord[0] += 1
                # to find whether the cords are part of a ship
                if [self.AIy, self.AIx] in player1.placedships:
                    self.destroyed_cords.append(
                        player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
                    checked = True
                # add the cords that are not part of a ship into AI_miss
                else:
                    self.AI_miss.append([self.AIy, self.AIx])
                    self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
                    self.mdirection += 1
                    self.missed += 1
            # right
            elif self.mdirection == 4 and self.AIx + 1 <= 9:
                self.entered = True
                self.AIx += 1
                self.currentcoord[1] += 1
                # to find whether the cords are part of a ship
                if [self.AIy, self.AIx] in player1.placedships:
                    self.destroyed_cords.append(
                        player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
                    checked = True
                # add the cords that are not part of a ship into AI_miss
                else:
                    self.AI_miss.append([self.AIy, self.AIx])
                    self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
                    self.mdirection += 1
                    self.missed += 1
            elif not self.entered:
                self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
                self.mdirection += 1
            if self.missed == 2:
                self.missed = 0
                self.fmove_check = True

        if self.fmove_check:
            first_move(self)
        elif not self.fmove_check:
            fol_move(self)
            if not self.entered:
                fol_move(self)


        # print('\n', self.destroyed_cords)
        # print(player1.placedships)
        # print(self.AI_miss)

    def ai_place(self):
        print(len(ai.ship_sizes))
        ai_dir = random.choice(self.directions)
        col = random.randint(0, 9)
        row = random.randint(0, 9)

        clear = True
        if ai_dir == 'v':
            v_range_start = row - self.ship_sizes[0] + 1
            if v_range_start >= 0:  # check if ship will be off the grid
                for cell in range(v_range_start, row + 1):  # check if the ship clashes with existing ships
                    if [cell, col] in self.ai_placedships:
                        clear = False
                        break
                if clear == True:
                    for y in range(v_range_start, row + 1):
                        self.ai_placedships.append([y, col])
                    self.ship_sizes.remove(self.ship_sizes[0])



        elif ai_dir == 'h':
            h_range_end = col + self.ship_sizes[0]
            if 10 > h_range_end:
                for cell in range(col, h_range_end):
                    if [row, cell] in self.ai_placedships:
                        clear = False
                        break
                if clear == True:
                    for x in range(col, h_range_end):
                        self.ai_placedships.append([row, x])
                    self.ship_sizes.remove(self.ship_sizes[0])
attackinstructionLabel = Label(tk, text="Arrow keys to move selection"
                                            "\nEnter to shoot at selected cell"
                                            "\nGrey cells are missed ships"
                                            "\nRed cells are hit ships")
attackinstructionLabel.grid(row=2)

instructionLabel = Label(tk, text="Arrow keys to move selection"
                                      "\nRight shift to change ship orientation"
                                      "\nEnter to place ship"
                                      "\nYellow cells means that you are selecting a cell to place the next ship in"
                                      "\nGreen cells show placed ships")

instructionLabel.grid(row=2)
tk.bind("<Key>", lambda event: moveShip(event, 'place'))
tk.bind("<Shift_R>", changedir)
tk.bind("<Return>", lambda event: player1.selectPlacement(event, 'place'))
base = baseGrid()
player1 = player()
ai = Ai()
while True:
    tk.update()
    tk.update_idletasks()
    if len(player1.ship_sizes) != 0:
        if len(ai.ship_sizes) != 0:
            ai_place = ai.ai_place()
        refresh_ocean('place')
    else:
        if (sorted(player1.hits) != sorted(ai.ai_placedships)) and len(player1.placedships) != 0:
            attack = attackGui()
            instructionLabel.destroy()
            refresh_ocean('attackselection')

        else:
            popup = Tk()
            p_label = Label(popup,text='GAME OVER')
            popup.after(5000,p_label.destroy())
            tk.destroy()

我尝试取出在while循环中运行的所有代码,这些代码在程序中创建了其他内容,但仍然明显滞后。我现在唯一可以识别的问题可能是refresh_ocean函数,它是在while循环中处理gui的唯一事物,但是它使用了itemconfig方法,该方法不应在gui <上添加任何内容/ p>

1 个答案:

答案 0 :(得分:0)

我认为您正在使用:

tk.player_canvas.itemconfig不好。

 tk.player_canvas.itemconfig(
                        tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='green')

您正在创建越来越多的矩形。 这是我在tkinter画布上处理网格的常用方法

grid = [[0 for x in range(10)] for y in range(10)]
for x in range(10):
    for y in range(10):
        grid[x][y] = tk.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')

    tk.player_canvas.itemconfig( grid[x][y], fill="blue")