#python #tkinter #canvas #coordinates #polygon
#python #tkinter #холст #координаты #полигон
Вопрос:
Я создаю и пользовательский интерфейс для танграма (головоломки с разными полигонами), используя tkinter на Python, и я хотел бы отслеживать координаты каждой точки каждого полигона, когда они перемещаются по моему холсту.
Для этого я создал этот класс:
class Polygon:
def __init__(self, coords, color, canvas):
self.coords = coords
self.color = color
self.move = False
canvas.bind('<Button-1>', self.start_movement)
canvas.bind('<Motion>', self.movement)
canvas.bind('<ButtonRelease-1>', self.stopMovement)
canvas.bind('<Button-3>', self.rotate)
canvas.create_polygon(self.coords, fill=self.color)
Каждый полигон создается таким образом :
medium_triangle = Polygon((0,0, 100*math.sqrt(2),0, 0,100*math.sqrt(2)),
'red', drawing_place)
small_triangle_1 = Polygon((0,0 ,100,0, 0,100), 'purple', drawing_place)
[...]
big_triangle_2 = Polygon((0,0, 200,0, 0,200), 'green', drawing_place)
Моя главная проблема в том, что, похоже, я могу изменить только coords
атрибут последнего Polygon
созданного.
Я использую мышь, чтобы перетаскивать фрагменты на моем холсте, и я использую эти методы, чтобы заставить мои полигоны двигаться:
def start_movement(self, event):
self.move = True
# Translate mouse coordinates to canvas coordinate
self.initi_x = drawing_place.canvasx(event.x)
self.initi_y = drawing_place.canvasy(event.y)
self.movingimage = drawing_place.find_closest(self.initi_x, self.initi_y,
halo=1) # get canvas object
# ID of where mouse
# pointer is.
def movement(self, event):
if self.move:
end_x = drawing_place.canvasx(event.x) # Translate mouse x screen
# coordinate to canvas coordinate.
end_y = drawing_place.canvasy(event.y) # Translate mouse y screen
# coordinate to canvas coordinate.
deltax = end_x - self.initi_x # Find the difference
deltay = end_y - self.initi_y # Find the difference
self.newPosition(deltax, deltay)
self.initi_x = end_x # Update previous current with new location
self.initi_y = end_y
drawing_place.move(self.movingimage, deltax, deltay) # Move object
def stopMovement(self, event):
self.move = False
affichage(self)
Мне удается добавить к моим начальным координатам смещение, которое было выполнено благодаря моему методу new_position :
def newPosition(self, deltax, deltay):
coord = self.coords # Retrieve object points coordinates
old_coord = list(coord) # Tuple to List
c = [] # New coords
i = 0 # Cursor on old_coord
for coordinates in old_coord:
# check if index of coordinates in range of i and len(old_coord)
# in old_coord is pair (x coord).
if (old_coord.index(coordinates, i, len(old_coord)) % 2) == 0:
c.append(coordinates deltax)
else: # index's impair => y-coord
c.append(coordinates deltay)
i = 1
coord2 = tuple(c) # List to Tuple
self.set_coords(coord2)
def set_coords(self, coords):
self.coords = coords
Но, как вы можете видеть прямо здесь, в моей консоли
just after medium_triangle declaration:
(0, 0, 141.4213562373095, 0, 0, 141.4213562373095)
(0, 0, 200, 0, 0, 200)
(0, 0, 200, 0, 0, 200)
(0, 0, 200, 0, 0, 200)
(0, 0, 200, 0, 0, 200)
(297.0, 61.0, 497.0, 61.0, 297.0, 261.0)
(551.0, 166.0, 751.0, 166.0, 551.0, 366.0)
(951.0, 250.0, 1151.0, 250.0, 951.0, 450.0)
Во время объявления моих полигонов я, кажется, могу печатать их координаты с medium_triangle.coords
помощью, но после, когда я нажимаю на свой холст, он напрямую отображает координаты последнего объявленного. И когда я перемещаю другой фрагмент на своем холсте, он просто добавляет то же Polygon
самое.
Я не совсем разбираюсь в классах, методах и т. Д., Но я думал, что понял, что каждый из моих полигонов был другим экземпляром моего класса, но, несмотря на это, похоже, что я могу получить доступ только к одному экземпляру Polygon
.
Надеюсь, моя проблема ясна, действительно ли я создал разные полигоны, и если да, то почему я не могу изменить их отдельно?
Комментарии:
1. Вам необходимо включить определение метода класса.
set_coords()
2. Спасибо, что указали на эту проблему, я отредактировал свой пост и поместил метод класса
set_coords()
в его конец3. Все еще не уверен, что понимаю, в чем проблема. Однако я отмечаю, что
newPosition()
метод изменяет координатыPolygon
экземпляра, через который он вызывается (т. Е. На месте). Похоже, что выPolygon
где-то копируете экземпляр, но я не вижу никакого кода, делающего это, но это может иметь какое-то отношение к проблеме.
Ответ №1:
canvas.bind('<Button-1>', self.start_movement)
canvas.bind('<Motion>', self.movement)
canvas.bind('<ButtonRelease-1>', self.stopMovement)
canvas.bind('<Button-3>', self.rotate)
Ваш холст (типа Canvas
, или я так полагаю) может быть привязан только к одному действию для каждого ключа. Попробуйте этот код:
canvas.bind('<Button-1>', self.start_movement)
canvas.bind('<Button-1>', lambda e: print("ok"))
… и вы увидите, что он больше не будет вызываться start_movement()
, потому что вместо этого будет вызываться лямбда.
Здесь единственными функциями, привязанными к холсту, являются те, которые вы вызывали в последний раз: то есть те, которые были инициализированы последним Polygon
, который вы создали. Привязывая новые методы, вы удаляли предыдущие привязки к тем же ключам.
Ответ №2:
Вы не должны использовать canvas.bind(...)
Polygon
класс inside. Используйте canvas.tag_bind(...)
вместо:
class Polygon:
def __init__(self, coords, color, canvas):
self.coords = coords
self.color = color
self.move = False
self.canvas = canvas
self.id = canvas.create_polygon(self.coords, fill=self.color)
canvas.tag_bind(self.id, '<Button-1>', self.start_movement)
canvas.tag_bind(self.id, '<Motion>', self.movement)
canvas.tag_bind(self.id, '<ButtonRelease-1>', self.stopMovement)
canvas.tag_bind(self.id, '<Button-3>', self.rotate)
Обратите внимание, что я сохранил переданную canvas
переменную экземпляра self.canvas
. Вы должны заменить все drawing_place
на self.canvas
внутри других методов класса.
Также вам не нужно вызывать следующую строку внутри start_movement()
:
self.movingimage = drawing_place.find_closest(self.initi_x, self.initi_y,
halo=1) # get canvas object
# ID of where mouse
# pointer is.
As self.id
может использоваться вместо результата find_closest()
внутри movement()
:
def movement(self, event):
if self.move:
end_x = self.canvas.canvasx(event.x) # Translate mouse x screen
# coordinate to canvas coordinate.
end_y = self.canvas.canvasy(event.y) # Translate mouse y screen
# coordinate to canvas coordinate.
deltax = end_x - self.initi_x # Find the difference
deltay = end_y - self.initi_y # Find the difference
self.newPosition(deltax, deltay)
self.initi_x = end_x # Update previous current with new location
self.initi_y = end_y
self.canvas.move(self.id, deltax, deltay) # Move object