PyGTK、线程与WebKit

2 投票
2 回答
2653 浏览
提问于 2025-04-17 08:59

在我的PyGTK应用程序中,当我点击按钮时,我需要:

  1. 获取一些HTML内容(这可能需要一些时间)
  2. 在新窗口中显示这些内容

在获取HTML内容的过程中,我希望保持界面可以响应用户操作,所以我决定在一个单独的线程中进行这个操作。我使用WebKit来渲染HTML。

问题是,当WebView在单独的线程中时,我得到的是一个空白页面。

这个方法是有效的:

import gtk
import webkit

webView = webkit.WebView()
webView.load_html_string('<h1>Hello Mars</h1>', 'file:///')
window = gtk.Window()
window.add(webView)
window.show_all()
gtk.mainloop()

但是这个方法不行,会产生一个空窗口:

import gtk
import webkit
import threading

def show_html():
    webView = webkit.WebView()
    webView.load_html_string('<h1>Hello Mars</h1>', 'file:///')
    window = gtk.Window()
    window.add(webView)
    window.show_all()

thread = threading.Thread(target=show_html)
thread.setDaemon(True)
thread.start()
gtk.mainloop()

这是不是因为WebKit不是线程安全的?有没有什么解决办法呢?

2 个回答

0

我对webkit的内部工作原理不太了解,不过你可以试试用多个进程来解决这个问题。

3

根据我的经验,有时候在使用gtk时,更新小部件(也就是界面上的元素)在不同的线程中并不会像你预期的那样工作。

为了解决这个问题,你可以在线程中处理数据,然后使用 glib.idle_add 来安排在主线程中更新小部件,这样一旦数据处理完成,就可以更新界面了。

下面的代码是你例子的一个更新版本,对我来说是有效的(time.sleep 用来模拟在真实场景中获取html时的延迟):

import gtk, glib
import webkit
import threading
import time

# Use threads                                       
gtk.gdk.threads_init()

class App(object):
    def __init__(self):
        window = gtk.Window()
        webView = webkit.WebView()
        window.add(webView)
        window.show_all()

        self.window = window
        self.webView = webView

    def run(self):
        gtk.main()

    def show_html(self):
        # Get your html string                     
        time.sleep(3)
        html_str = '<h1>Hello Mars</h1>'

        # Update widget in main thread             
        glib.idle_add(self.webView.load_html_string,
                      html_str, 'file:///')

app = App()

thread = threading.Thread(target=app.show_html)
thread.start()

app.run()
gtk.main()

撰写回答