1

I am writing a chatroom client in wxPython in which there are 3 wx.HtmlWindows for each chatroom on a notebook page: one for the messages, one for the title of the room, and one for the topic of the room (two similar things)

The program works fine, loads images when images are in the message's code, etc. But when it suddenly has to load a bunch of images at once, or an animated image that takes longer to load, or a combination (the images are generally just 50x50 - 100x100) it can be a problem because sometimes it will lock up and then the program won't respond because it's taking too long. The question posing is, how would I stop the locking up from happening? I don't know how to go about binding wx.HtmlWindow's image loading to have the images load dynamically in a worker thread instead of the program having to wait for the images to load to continue.

If you need a sample code of what I am writing let me know.

EDIT: I'm stil having trouble figuring out an answer for this.. I have gotten literally no where on this project because of this. my application needs to be able to dynamically load messages/images without it locking up and I simply do not know how to force any image loading into a different thread so that the frames of the images and the messages are displayed, while the loader thread loads the images and updates the empty frames when done. This all needs to happen in an HtmlWindow. I want it to act like a real web browser when it comes to loading images (you see the frames and the images slowly appear)

Blazer
  • 337
  • 2
  • 11

4 Answers4

0

You might want to try out the new functionality in the latest wxPython development release?

You first need to make sure you have downloaded and installed last version. You can find it here, under "Development release": http://www.wxpython.org/download.php

This is a simple example that works with the latest wxPython(v2.9) development release:

import wx 
import wx.html2 

class MyBrowser(wx.Dialog): 
  def __init__(self, *args, **kwds): 
    wx.Dialog.__init__(self, *args, **kwds) 
    sizer = wx.BoxSizer(wx.VERTICAL) 
    self.browser = wx.html2.WebView.New(self) 
    sizer.Add(self.browser, 1, wx.EXPAND, 10) 
    self.SetSizer(sizer) 
    self.SetSize((700, 700)) 

if __name__ == '__main__': 
  app = wx.App() 
  dialog = MyBrowser(None, -1) 
  dialog.browser.LoadURL("http://www.google.com") 
  dialog.Show() 
  app.MainLoop()

I hope this solves your problem, let me know.

patchie
  • 615
  • 1
  • 9
  • 21
0

Steven Sproat was on the right track (kudos for putting me on it - couldn't have done it without your suggestion) - here is are the relevant bits of a complete solution:

import wx.html as html
import urllib2 as urllib2
import os
import tempfile
import threading
from Queue import Queue

class HTTPThread(threading.Thread):
     def __init__(self, urlQueue, responseQueue):
        threading.Thread.__init__(self)
        self.urlQueue = urlQueue
        self.responseQueue = responseQueue

    def run(self):
        # add error handling
        url = self.urlQueue.get()
        request = urllib2.Request(url)
        response = urllib2.urlopen(request)
        page = response.read()
        self.responseQueue.put(page)

And in your derivative class of html.HtmlWindow:

def OnOpeningURL(self, type, url):
    if type == html.HTML_URL_IMAGE:
        # If it is a tempfile already, just tell it to open it.
        # Since it will be called again
        # immediately after first failure only need to keep the last
        # temp file within the object, and the former is closed!
        if self.f is not None and self.f.name in url:
            return html.HTML_OPEN
        # if its not a tempfile, download asynchronously and redirect
        urlq = Queue()
        resq = Queue() 
        t = HTTPThread(urlq, resq)
        t.start()
        urlq.put_nowait(url)
        while True:
            if resq.empty():
                # your task while waiting
                time.sleep(0.1)
            else:
                img = resq.get()
                break
        self.f = tempfile.NamedTemporaryFile()
        self.f.write(img)
        self.f.seek(0)
        return 'file://' + self.f.name
    else:
        return html.HTML_OPEN

For my application this works great, but if you truly want to have the images load "like a regular web browser" then you are going to need more than an wx.html.HtmlWindow. However, this is non-blocking and will correctly load the images.

bbbruce
  • 411
  • 2
  • 5
0

Long running processes will block the main loop of your application, which causes it to "lock up". You'll want to do the downloading in a separate thread and then update your UI when that's finished. Here are a couple links on using threads (and other methods) that might help you:

http://wiki.wxpython.org/LongRunningTasks

http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/

Mike Driscoll
  • 32,629
  • 8
  • 45
  • 88
  • that doesn't really help with his issue though as he's not sure where to bind for the images being loaded. – Steven Sproat Sep 29 '10 at 15:07
  • I already know how to use threads I just wasn't sure how to get the window to do the image loading in a different thread instead. Thanks though – Blazer Sep 29 '10 at 23:37
  • I was thinking that you could download the images with the thread and then use PubSub or PostEvent to tell your application to display it. – Mike Driscoll Sep 30 '10 at 14:03
0

In addition to Mike's answer (what he says applies), you can hook into an image being loaded by overriding the OnOpeningURL method from HTMLWindow and specifying the type of wx.html.HTML_URL_IMAGE.

See: these wx docs for an explanation.

Steven Sproat
  • 4,398
  • 4
  • 27
  • 40
  • Thanks! Do you happen to know how to make the wxHtmlWindow add a blank frame in place of images while it loads the page and then update the page when it's done loading? This way the messages wouldn't get mixed up from the time they are actually received (a message without an image that was actually received after a message with an image might appear first, messing up the order, for example) – Blazer Sep 29 '10 at 23:42
  • Hmm, I'm not sure, sorry. I haven't used wx.HtmlWindow – Steven Sproat Sep 30 '10 at 12:22