为什么在 Python 中发出 HTTP 请求时无法查看标签的更新
题
我有这个代码:
def on_btn_login_clicked(self, widget):
email = self.log_email.get_text()
passw = self.log_pass.get_text()
self.lbl_status.set_text("Connecting ...")
params = urllib.urlencode({'@log_email': email, '@log_pass': passw, '@action': 'login', '@module': 'user'})
headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"}
conn = httplib.HTTPConnection("website.com")
self.lbl_status.set_text("Logging in ...")
conn.request("POST", "/ajax.php", params, headers)
response = conn.getresponse()
print response.status
self.lbl_status.set_text("")
data = response.read()
print data
conn.close()
这 self.lbl_status
在请求完成之前不会改变,因此由于最后的原因它不会显示任何内容 set_text
功能。
为什么会发生这种情况,以及如何避免/解决这种情况?
解决方案
下面是一个简单下载器的工作示例,仅供说明之用。如果您希望 GUI 能够响应并且在执行某些长时间运行或阻塞操作时不会冻结,则需要使用多线程。我把这个例子放在一起是基于 这个堆栈溢出问题 和这篇优秀的文章 在 PyGTK 中使用线程. 。Ubuntu iso 的默认 URL 需要一段时间才能下载,并且应该提供一个很好的演示。您可以输入任何您想要的网址,系统会在提示时下载文件并将其保存在当前目录中。
from threading import Thread
import time
import gtk, gobject, urllib
URL = 'http://releases.ubuntu.com//precise/ubuntu-12.04.1-desktop-i386.iso'
def download(url):
filename = url.split('/')[-1]
out = open(filename, 'wb')
gobject.idle_add(label.set_text, "connecting...")
f = urllib.urlopen(url)
buffer = f.read(1024)
counter = 0
while buffer:
counter += len(buffer)
out.write(buffer)
msg = "downloaded {0:,} bytes".format(counter)
gobject.idle_add(label.set_text, msg)
buffer = f.read(1024)
out.close()
gobject.idle_add(label.set_text, "download complete")
def clicked(button):
url = entry.get_text()
Thread(target=download, args=(url,)).start()
gtk.gdk.threads_init()
win = gtk.Window()
win.set_default_size(400, 100)
entry = gtk.Entry()
entry.set_text(URL)
label = gtk.Label("Press the button")
button = gtk.Button(label="Download")
button.connect('clicked', clicked)
box = gtk.VBox()
box.pack_start(entry)
box.pack_start(label)
box.pack_start(button)
win.add(box)
win.show_all()
gtk.main()
其他提示
在主循环运行之前,Gtk 不会更新任何内容。这意味着它首先执行所有更改,并在全部完成后才进行更新。这是因为它希望所有回调都是原子的(在可忽略的时间内完成)。回调永远不应该使用阻塞调用,因为这意味着界面将冻结。
这里有两种可能的解决方案。最好的方法是在响应准备好时注册一个新的回调,然后返回到主循环。然而,这可能并不容易。一个肮脏的解决方法是在进行阻塞调用之前强制主循环处理挂起的事件。然后它将更新标签。你可以这样做
while gtk.events_pending ():
gtk.main_iteration (False)
但正如我所写,不从回调中调用任何阻塞函数要干净得多。
不隶属于 StackOverflow