Как исправить зависание интерфейса?
Знаю, есть несколько тем на эту тему и практически везде помогает использование after.
Я хотел узнать как можно конкретно в моей программе это исправить?
Что должна делать программа в целом:
Есть квадрат, середины его сторон сжимаются до образования креста, а затем разжимаются. И так циклически. У меня же квадрат сжимается, но когда должно происходить разжимание, интерфейс виснет.
Код:
import time
from tkinter import *
root = Tk()
root.title('main')
root.geometry('600x800')
c = Canvas(width=600, height=800, bg='white')
c.place(x=0, y=0)
n = 8
def start():
global l1, l2, l3, l4, l5, l6, l7, l8
l1 = c.create_line(200, 100, 300, 100)
l2 = c.create_line(300, 100, 400, 100)
l3 = c.create_line(400, 100, 400, 200)
l4 = c.create_line(400, 200, 400, 300)
l5 = c.create_line(400, 300, 300, 300)
l6 = c.create_line(300, 300, 200, 300)
l7 = c.create_line(200, 300, 200, 200)
l8 = c.create_line(200, 200, 200, 100)
def delete_line():
c.after(10, c.delete, l1)
c.after(10, c.delete, l2)
c.after(10, c.delete, l3)
c.after(10, c.delete, l4)
c.after(10, c.delete, l5)
c.after(10, c.delete, l6)
c.after(10, c.delete, l7)
c.after(10, c.delete, l8)
def move():
s = c.coords(l1)
s1 = c.coords(l3)
print(s1)
s2 = c.coords(l5)
s3 = c.coords(l7)
if s[3] < 200:
s[3] = s[3] + n
c.coords(l1, 200, 100, 300, s[3])
c.coords(l2, 300, s[3], 400, 100)
print(s)
print(s[3])
c.after(0)
if s1[2] > 300:
s1[2] = s1[2] - n
c.coords(l3, 400, 100, s1[2], 200)
c.coords(l4, s1[2], 200, 400, 300)
c.after(0)
if s2[3] > 200:
s2[3] = s2[3] - n
c.coords(l5, 400, 300, 300, s2[3])
c.coords(l6, 300, s2[3], 200, 300)
c.after(0)
if s3[2] < 300:
s3[2] = s3[2] + n
c.coords(l7, 200, 300, s3[2], 200)
c.coords(l8, s3[2], 200, 200, 100)
c.after(0)
#global t
#t = root.after(100, move)
if not (s[3] < 200 and s1[2] > 300 and s2[3] > 200 and s3[2] < 300):
#delete_line()
#start()
while s[3] > 200:
c.coords(l1, 200, 100, 300, s[3])
c.coords(l2, 300, s[3], 400, 100)
s[3] = s[3] + n
c.after(100)
# if s[3] > 200:
# s[3] = s[3] - n
# c.coords(l1, 200, 100, 300, s[3])
# c.coords(l2, 300, s[3], 400, 100)
# c.after(0)
# print(s)
# if s1[2] < 300:
# s1[2] = s1[2] + n
# c.coords(l3, 400, 100, s1[2], 200)
# c.coords(l4, s1[2], 200, 400, 300)
# c.after(0)
# print(s1)
# if s2[3] < 200:
# s2[3] = s2[3] + n
# c.coords(l5, 400, 300, 300, s2[3])
# c.coords(l6, 300, s2[3], 200, 300)
# c.after(0)
# if s3[2] > 300:
# s3[2] = s3[2] - n
# c.coords(l7, 200, 300, s3[2], 200)
# c.coords(l8, s3[2], 200, 200, 100)
# c.after(0)
global t
t = root.after(100, move)
def stop():
root.after_cancel(t)
b1 = Button(text='Запуск', command=move)
b1.pack()
b2 = Button(text='Стоп', command=stop)
b2.pack()
start()
# x=300,y=200 координаты центра.
root.mainloop()
Ответы (1 шт):
Автор решения: insolor
→ Ссылка
- Не должно быть цикла
while, цикл должен быть полностью организован через планирование выполнения функции с помощью методаafter. - Разбиваете на две функции (одна для движения внутрь, другая - наружу), работающие абсолютно аналогично друг другу
- Выпиливаете все вызовы
afterс одним аргументом - они ничего не делают.
def move_in():
global t
s = c.coords(l1)
s1 = c.coords(l3)
print(s1)
s2 = c.coords(l5)
s3 = c.coords(l7)
s[3] = s[3] + n
c.coords(l1, 200, 100, 300, s[3])
c.coords(l2, 300, s[3], 400, 100)
print(s)
print(s[3])
s1[2] = s1[2] - n
c.coords(l3, 400, 100, s1[2], 200)
c.coords(l4, s1[2], 200, 400, 300)
s2[3] = s2[3] - n
c.coords(l5, 400, 300, 300, s2[3])
c.coords(l6, 300, s2[3], 200, 300)
s3[2] = s3[2] + n
c.coords(l7, 200, 300, s3[2], 200)
c.coords(l8, s3[2], 200, 200, 100)
# Условие при котором должно продолжаться движение внутрь
# if s[3] < 200 and s1[2] > 300 and s2[3] > 200 and s3[2] < 300:
if s[3] < 200: # Достаточно проверки одного числа, т.к. все линии движутся согласованно
t = root.after(100, move_in)
else: # Иначе начинаем движение наружу
t = root.after(100, move_out)
def move_out():
global t
s = c.coords(l1)
s1 = c.coords(l3)
print(s1)
s2 = c.coords(l5)
s3 = c.coords(l7)
s[3] = s[3] - n
c.coords(l1, 200, 100, 300, s[3])
c.coords(l2, 300, s[3], 400, 100)
print(s)
print(s[3])
s1[2] = s1[2] + n
c.coords(l3, 400, 100, s1[2], 200)
c.coords(l4, s1[2], 200, 400, 300)
s2[3] = s2[3] + n
c.coords(l5, 400, 300, 300, s2[3])
c.coords(l6, 300, s2[3], 200, 300)
s3[2] = s3[2] - n
c.coords(l7, 200, 300, s3[2], 200)
c.coords(l8, s3[2], 200, 200, 100)
# Условие при котором должно продолжаться движение наружу
if s[3] > 100:
t = root.after(100, move_out)
else: # Иначе начинаем движение внутрь
t = root.after(100, move_in)
def stop():
root.after_cancel(t)
b1 = Button(text='Запуск', command=move_in)
b1.pack()
b2 = Button(text='Стоп', command=stop)
b2.pack()
Еще добавил некоторые улучшения:
- Шаг 10, чтобы линии гарантированно доходили до чисел кратных 10, и не было "недожима" или "перехлеста"
- Сначала вычисляем новые координаты, потом делаем проверку, потом отрисовку, опять же, чтобы не было перехлеста
- Добавил запрет повторного (многократного) запуска движения
from tkinter import *
root = Tk()
root.title('main')
root.geometry('600x800')
c = Canvas(width=600, height=800, bg='white')
c.place(x=0, y=0)
n = 10
def init_lines():
global l1, l2, l3, l4, l5, l6, l7, l8
l1 = c.create_line(200, 100, 300, 100)
l2 = c.create_line(300, 100, 400, 100)
l3 = c.create_line(400, 100, 400, 200)
l4 = c.create_line(400, 200, 400, 300)
l5 = c.create_line(400, 300, 300, 300)
l6 = c.create_line(300, 300, 200, 300)
l7 = c.create_line(200, 300, 200, 200)
l8 = c.create_line(200, 200, 200, 100)
def delete_lines():
c.delete(l1)
c.delete(l2)
c.delete(l3)
c.delete(l4)
c.delete(l5)
c.delete(l6)
c.delete(l7)
c.delete(l8)
def move_in():
global t
s = c.coords(l1)
s1 = c.coords(l3)
s2 = c.coords(l5)
s3 = c.coords(l7)
s[3] = s[3] + n
s1[2] = s1[2] - n
s2[3] = s2[3] - n
s3[2] = s3[2] + n
# Условие при котором должно начинаться движение в противоположном направлении
if s[3] > 200:
move_out()
return
c.coords(l1, 200, 100, 300, s[3])
c.coords(l2, 300, s[3], 400, 100)
c.coords(l3, 400, 100, s1[2], 200)
c.coords(l4, s1[2], 200, 400, 300)
c.coords(l5, 400, 300, 300, s2[3])
c.coords(l6, 300, s2[3], 200, 300)
c.coords(l7, 200, 300, s3[2], 200)
c.coords(l8, s3[2], 200, 200, 100)
t = root.after(100, move_in)
def move_out():
global t
s = c.coords(l1)
s1 = c.coords(l3)
s2 = c.coords(l5)
s3 = c.coords(l7)
s[3] = s[3] - n
s1[2] = s1[2] + n
s2[3] = s2[3] + n
s3[2] = s3[2] - n
# Условие при котором должно начинаться движение в противоположном направлении
if s[3] < 100:
move_in()
return
c.coords(l1, 200, 100, 300, s[3])
c.coords(l2, 300, s[3], 400, 100)
c.coords(l3, 400, 100, s1[2], 200)
c.coords(l4, s1[2], 200, 400, 300)
c.coords(l5, 400, 300, 300, s2[3])
c.coords(l6, 300, s2[3], 200, 300)
c.coords(l7, 200, 300, s3[2], 200)
c.coords(l8, s3[2], 200, 200, 100)
t = root.after(100, move_out)
t = None
def start():
if t is None: # Не запускаем, если уже запущено
move_in()
def stop():
global t
root.after_cancel(t)
t = None
b1 = Button(text='Запуск', command=start)
b1.pack()
b2 = Button(text='Стоп', command=stop)
b2.pack()
init_lines()
# x=300,y=200 координаты центра.
root.mainloop()

