Какой диапазон у mainloop() над кодом?
Я хотел бы сделать окно Python Tkinter с настраиваемыми виджетами на холсте для имитации движения. На данный момент у меня есть один холст и один неподвижный овальный виджет. У меня проблемы на базовом уровне; MainLoop(). Я понимаю, что он работает в ожидании, чтобы пользователь что-то сделал, но мне трудно увидеть:
Как контролировать / видеть, какой именно код mainloop() повторяет (где и только tkinter?);
Как правильно прервать его и вернуться к нему из другой функции, если он сам этого не делает;
Какой код следует повторить? Все объекты tkinter или только обновление меняющихся? Вместо этого использовать какую-нибудь операцию обновления? В заключение;
В чем разница между функциональностью tkinter.mainloop() и window.mainloop()? Возможно, на предыдущие вопросы ответим.
У меня небольшой опыт работы со Swift, и я начал изучать очень похожий язык Python вчера вечером. Я пробовал, вероятно, сотни мутаций в моем коде, который в настоящее время находится на стадии тестирования. Я переместил все в область видимости основного цикла и даже получил несколько сотен крошечных окон Python по всему экрану. Все делает одно из двух: ничего не делает или выдает ошибку. Так как я не знаю, что вообще работает или работает, я не могу ничего диагностировать. Моя цель - просто несколько раз переместить круг на сто пикселей. Я искал источники, но, может быть, это я, ясного мало. У меня есть мой код здесь все размечено. Эта страница ближе всего к тому, что я ищу: переместите мяч в Tkinter Canvas Widget (простая игра арканоид). Кажется, все находится под mainloop. Итак, все перерисовывается каждый проход? Здесь, к сожалению, весь мой сценарий; Я не могу только показать кусочки. По какой-то причине он вызывает только небольшое окно, а не полноэкранное. (Изменить: кажется, я потерял код размера экрана)
import tkinter
import time
# Initial values for circle's corners and start idicator ('b'):
x1 = 10
y1 = 10
x2 = 210
y2 = 210
b = 0
# Window ('window')
window = tkinter.Tk()
# Canvas ('area')
area = tkinter.Canvas(window, width=1368, height=650)
area.place(x=0, y=0)
# Ovals to be placed on 'area'
oval1 = area.create_oval(x1,y1,x2,y2,fill='#42befe')
oval2 = area.create_oval(100,10,300,210,fill='#d00000')
# Turns b to 1 to start shifting when 'butt' is pressed:
def startFunc():
b = 1
print('b = 1')
# My button to activate 'startFunc'
butt = tkinter.Button(window, text='Start movement', command=startFunc)
butt.pack()
# Adjusts the x and y coordinates when they are fed in:
def Shift(A, B, C, D):
print('Shift activated.')
window.after(1000)
print('Edit and return:')
A += 100
B += 100
C += 100
D += 100
return(A, B, C, D)
# Problems start about here: my Mainloop section;
# I have little idea how this is supposed to be.
while True:
if b == 1:
# Takes adjusted tuple
n = Shift(x1, y1, x2, y2)
print('Returned edited tuple.')
# Changes coordinates
x1 = n[0]
y1 = n[1]
x2 = n[2]
y2 = n[3]
print(f'{x1}, {y1}, {x2}, and {y2}')
# Reiterate moving oval
oval1 = area.create_oval(x1,y1,x2,y2,fill='#42befe')
#Does this re-run 'window' relations outside here, or only within the 'while'?
window.mainloop()
Он должен показывать окно 1368 на 650, а не маленькое. Кнопка только печатает, что означает, что последнее 'while' не запущено, несмотря на основной цикл. Он хочет, чтобы он зацикливался внутри линии while, которая должна корректировать координаты и перемещать мой синий круг. Итерация не может касаться начальных значений, иначе она сбрасывает их.
1 ответ
По сути, вызов mainloop такой же, как если бы вы добавили это в свой код вместо вызова mainloop()
:
while the_program_is_running():
event = wait_for_event()
process_the_event(event)
Как правило большого пальца, mainloop()
должен вызываться ровно один раз после инициализации интерфейса, и вы готовы к тому, чтобы пользователь начал взаимодействовать с вашей программой. Когда он выходит, у вас обычно не будет кода после него, и ваша программа завершит работу.
Как контролировать / видеть, какой именно код mainloop() повторяет (где и только tkinter?);
Я не знаю, что вы подразумеваете под "повторением". Он не запускает никакого кода, кроме своего внутреннего кода. Он просто ждет событий, а затем отправляет их обработчикам.
Как правильно прервать его и вернуться к нему из другой функции, если он сам этого не делает;
Это чрезвычайно редко сделать это в работающей программе. Как правило, звонит mainloop
это последнее, что ваша программа делает перед тем, как пользователь начинает с ней взаимодействовать, и как только она выходит из программы, она закрывается.
Однако, чтобы ответить на конкретный ответ, как прервать его, вы можете позвонить quit
метод корневого окна. Это вызовет самый последний звонок mainloop()
возвращать.
Какой код следует повторить? Все объекты tkinter или только обновление меняющихся? Вместо этого использовать какую-нибудь операцию обновления?
На этот вопрос сложно ответить, потому что он не имеет особого смысла. Когда вы звоните mainloop()
, он будет следить за всеми событиями на всех объектах tkinter.
В чем отличие функциональности между tkinter.mainloop() и window.mainloop()
Они имеют точно такой же эффект и поведение. Ткинтер как ни странно решил сделать mainloop
доступны из любого виджета. Наиболее распространенный способ вызвать его - либо из самого модуля tkinter, либо из корневого окна.
Моя цель - просто несколько раз переместить круг на сто пикселей.
Обычный способ сделать это - создать функцию, которая перемещает его на сто пикселей. Затем эта функция (или вызывающая ее функция) может поставить себя в очередь событий для запуска в будущем.
Например, следующий код будет перемещать объект canvas на 100 пикселей каждую секунду до выхода из программы:
def move_object():
the_canvas.move(item_id, 100, 0)
the_canvas.after(1000, move_object)
Когда он вызывается, он переместит элемент на 100 пикселей вправо. Затем он поместит новый вызов в очередь событий, которая будет обработана и обработана примерно за 1000 миллисекунд.
Есть много рабочих примеров использования after
на этом сайте, включая вопрос, который вы указали в своем вопросе.
Кажется, все находится под mainloop. Итак, все перерисовывается каждый проход?
Нет не совсем Единственные объекты, которые перерисовываются, это вещи, которые нужно перерисовать. Перемещение объектов на холсте, изменение размера окна, перетаскивание другого окна поверх окна и т. Д. - все это помещает событие в очередь событий, которое сообщает tkinter "этот объект необходимо перерисовать". Обработка этого события происходит автоматически mainloop
, Если в вашем приложении ничего не происходит, mainloop ничего не перерисовывает.
Он должен показывать окно 1368 на 650, а не маленькое
Это потому, что вы не указали размер главного окна. Вы дали холсту размер, но вы используете place
который не заставит содержащее окно расти или уменьшаться, чтобы соответствовать. Как новичок, вы должны полностью избегать place
и вместо этого использовать pack
или же grid
, так как pack
а также grid
оба автоматически изменят размер вашего окна, чтобы вместить все внутри.
Хотя заманчиво использовать place
из-за его кажущейся простоты в действительности обычно требуется, чтобы вы выполняли гораздо больше работы, чем если бы вы использовали один из других менеджеров геометрии, и это приводит к графическому интерфейсу, который не особенно реагирует на изменения.
while True:
Вы почти никогда не должны делать это в tkinter. Tkinter - и почти все программы, основанные на событиях - полагаются на постоянный поток событий. Когда у вас есть бесконечный цикл, он не может обрабатывать эти события. Вы можете сделать явный вызов для обновления экрана в цикле, но это неэффективно и его следует избегать. Если вам нужно периодически что-то делать, создайте функцию, которая инкапсулирует тело вашего цикла, а затем используйте after
получить mainloop
запустить его, пока он обрабатывает события.
window.after(1000)
Вы почти никогда не должны использовать after
таким образом, без второго аргумента. Это использование функционально ничем не отличается от вызова time.sleep(1)
в том, что это мешает mainloop
от обработки событий. Вы должны структурировать свой код, чтобы обеспечить непрерывный поток событий для обработки mainloop
,
while True: ... window.mainloop()
Вам определенно нужно избегать звонков mainloop
внутри петли. Хорошая программа tkinter должна вызывать mainloop()
ровно один раз