【问题标题】:freezing gui while socket在套接字时冻结 gui
【发布时间】:2017-07-24 03:48:48
【问题描述】:
我正在构建一个小型 gui 应用程序,允许用户
从服务器下载文件。它主要用于套接字和 tkinter。
但是当我下载一个文件(例如一部电影)时,它需要一些时间,例如 5 分钟。在那个时候,我想要一个进度条,它将开始循环直到文件完全下载。但是当客户端使用sock.recv逐行获取文件数据时,
所有的 gui 程序都冻结了!
所以因为进度条不能移动,
我不能按任何按钮。
所以我的问题是 - 我该如何解决?意味着gui应用程序在从服务器获取数据时不会被堆栈,然后我可以让进度条工作。
非常感谢你们。
【问题讨论】:
标签:
python
sockets
user-interface
【解决方案1】:
在这里,我尝试描述(主要是伪代码)如何实现带有进度条的非阻塞下载功能。
希望对你有帮助。
def update_progress(percentage):
# update your progress bar in GUI
def download(callback):
# implement your download function
# check the full size of the file to be downloaded.
# try to download a reasonable amount at once
# call callback with percentage that you have downloaded to update GUI
total = 1000000 # get total size of the file to be downloaded.
current = 0
block_size = 1000 # i.e., 1 KB
while True:
# do required operations to download data of block_size amount
# example: sock.recv(block_size)
current += block_size
# calculate downloaded percentage
percentage = (block_size * 100) / total # you may add precision if you prefer
# call the callback function to update GUI based on the downloaded percentage
callback(percentage)
# check if download completed
if current >= total:
break
def start_download(): # bind this function to your button's click on GUI.
# import threading
# create a thread to execute download
# see how 'update_progress' is passed as an argument
thread = threading.Thread(target=download, args=[update_progress])
thread.start()
# execution will not be blocked here as the thread runs in the background.
# so, any code here will run without waiting for download to be completed.
【解决方案2】:
感谢你们的帮助,特别是对你们ohannes,我在后台使用
线程类,这是代码:(您需要将 'root' 更改为 tkinter 窗口的名称)
class ThreadedClient(threading.Thread):
def __init__(self, queue, fcn):
threading.Thread.__init__(self)
self.queue = queue
self.fcn = fcn
def run(self):
time.sleep(1)
self.queue.put(self.fcn())
def spawnthread(fcn):
thread = ThreadedClient(queue, fcn)
thread.start()
periodiccall(thread)
def periodiccall(thread):
if(thread.is_alive()):
root.After(100, lambda: periodiccall(thread))
#END