0

まず始めに、私は Tkinter を使用するのに非常に慣れていません。

私が抱えている問題は、オブジェクト タイプが 1 つしかない場合にコードが機能することです。そのタグ タイプの唯一のタグである場合、正しく相互作用します。したがって、実行するたびに 1 つの「ボート」と 100 の「シェル」がある場合、正しく実行されます。

このコードは、2 つのオブジェクト間に衝突があるかどうかを検出し、現在選択されているアイテムの色をランダムに変更します。そのため、現在タグ タイプが 1 つしかない限り、正しく機能します。「ボート」をクリックして「シェル」にドラッグすると、色が切り替わります。次に、100 個のシェルのうちの 1 つを取得して同じことを行うと、このエラーが発生します。

特定のタイプのオブジェクトが 1 つしかなく、他のオブジェクトが無限にある場合に正しく機能する理由がわかりませんが、タグタイプが複数ある場合は失敗します。

選択したオブジェクトのID番号を正しく選択するので、今迷っており、助けていただければ幸いです。

以下は、受け取ったエラーと使用しているコードです。必要なタスクを実行するために必要な重要な部品です。ただし、衝突コードはコードと同じです。


Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python34\lib\tkinter\__init__.py", line 1487, in __call__
    return self.func(*args)
  File "H:/Charles Engen/PycharmProjects/Battleship/BattleShipGUI.py", line 112, in on_token_motion
    self.collision_detection(event)
  File "H:/Charles Engen/PycharmProjects/Battleship/BattleShipGUI.py", line 85, in collision_detection
    self.canvas.itemconfig(current_token, outline=_random_color())
  File "C:\Python34\lib\tkinter\__init__.py", line 2385, in itemconfigure
    return self._configure(('itemconfigure', tagOrId), cnf, kw)
  File "C:\Python34\lib\tkinter\__init__.py", line 1259, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: unknown option "22"

import tkinter as tk
from random import randint

HEIGHT = 400
WIDTH = 680

def _random_color():
    '''Creates a random color sequence when called'''
    random_color = ("#"+("%06x" % randint(0, 16777215)))
    return random_color

class Board(tk.Tk):
    '''Creates a Board Class'''

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.menu_item = tk.Menu(self)
        self.file_menu = tk.Menu(self.menu_item, tearoff=0)
        self.file_menu.add_command(label='New', command=self.new_game)
        self.file_menu.add_command(label='Exit', command=self.quit)

        self.config(menu=self.file_menu)

        self.canvas = tk.Canvas(width=WIDTH, height=HEIGHT)
        self.canvas.pack(fill='both', expand=True)

        # adds variable that keeps track of location
        self._token_location_data = {"x": 0, "y": 0, "item": None}


    def _create_object(self, coord, fcolor, color, token_name):
        '''Creates an object with a tag, each object is assigned the ability to be clicked and dragged'''
        (x, y) = coord
        if token_name == 'boat':
            points = [10+x, 10+y, 20+x, 20+y, 110+x, 20+y, 120+x, 10+y, 80+x,
                      10+y, 80+x, 0+y, 60+x, 0+y, 60+x, 10+y]
            self.canvas.create_polygon(points, outline=fcolor, fill=color, width=3, tag=token_name)
        elif token_name == 'shell':
            self.canvas.create_oval(0+x, 0+y, 10+x, 10+y, outline=fcolor, fill=color, width=3, tag=token_name)
        self.canvas.tag_bind(token_name, '<ButtonPress-1>', self.on_token_button_press)
        self.canvas.tag_bind(token_name, '<ButtonRelease-1>', self.on_token_button_press)
        self.canvas.tag_bind(token_name, '<B1-Motion>', self.on_token_motion)

    def collision_detection(self, event):
        '''This function tracks any collision between the boat and shell objects'''
        # I will upgrade this to take any object collision
        token = self.canvas.gettags('current')[0]
        current_token = self.canvas.find_withtag(token)

        x1, y1, x2, y2 = self.canvas.bbox(token)
        overlap = self.canvas.find_overlapping(x1, y1, x2, y2)

        for item in current_token:
            for over in overlap:
                if over != item:
                    # Changes the color of the object that is colliding.
                    self.canvas.itemconfig(current_token, outline=_random_color())

    # The following three functions are required to just move the tokens
    def on_token_button_press(self, event):
        '''Adds ability to pick up tokens'''
        # Stores token item's location data
        self._token_location_data['item'] = self.canvas.find_closest(event.x, event.y)[0]
        self._token_location_data['x'] = event.x
        self._token_location_data['y'] = event.y

    def on_token_button_release(self, event):
        '''Adds ability to drop token'''
        # Resets the drag
        self._token_location_data['item'] = self.canvas.find_closest(event.x, event.y)
        self._token_location_data['x'] = event.x
        self._token_location_data['y'] = event.y

    def on_token_motion(self, event):
        '''Adds ability to keep track of location of tokens as you drag them'''
        # Computes how much the object has moved
        delta_x = event.x - self._token_location_data['x']
        delta_y = event.y - self._token_location_data['y']
        # move the object the appropriate amount
        self.canvas.move(self._token_location_data['item'], delta_x, delta_y)
        # record the new position
        self._token_location_data['x'] = event.x
        self._token_location_data['y'] = event.y
        # Detects collision between objects
        self.collision_detection(event)

    def new_game(self):
        '''Creates new game by deleting the current canvas and creating new objects'''
        # Deletes current canvas
        self.canvas.delete('all')
        # runs the create board mechanism
        self._generate_board()
        # adds code to create a shell and boat on the screen from the appropriate function
        for i in range(1):
            self._create_object((410, 15*i), _random_color(), _random_color(), 'boat')
        for i in range(4):
            for j in range(10):
                self._create_object((590+(i*10), 15*j), _random_color(), _random_color(), 'shell')

def main():
    app = Board()
    app.mainloop()

if __name__ == '__main__':
    main()
4

1 に答える 1