Incorporating HTML into wxPython-Part2

In the “Incorporating HTML into wxPython : Part 1” we covered – HTML with wxPython, HTML parser, tags and file formats, using widgets in HTML etc. In this part we will cover – adding support for new tags, methods of wx.Html.Tag, working with other file formats, HTML Widget and summary. Following is an excerpt from the book wxPython in Action.

16.3.2 How can I add support for new tags?

The cells returned by the parser are created internally by tag handlers, a pluggable structure by which HTML tags are associated with the creation and manipulation of the HTML parser cells. You can create your own tag handlers and associate them with HTML tags. With this mechanism you can extend the HTML window to include standard tags not currently supported, or custom tags of your own invention. Figure 16.4 displays the use of a custom HTML tag.

Listing 16.4 displays the code used to produce figure 16.4.

Listing 16.4 Defining and using a custom tag handler

import wx

import wx.html

page = “””<html><body>

This silly example shows how custom tags can be defined and used in a wx.HtmlWindow. We’ve defined a new tag, &lt;blue&gt; that will change the <blue>foreground color</blue> of the portions of the document that it encloses to some shade of blue. The tag handler can also use parameters specified in the tag, for example:

<ul>

<li> <blue shade=’sky’>Sky Blue</blue>

<li> <blue shade=’midnight’>Midnight Blue</blue>

<li> <blue shade=’dark’>Dark Blue</blue>

<li> <blue shade=’navy’>Navy Blue</blue>

</ul>

</body></html>

“””

class BlueTagHandler(wx.html.HtmlWinTagHandler):

def __init__(self):

wx.html.HtmlWinTagHandler.__init__(self)

def GetSupportedTags(self):

return “BLUE”

def HandleTag(self, tag):

old = self.GetParser().GetActualColor()

clr = “#0000FF”

if tag.HasParam(“SHADE”):

shade = tag.GetParam(“SHADE”)

if shade.upper() == “SKY”:

clr = “#3299CC”

if shade.upper() == “MIDNIGHT”:

clr = “#2F2F4F”

elif shade.upper() == “DARK”:

clr = “#00008B”

elif shade.upper == “NAVY”:

clr = “#23238E”

self.GetParser().SetActualColor(clr)

container = self.GetParser().GetContainer()

container.InsertCell(wx.html.HtmlColourCell(clr))

self.ParseInner(tag)

self.GetParser().SetActualColor(old)

container = self.GetParser().GetContainer()

container.InsertCell(wx.html.HtmlColourCell(old))

return True

wx.html.HtmlWinParser_AddTagHandler(BlueTagHandler)

class MyHtmlFrame(wx.Frame):

def __init__(self, parent, title):

wx.Frame.__init__(self, parent, -1, title)

html = wx.html.HtmlWindow(self)

if “gtk2” in wx.PlatformInfo:

html.SetStandardFonts()

html.SetPage(page)

app = wx.PySimpleApp()

frm = MyHtmlFrame(None, “Custom HTML Tag Handler”)

frm.Show()

app.MainLoop()

The tags themselves are represented internally as methods of the class wx.Html. Tag, which is created by the HTML parser. Typically, you won’t need to create your own instances. Table 16.4 displays the wx.Html.Tag class with methods that are useful to retrieve information about the tags.

Table 16.4 Some methods of wx.Html.Tag

Method

Description

GetAllParams()

Returns all the parameters associated with the tag as a string. For some purposes, it might be easier to parse this string rather than get each
parameter individually.

GetName()

Returns the tag name, in uppercase text.

HasParam(param)

Returns True if the tag has the given parameter.

GetParam(param,
with_commas=False)

Returns the value of the parameter param. If the with_commas parameter is True, you get a raw string including the quotation marks starting and ending the value, if any. Returns an empty string if the parameter doesn’t exist. The related method GetParamAsColour(param) returns the parameter value as a wx.Color, and the method GetParamAsInt(param) returns
the value as an int.

HasEnding()

Returns True if the tag has an ending tag, and false otherwise.

A tag handler used for extending the HTML window is a subclass of wx.html. HtmlWinTagHandler . Your subclass needs to override two methods, and needs to be aware of one further method. The first method to override is GetSupportedTags(). This method returns the list of tags that are managed by this handler. The tags must be in uppercase, and if there is more than one they are separated by a comma, with no spaces in between, as in the following example.

GetSupportedTags(self):

return “MYTAG,MYTAGPARAM”

The second method that you need to override is HandleTag(tag). Within the HandleTag method, you handle the tag by adding new cell elements to the parser (or alternately making changes to the container cell that the parser has open at that point). You get the parser by calling the GetParser() method of the tag handler.

To write a HandleTag() method, you should:

1 Get the parser.

2 Process the parameters to your tag as necessary, possibly making changes to or creating a new cell.

3 If the tag being parsed is a begin/end pair with inner text, parse the text in between.

4 Perform any cleanup needed to the parser.

As mentioned, you get the parser with GetParser(). To add or edit cells in the parser, you have three options. First, if you want to add another cell to the container, you can work with the current container. Next, you call the parser’s GetContainer() method, then create your wx.html.HTMLCell subclass instance by whatever means you want, and add it to the container by calling the container’s InsertCell(cell) method.

Occasionally, you’ll want to create a container that is subordinate or nested within the currently open container. One example might be a table cell that is nested within a table row. To do this, you need to call the parser method OpenContainer(). This method returns your new container cell, into which you can insert display cells with the InsertCell(cell) method. For every container you open in your tag handler, you are expected to close it using the CloseContainer() method. If you do not have a balance between your OpenContainer() and CloseContainer() calls, it will disrupt the parser behavior on the rest of the HTML text.
Another option is to create a container at the same level as the parser’s current container, meaning that you aren’t nesting containers. An example would be a new paragraph—it’s not part of the previous paragraph, nor is it subordinate to it; it’s a new entity in the page. In order to get that behavior in the parse, you need to close the existing container, open a new container, and reverse the process at the end of the method.

parser = self.GetParser()
parser.CloseContainer()
parser.OpenContainer()

# Do all your stuff

parser.CloseContainer()
parser.OpenContainer()

This has the effect of giving you a new container to put your information into, but ensuring that the parser has a clean container at the same nesting depth that existed at the beginning of the method.

16.3.3 How can I support other file formats?

By default, the HTML window can handle files with the MIME type text/html, text/txt, and image/* (assuming the wxPython image handlers are loaded). When confronted with a file that is not an image or HTML file, the HTML window attempts to display it as plain text. That may not be the behavior you want. If there is some file format that you want displayed in a custom way, you can create a wx.html.HtmlFilter to manage it. For example, you might want XML files to display as a source tree, or you could display Python source files with syntax coloring.

To create a filter, you must build a subclass of wx.html.HtmlFilter. This class has two methods, and you must override both of them. The first method is CanRead(file). The file parameter is an instance of wx.FSFile—the wxPython representation of an opened file. The wx.FSFile class has two properties that you would use to determine if your filter can read the file. The method GetMimeType() returns the file’s MIME type as a string. The mime type is usually determined by the file’s extension. The method GetLocation() returns a string with the absolute path or URL to the file location. The CanRead() method should return True if the filter will handle the file, otherwise it returns False. A sample CanRead() to handle Python source files may look like the following.

CanRead(self, file):
return file.GetLocation().endswith(‘.py’)

The second method you need to override is ReadFile(file). This method takes in the same file parameter, and returns a string HTML representation of the file’s contents. If you don’t want to use the wxWidgets C++ file mechanisms to read the file, you can use the Python file mechanisms by simply opening a Python file at file.GetLocation().

Once the filter has been created, it must be registered with the wx.html.HtmlWindow using the window’s AddFilter(filter) static method. The filter parameter is an instance of your new wx.html.HtmlFilter class. Once it has registered the filter, the window uses it to manage the file objects that pass the CanRead() test.

16.3.4 How can I get a more fully featured HTML Widget?

Although the wx.html.HtmlWindow is not a fully featured browser pane, there are a couple of options for embedding a more fully featured HTML rendering window. If you are on a Windows platform, you can use the class wx.lib.iewin.IEHtmlWindow , which is a wxPython wrapper around the Internet Explorer ActiveX control. This allows you to embed an Internet Explorer window directly into your application.

Using the Internet Explorer (IE) control is relatively straightforward and similar to using the internal wxPython HTML window. It has a widget-like constructor, as in the following.

wx.lib.iewin.IEHtmlWindow(self, parent, ID=-1,

pos=wx.DefaultPosition, size=wx.DefaultSize, style=0,

name=’IEHtmlWindow’)

Everything here is in keeping with wxPython widgets, the parent is the parent window, and the ID is the wxPython ID. There are no useful style flags for an IE window. To load HTML into the IE component, use the method LoadString (html), where the html parameter is an HTML string to display. You can load from an open file, or anything that is a Python file object, using the method LoadStream(stream), or from a URL using the method LoadString(URL). You can retrieve the text being displayed with the method GetText(asHTML). The asHTML parameter is a Boolean. If True, the text is returned in HTML, otherwise, it’s just returned as a text string.

On other platforms, you can try the wxMozilla project (http://wxmozilla. sourceforge.net), which attempts to create a wxPython wrapper around the Mozilla Gecko renderer. Currently, the project is still in beta. The wxPython extension for this project has an installer for Windows and Linux, with Mac OS X support in progress.

16.4 Summary

  • HTML is not just for the Internet anymore. In wxPython, you can use an HTML window to display text with a simple subset of HTML markup. The HTML window is of the class wx.html.HtmlWindow. In addition to HTML text, the HTML window can manage any image that has a currently loaded image handler.
  • You can give the HTML window its display information as a string, a local file, or a URL. You can respond to a user click either as a hypertext browser normally would, or with a custom response of your own. You can also connect the HTML window to its frame so that the title and status information automatically displays in the correct locations. The HTML window maintains a history list that you can access and manipulate. You can use the class wx.Html.HtmlEasyPrinting to print your page straightforward.
  • There is an HTML parser in wxPython that you can use to create your own custom tags for your window. You can also set up custom file filters to render other file formats to an HTML window.
  • Finally, if you get frustrated with the limitations of the HTML window, a wrapper around the Internet Explorer ActiveX control is available. If you aren’t on Windows, there’s a beta version of a wrapper around the Mozilla Gecko HTML renderer.

Related :
>> Incorporating HTML into wxPython : Part 1
>> wxPython is a good answer for almost any kind of desktop application.

Content Team

The IndicThreads Content Team posts news about the latest and greatest in software development as well as content from IndicThreads' conferences and events. Track us social media @IndicThreads. Stay tuned!

Leave a Reply