_tkinter.TclError:unknown option "23" Code works with few object, but not with many
_tkinter.TclError:unknown option "23" Code works with few object, but not with many
首先,我对使用 Tkinter 非常陌生,
我遇到的问题是,如果我只有一种对象类型,我的代码就可以工作。如果它是该标签类型中的唯一一种,它将正确交互。因此,如果每次执行时我有一个 'boat' 和 100 个 'shells',它就会正确执行。
该代码检测两个对象之间是否存在碰撞,然后将当前选定项目的颜色更改为随机颜色。因此,只要当前只有一种标签类型,它就可以正常工作。因此,如果我单击 'boat' 并将其拖动到 'shell' 中,它会切换颜色。然后,如果我取 100 个 'shell' 中的 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()
为了运行代码,我去掉了对不存在的._generate_board
的调用。在此之后,我得到了同样的错误,但有未知的选项“3”。
异常是由于传递给 self.canvas.itemconfig
一个 id 元组引起的,您将其误称为 current_token
,而不是标签或 id。由于 _flatten
调用,单例是可以容忍的,但任何更多都会成为错误。我很确定“3”是 shell 元组的第二个成员并非巧合。传递 token
而不是停止异常。另外,第一次调用 itemconfig
后应该有一个中断。
但是,shell 被视为一个组,边界框包含所有 shell,overlap
包含所有 shell。这就是为什么将一个 shell 与其他 shell 移开被视为碰撞的原因。此时,所有 shell 都将随机分配到一种新颜色(如果移动了一个)。要解决此问题,应将令牌设置为 on_token_button_press
中设置的单个项目,而不是标签组。这实现了你的待办事项。这是结果。
def collision_detection(self, event):
'''Detect collision between selected object and others.'''
token = self._token_location_data['item']
x1, y1, x2, y2 = self.canvas.bbox(token)
overlap = self.canvas.find_overlapping(x1, y1, x2, y2)
for over in overlap:
if over != token:
# Changes the color of the object that is colliding.
self.canvas.itemconfig(token, outline=_random_color())
break
一个小问题是,您为每个 shell(在 _create_object
中)为 'shell' 执行标签绑定。相反,将标签绑定在 new
中,这样它们完成一次。
for tag in 'boat', 'shell':
self.canvas.tag_bind(tag, '<ButtonPress-1>', self.on_token_button_press)
self.canvas.tag_bind(tag, '<ButtonRelease-1>', self.on_token_button_press)
self.canvas.tag_bind(tag, '<B1-Motion>', self.on_token_motion)
首先,我对使用 Tkinter 非常陌生,
我遇到的问题是,如果我只有一种对象类型,我的代码就可以工作。如果它是该标签类型中的唯一一种,它将正确交互。因此,如果每次执行时我有一个 'boat' 和 100 个 'shells',它就会正确执行。
该代码检测两个对象之间是否存在碰撞,然后将当前选定项目的颜色更改为随机颜色。因此,只要当前只有一种标签类型,它就可以正常工作。因此,如果我单击 'boat' 并将其拖动到 'shell' 中,它会切换颜色。然后,如果我取 100 个 'shell' 中的 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()
为了运行代码,我去掉了对不存在的._generate_board
的调用。在此之后,我得到了同样的错误,但有未知的选项“3”。
异常是由于传递给 self.canvas.itemconfig
一个 id 元组引起的,您将其误称为 current_token
,而不是标签或 id。由于 _flatten
调用,单例是可以容忍的,但任何更多都会成为错误。我很确定“3”是 shell 元组的第二个成员并非巧合。传递 token
而不是停止异常。另外,第一次调用 itemconfig
后应该有一个中断。
但是,shell 被视为一个组,边界框包含所有 shell,overlap
包含所有 shell。这就是为什么将一个 shell 与其他 shell 移开被视为碰撞的原因。此时,所有 shell 都将随机分配到一种新颜色(如果移动了一个)。要解决此问题,应将令牌设置为 on_token_button_press
中设置的单个项目,而不是标签组。这实现了你的待办事项。这是结果。
def collision_detection(self, event):
'''Detect collision between selected object and others.'''
token = self._token_location_data['item']
x1, y1, x2, y2 = self.canvas.bbox(token)
overlap = self.canvas.find_overlapping(x1, y1, x2, y2)
for over in overlap:
if over != token:
# Changes the color of the object that is colliding.
self.canvas.itemconfig(token, outline=_random_color())
break
一个小问题是,您为每个 shell(在 _create_object
中)为 'shell' 执行标签绑定。相反,将标签绑定在 new
中,这样它们完成一次。
for tag in 'boat', 'shell':
self.canvas.tag_bind(tag, '<ButtonPress-1>', self.on_token_button_press)
self.canvas.tag_bind(tag, '<ButtonRelease-1>', self.on_token_button_press)
self.canvas.tag_bind(tag, '<B1-Motion>', self.on_token_motion)