#python #tkinter #tkinter-canvas
#python #tkinter #tkinter-canvas
Вопрос:
Я пытаюсь создать графический интерфейс для представления графической интерпретации группы симметрии треугольника (т. Е. отражений и поворотов равностороннего треугольника, который оставляет его неизменным). В идеале я хотел бы сделать это анимированным способом, но это выше моего понимания, поэтому я просто меняю метки на точках и хотел бы сделать это с помощью кнопки для отражения или для поворота, но я не могу заставить кнопки фактически изменять значение координат, которые мне нужны.
Я пытаюсь поменять местами координаты p1, p2 и p3 в приведенном ниже коде `
def rf(p1, p2, p3):
p4=p3
p3=p2
p2=p4
def ro(p1, p2, p3):
p4=p1
p1=p2
p2=p3
p3=p4
print(p4)
def buttons(p1, p2, p3):
l=tk.Button(top, text="Rotate", command=ro(p1, p2, p3))
k=tk.Button(top, text="Reflect", command=rf(p1, p2, p3))
triangle(p1, p2, p3)
text(p1, p2)
k.pack()
l.pack()
buttons(p1, p2, p3)
top.mainloop()
`
когда я запускаю его и нажимаю кнопку поворота, p1 печатает с исходным значением и печатает только один раз, независимо от того, сколько раз нажата кнопка. Как я могу это исправить, и есть ли лучший пакет, который действительно сможет это анимировать? Спасибо!
Ответ №1:
Вы не можете передавать аргументы командам в такой кнопке. То, что вы сделали, на самом деле оценивает ro (p1, p2, p3) при создании кнопки, принимает возврат этого метода (который равен None) и сохраняет его как команду. Итак, когда вы нажимаете кнопку, она вызывает None …. что, конечно, ничего не делает.
Обычно, когда вы создаете кнопку, команда должна содержать только ИМЯ МЕТОДА, например: l = tk.Button(top, text=»Rotate», command=ro)
Это особенность Python, где вы можете обрабатывать целые методы так, как будто они являются переменными. Так что, возможно, сделайте это и измените метод, чтобы он был примерно таким:
def ro():
p4=p1
p1=p2
p2=p3
p3=p4
print(p4)
Если вам действительно нужно передавать аргументы, это наиболее распространенный обходной путь:
l = tk.Button(top, text="Rotate", command=lambda: ro(p1, p2, p3)
Существует довольно длинное объяснение того, почему это работает, вы можете посмотреть, что делает ключевое слово lambda в python, чтобы лучше понять его.
Редактировать, как указано в комментариях:
Использование ваших переменных таким образом, каким вы являетесь, может привести к возникновению некоторых странных вещей. А именно, что он не будет «сохранять» изменения в переменных. Это происходит потому, что переменные, с которыми вы работаете, имеют область действия, ограниченную функцией, в которой они используются. То есть используемые вами имена создаются в функции, поэтому они удаляются после завершения функции. Есть несколько способов исправить это.
Один из способов сделать это — сохранить имена глобально, удалить аргументы и сообщить функции, что они являются глобальными:
p1 = 5 # these are just examples, make sure they are established
p2 = 7 # on the root level, or at least on the level that your
p3 = 12 # button is made or lower
def ro():
global p1, p2, p3 # this will insist on using the globally named variables and not things specific to this function
p1, p2, p3 = p2, p3, p1 # oh, btw, you can do this to save space and not have to make a p4
В этом случае вам придется отказаться от лямбда-выражения и просто вызвать ‘ro’ в качестве команды.
Это будет делать то, что вы хотите, но имеет пару проблем:
- вы не можете использовать метод ro() ни для чего другого, кроме поворота этих трех вещей
- использование ключевого слова ‘global’ обычно не одобряется, и я лично никогда его не использую
Чем вы можете быть довольны, так это чем-то более похожим на это:
p = [14, 12, 83]
q = [1, 43, 18, 75]
def ro(x):
first = x.pop(0)
x.append(first)
print(p)
ro(p)
print(p)
print()
print(q)
ro(q)
print(q)
Если вы запустите это, вы увидите, что оно поворачивает все числа в произвольном списке.
Таким образом, вы можете сохранить свои треугольники в списке, а затем создать свою кнопку следующим образом:
l=tk.Button(top, text="Rotate", command=lambda: ro(p))
и это изменит список, предоставленный команде ro(), и вам не нужно будет беспокоиться о том, в какой области видимости находится переменная, потому что вы передаете ее с ‘p’ в ro(p)
, и это вносит изменения во все, что передается.
Я надеюсь, что это поможет.
Комментарии:
1. Спасибо, это работает с лямбдой, однако, похоже, что это не приводит к постоянному изменению значения p1, которое необходимо для перехода к следующему значению поворота, нет предложений по этому поводу?
2. Да, Python имеет несколько запутанных уровней области видимости для переменных, и я уверен, что именно это здесь и происходит. Я отредактирую свой ответ, чтобы я мог объяснить его немного подробнее, чем может сделать комментарий, подобный этому.
3. Большое вам спасибо, прошло некоторое время с тех пор, как я работал на python, в основном использую C, поэтому я довольно незнаком с соглашениями о глобальных переменных! —теперь помечено как правильное!