Индикатор выполнения не обновляется во время работы

StackOverflow https://stackoverflow.com/questions/496814

Вопрос

в моей программе python для загрузки файла в Интернет я использую индикатор выполнения GTK, чтобы показать ход загрузки.Но проблемы, с которыми я сталкиваюсь, заключаются в том, что индикатор выполнения не показывает никакой активности до завершения загрузки, а затем он внезапно указывает на завершение загрузки.я использую pycurl для создания http requests...my вопрос в том - нужно ли мне иметь многопоточное приложение для загрузки файла и одновременного обновления графического интерфейса?или есть какая-то другая ошибка, которую я совершаю?

Заранее спасибо!

Это было полезно?

Решение

Я собираюсь процитировать Часто ЗАДАВАЕМЫЕ ВОПРОСЫ PyGTK:

Вы создали индикатор выполнения внутри окна, затем запускаете цикл, который выполняет некоторую работу:

while work_left:
    ...do something...
    progressbar.set_fraction(...)

Вы заметите, что окно даже не отображается, а если и появляется, индикатор выполнения остается замороженным до окончания выполнения задачи.Объяснение этому простое:gtk управляется событиями, и вы крадете управление у основного цикла gtk, тем самым не позволяя ему обрабатывать обычные события обновления графического интерфейса пользователя.

Самое простое решение состоит в том, чтобы временно возвращать управление gtk каждый раз, когда изменяется ход выполнения:

while work_left:
    ...do something...
    progressbar.set_fraction(...)
    while gtk.events_pending():
        gtk.main_iteration()

Обратите внимание, что с этим решением пользователь не может выйти из приложения (gtk.main_quit не будет работать из-за нового цикла [gtk.main_iteration()]), пока ваша тяжелая работа не будет выполнена.

Другое решение состоит в использовании функций gtk idle, которые вызываются основным циклом gtk всякий раз, когда ему нечего делать.Таким образом, gtk находится под контролем, и функция idle должна выполнить небольшую работу.Он должен возвращать True, если предстоит проделать еще большую работу, в противном случае False.

На лучшее решение (у него нет недостатков) указал Джеймс Хенстридж.Он использует генераторы python в качестве неработающих функций, чтобы заставить python автоматически сохранять состояние для нас.Это происходит примерно так:

def my_task(data):
    ...some work...
    while heavy_work_needed:
        ...do heavy work here...
        progress_label.set_text(data) # here we update parts of UI
        # there's more work, return True
        yield True
    # no more work, return False
    yield False

def on_start_my_task_button_click(data):
    task = my_task(data)
    gobject.idle_add(task.next)

Приведенное выше 'while' - это всего лишь пример.Единственные правила заключаются в том, что оно должно выдавать значение True после выполнения небольшой работы, а впереди еще больше работы, и оно должно выдавать значение False, когда задача выполнена.

Другие советы

Более чем вероятно, проблема заключается в том, что в вашем обратном вызове progress, где, я полагаю, вы обновляете индикатор выполнения, вы не выполняете вызов для ручного обновления отображения, т. е.запустите цикл событий графического интерфейса пользователя.Это всего лишь предположение, хотя, если вы можете предоставить больше кода, возможно, будет проще сузить его еще больше.

Причина, по которой вам необходимо вручную обновить отображение, заключается в том, что ваш основной поток также выполняет загрузку, и именно здесь он блокируется.

В python 2.x целочисленные операнды приводят к целочисленному делению.Попробуй это:

#Callback function invoked when download/upload has progress
def progress(download_t, download_d, upload_t, upload_d):
    print 'in fileupload progress'
    mainwin.mainw.prog_bar.set_fraction(float(upload_d) / upload_t)

Да, вам, вероятно, нужен параллелизм, и да, потоки - это один из подходов, но если вы используете потоки, пожалуйста, используйте метод, подобный этому: http://unpythonic.blogspot.com/2007/08/using-threads-in-pygtk.html это отвлечет вас от боли и позволит вам сосредоточиться на важных аспектах.

(Я не повторил все в этом посте в блоге из-за лени, отсюда и вики сообщества).

Один из вариантов, если вы не женаты на pycurl, - это использовать средства просмотра ввода-вывода GObject .

http://pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--io-add-watch

Используя это, вы можете чередовать загрузку файла с обычным циклом событий PyGTK и даже выполнять вызов set_progress в обратном вызове просмотра ввода-вывода.Если вы выгружаете всю работу для загрузки в pycurl, это на самом деле неосуществимо, но если вы просто загружаете файл по HTTP, io_add_watch также сделает использование сокета для этого намного менее болезненным.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top