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

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

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

Я расскажу о часто задаваемых вопросах 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 ()]) до тех пор, пока ваш heavy_work не будет выполнен.

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

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

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

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

В 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, который абстрагирует боль и позволяет сосредоточиться на важных аспектах.

(Я не повторил все в этом блоге через лень, следовательно, сообщество wiki).

Один из вариантов, если вы не состоите в браке с pycurl, – использовать наблюдателей IO GObject.

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

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