Какой диапазон у mainloop () над кодом? - PullRequest
0 голосов
/ 27 января 2019

Я хотел бы создать окно python tkinter с пользовательскими перемещаемыми виджетами на холсте для имитации движения.На данный момент у меня есть один холст и один неподвижный овальный виджет.У меня проблемы на базовом уровне;MainLoop ().Я понимаю, что он работает в ожидании, чтобы пользователь что-то сделал, но мне трудно увидеть:

  1. Как контролировать / увидеть, какой именно код mainloop () повторяет (гдеи только ткинтер?);

  2. Как правильно прервать его и вернуться к нему из другой функции, если она сама этого не делает;

  3. Какой код должен бытьповторил?Все объекты tkinter или только обновление меняющихся?Вместо этого использовать какую-нибудь операцию обновления?Наконец,

  4. В чем заключается функциональная разница между 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 Ответ

0 голосов
/ 27 января 2019

По сути, вызов 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 ()

Они имеют одинаковый эффект и поведение.Странно, но Tkinter решил сделать 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 для его кажущейся простоты, в действительности это обычно требует от вас гораздо больше работы, чем если бы вы использовали один из других менеджеров геометрии, и это приводит к GUI, который не особенно реагирует на изменения.

while True:

Вы почти никогда не должны делать это в tkinter. Tkinter - и почти все программы, основанные на событиях - полагаются на постоянный поток событий. Когда у вас есть бесконечный цикл, он не может обрабатывать эти события. Вы можете сделать явный вызов для обновления экрана в цикле, но это неэффективно и его следует избегать. Если вам нужно периодически что-то делать, создайте функцию, которая инкапсулирует тело вашего цикла, а затем используйте after, чтобы получить mainloop, чтобы запустить его во время обработки событий.

window.after(1000)

Вы почти никогда не должны использовать after без второго аргумента. Такое использование функционально ничем не отличается от вызова time.sleep(1) тем, что оно mainloop не позволяет обрабатывать события. Вы должны структурировать свой код так, чтобы mainloop.

обрабатывал постоянный поток событий.

while True: ... window.mainloop()

Вы определенно должны избегать вызова mainloop внутри цикла. Хорошо функционирующая программа tkinter должна вызывать mainloop() ровно один раз.

...