K_DOT
@K_DOT
DevOps инженер

Python Tkinter. Почему зависает графический интерфейс?

Здравствуйте! Помогите решить проблему, пожалуйста.
Написал такой код:
# -*- coding: utf-8 -*-
from Tkinter import *
import urllib,  ttk, tkMessageBox
from threading import Thread
def downloader():
    urllib.urlretrieve('http://cs521111v4.vk.me/u176613573/audios/d622212d34bf.mp3','Big K.R.I.T. – Bigger Picture.mp3')  
th=Thread(target=downloader,args=())
def starter(event):
    th.start()
    pb.pack()
    pb.start()   
root= Tk()
pb = ttk.Progressbar(length = 200, orient = 'horizontal', mode = 'indeterminate')
but = Button(root, text = 'Go!')
root.minsize(width = 400, height = 350)
but.bind('<Button-1>', starter)
but.pack()
root.mainloop()

И мне нужно, чтобы после загрузки файла с помощью urllib.urlretrieve появлялось диалоговое окно.
Пробовал так:
def downloader():
    urllib.urlretrieve('http://cs521111v4.vk.me/u176613573/audios/d622212d34bf.mp3','Big.mp3')
    tkMessageBox.showinfo('Done')

Но после скачивания файла графический интерфейс зависает. Что я делаю не так?
  • Вопрос задан
  • 6159 просмотров
Решения вопроса 1
mysticmirage
@mysticmirage
# -*- coding: utf-8 -*-

from Tkinter import *
import urllib, ttk, tkMessageBox
from threading import Thread
from Queue import Queue

queue = Queue()  # создаём очередь

def downloader():
    urllib.urlretrieve('http://cs521111v4.vk.me/u176613573/audios/d622212d34bf.mp3', 'Big K.R.I.T. – Bigger Picture.mp3')
    queue.put(True)  # помещаем в очередь True, после завершения загрузки. В очередь можно помещать любой объект.

th = Thread(target=downloader, args=())

def starter(event):
    th.start()
    pb.pack()
    pb.start()

root = Tk()

# создаём задачу, которая раз в секунду будет проверять очередь
def task():
    try:
        q = queue.get_nowait()  # получить значение из очереди
    except:  # если в очереди ничего нет, то возвращаем False
        q = False
    if q:  # если вернулось True, то сообщаем об окончании
        tkMessageBox.showinfo('Done')
    root.after(1000, task)  # снова перезапускаем задачу после выполнения

root.after(1000, task)  # инициализация задачи

pb = ttk.Progressbar(length=200, orient='horizontal', mode='indeterminate')
but = Button(root, text = 'Go!')
root.minsize(width=400, height=350)
but.bind('<Button-1>', starter)
but.pack()
root.mainloop()
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
mysticmirage
@mysticmirage
Нельзя вызывать методы Tkinter из других потоков, кроме как из главного (там где root = Tk()).
Тут два варианта:
1. Попробовать использовать mtTkinter.
2. Передавать информацию о завершении загрузки из дочернего потока в главный при помощи Queue.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы