Неопределенный ttk Progressbar не обновляется, если не принудительно

У меня есть графический интерфейс tkinter, который позволяет пользователям выполнять поиск в базе данных sqlite. База данных не статична, поэтому неизвестно, сколько времени займет каждый поиск. Приложение является однопоточным (и я бы хотел, чтобы оно оставалось таким). Поэтому я хотел бы, чтобы индикатор выполнения (или что-то анимированное) убедил пользователя, что что-то происходит во время поиска. На первый взгляд ttk.ProgressBar выглядел так, как будто он может добиться цели в режиме indeterminate, но, похоже, он не работает так, как описано в TkDocs.

Для неопределенного прогресса TkDocs сообщает...

... в начале операции вы просто вызовете метод "start" индикатора выполнения, а в конце операции вы вызовете его метод "stop". Индикатор выполнения позаботится обо всем остальном.

... но, похоже, это не так. Если я просто использую .start() перед выполнением моего запроса sqlite и .stop() после его завершения, индикатор выполнения присутствует, но не анимируется вообще.

Я могу заставить его обновиться, если выполню оператор sqlite select в цикле for и включу prog.step() и prog.update_idletasks(). Но это влияет на производительность и действительно работает, только если возвращается несколько строк, поскольку цикл for row in select_statement:.

Итак, как я могу получить неопределенный индикатор выполнения (или анимацию) для анимации в одном потоке, не заставляя его использовать step и update_idletask?


Код. Это не работает...

prog = ttk.ProgressBar(root,mode='indeterminate')
...
prog.start()
result = None
try:
    conn = sqlite3.connect(database)
    result = conn.execute('select * from table where a=? and b=?',(var1,var2))
    result = result.fetchall()
    conn.close()
except:
    handle the exception
prog.stop()

Работает, но хакерский.

prog = ttk.ProgressBar(root,mode='indeterminate')
...
prog.start()
result = None
try:
    for row in conn.execute('select * from table where a=? and b=?',(var1,var2)):
        result.append(row)
        prog.step()
        prog.update_idletasks()
    conn.close()
except:
    handle the exception
prog.stop()

person I_do_python    schedule 22.01.2015    source источник
comment
В вашей программе есть .mainloop()?   -  person PM 2Ring    schedule 22.01.2015
comment
Да. Все это происходит в окне toplevel, которое пользователь открывает из окна root, mainloop которого уже инициализировано.   -  person I_do_python    schedule 22.01.2015
comment
хотя вы заявили, что предпочитаете, чтобы он был однопоточным, я бы сказал, что для плавного реагирования графического интерфейса вам лучше всего сделать свой запрос во втором потоке, чтобы вы могли запустить индикатор выполнения и позволить основному поток возвращается в основной цикл.   -  person James Kent    schedule 22.01.2015
comment
Я согласен с Джеймсом. Пожалуйста, прочитайте этот ответ и дайте мне знать, если вы не полностью осведомлены. ;-]   -  person Honest Abe    schedule 24.01.2015


Ответы (1)


Так что, взяв второй рабочий блок кода и рефакторинг обновления индикатора выполнения, вы все уберете.

prog = ttk.ProgressBar(root,mode='indeterminate')
...
prog.start()

def progress():
    prog.step()
    prog.update_idletasks()

with sqlite3.connect(database) as conn:
     conn.set_progress_handler(handler=progress, n=1)
     database_query = conn.execute('select * from table where a=? and b=?',(var1,var2))
     result = database_query.fetchall()
person Echocage    schedule 22.01.2015
comment
Но имеет ли это ту же проблему, что и во втором примере, в том, что progress будет вызываться только тогда, когда строка будет найдена и добавлена ​​в список? Что произойдет, если будет просканировано миллион строк, а будет возвращена только одна строка? Будет ли индикатор выполнения увеличиваться один раз? - person I_do_python; 22.01.2015
comment
Ах, я вижу, что вы ищете. Похоже, set_progress_handler — это то, что вы ищете. sqlite.org/c3ref/progress_handler.html Я обновил свой ответ, чтобы он соответствовал вашим требованиям. . - person Echocage; 22.01.2015
comment
Это выглядит очень многообещающе, но на данный момент мне не удалось заставить его работать, так как метод ожидает входных данных, отличных от функции progress, и я немного озадачен тем, какими должны быть эти значения. Я поиграю. - person I_do_python; 23.01.2015
comment
Да, это действительно странно, как трудно найти документацию, извините, что не связал ее! Вот ссылка, параметры - это функция-обработчик , затем количество итераций между каждым вызовом функции. Я обновил код с правильным соглашением - person Echocage; 25.01.2015