28 Aug 2012

Python Tkinter显示HTML

Python内置了Tkinter来实现GUI编程,无需使用第三方库如pyWxWidget,pyQt等,虽说控件基本够用,但是没有html显示控件.这里有一个Tkhtml widget,纯C编写,python可用.使用方法:
1. 去这里下载dll
2. 在Python_DIR\tcl下建立Tkhtml文件夹
3. 将tkhtml.dll复制进2建立的文件夹
4. 建立pkgIndex.tcl文件,内容如下:
package ifneeded Tkhtml 0.0 [list load [file join $dir tkhtml.dll]]
5. 测试Tkhtml是否安装好
>>> import Tkinter #tkinter
>>> root = Tkinter.Tk()
>>> root.tk.eval('package require Tkhtml')
'0.0'
note: python使用tkhtml的例子
# -*-mode: tcl; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
#
#	$Id$
#

# http://tix.sourceforge.net/Tixapps/src/Python/TkHtml.py

"""TkHtml

Wrapper for the TkHtml widget from http://www.hwaci.com.
"""

import Tkinter

__require__ = 1
__tk_call__ = None

# This function is not implemented yet.
token_append_implemented = 0

def __setup_globals(master):
    global __require__, __tk_call__
    if __require__:
        master.tk.call("package","require","Tkhtml")
        __tk_call__ = master.tk.call
        __require__ = None

def reformat(from_, to, text):
    "Reformat a string to another representation: plain, http, url, html"
    if __require__: __setup_globals(Tkinter._default_root)
    return __tk_call__("html", "reformat", from_, to, text)

def uri_join(scheme, authority, path, query, fragment):
    "Join the five components of the URI together."
    if __require__: __setup_globals(Tkinter._default_root)
    return __tk_call__("html", "urljoin", scheme, authority, path, query, fragment)

def uri_split(uri):
    "Takes an URI and splits it into it's five main components."
    if __require__: __setup_globals(Tkinter._default_root)
    return __tk_call__("html", "urlsplit", uri)

class Html(Tkinter.Widget):
    """Html widget"""
    def __init__(self, master=None, cfg={}, **kw):
        master.tk.call("package", "require", "Tkhtml")
        Tkinter.Widget.__init__(self, master, 'html', cfg, kw)

    def parse(self, text):
        """Add the given HTML-TEXT to the end of any text previously
        received through the parse command and parses as much of the
        text as possible into tokens.

        Afterwards, the display is updated to show the new tokens, if
        they're visible.
        """
        self.tk.call(self._w, "parse", text)

    def clear(self):
        "Clear the widget."
        self.tk.call(self._w, "clear")

    def href(self, x, y):
        "Returns the href at coordinates X, Y"
        return self.tk.call(self._w, "href", x, y)

    def index(self, index, count=None, units=None):
        "Translates 'index' into it's cannonical form."
        cmd = (index,)
        if count and units:
            cmd = cmd + (count,units)
        return self.tk.call(self._w, "index", *cmd)

    def insert(self, index):
        """Causes insertion point to be position immediately
        after the character at 'index'."""
        return self.tk.call(self._w, "insert", index)

    def names(self):
        """This command causes the widget to scan the entire text of
        the document looking for tags of the form:

            

        It returns a list of values of the 'name=...' fields.

        The vertical position of the widget can  be moved to any of
        these names using the 'WIDGET yview NAME' command described below.
        """
        return self.tk.call(self._w, "names")

    def resolver(self, *args):
        """The resolver specified by the -resolvercommand option is called
        with the base URI of the document followed by the remaining
        arguments to this command. The result of this command is the
        result of the -resolvercommand script.
        """
        return self.tk.call(self._w, "resolver", *args)

    def selection(self, subcommand, *args):
        """The selection() widget command is used to control the selection.

        WIDGET selection clear
            Clear the current selection.

        WIDGET selection set START END
            Change the selection to the text between the START and
            END indices.
        """
        return self.tk.call(self._w, "selection", *args)

    def selection_clear(self):
        "Clear the current selection."
        return self.selection("clear")

    def selection_set(self, start, end):
        "Set the selection to the text between start and end indices."
        return self.selection("set", start, end)

    def text(self, *args):
        """There are several token commands. They all have the common
        property that they directly manipulate the text which is currently
        displayed. This could be used to build a WYSIWYG html editor.
        """
        return self.tk.call(self._w, "text", *args)

    def text_ascii(self, index1, index2):
        """Returns plain ascii text that represents all characters
        between index1 and index2. Formatting tags are omitted.
        The index1 character is included but index2 is excluded.
        """
        return self.text("ascii", index1, index2)

    def text_delete(index1, index2):
        """All text from index1 up to --but not including-- index2 is
        removed and the display is updated accordingly.
        """
        return self.text("delete", index1, index2)

    def text_html(index1, index2):
        """Returns HTML text that represents all characters and formatting
        tags between index1 and index2, excluding the character at index2.
        """
        return self.text("html", index1, index2)

    def text_insert(self, index, text):
        """Inserts one or more characters immediately before the character
        whose index is given.
        """
        return self.text("insert", index, text)

    def token(self, subcommand, *args):
        """There are several token commands. They all have the common
        property that they involve the list of tokens into which the HTML
        text is parsed.

        Some of the following subcommands make use of indices. The character
        number of these indices is ignored, since these commands only deal
        with tokens.
        """
        return self.tk.call(self._w, "token", subcommand, *args)

    def token_append(self, tag, *args):
        "The token is appended to the current list of tokens."
        return self.token("append", tag.upper(), *args)

    def token_delete(self, index1, index2=None):
        """The token at the given index is deleted; if the second index
        is specified, then the range of tokens is deleted (second index
        inclusive).
        """
        if index2: return self.token("delete", index1, index2)
        return self.token("delete", index1)

    def token_find(self, tag):
        """Locats all tokens with the given tag and returns a list of
        them all. Each element of the list contains the index of the
        token and the token's arguments.
        """
        return self.token("find", tag)

    def token_get(self, index1, index2=None):
        """Returns a list of tokens in the range index1 through index2;
        each element of the list consists of the token tag followed
        by it's arguments.
        """
        if index2: return self.token("get", index1, index2)
        return self.token("get", index1)

    def token_handler(self, tag, handler=None):
        """This command allows special processing to occur for selected
        tokens in the HTML input stream. The tag argument is either "Text"
        or "Space", or the name of an HTML tag ("H3", "/A", etc).

        If a none-None function is specified for the handler, then when
        instances of that tag are encountered by the parser, the parser calls
        the corresponding function instead of appending the token to the
        end of the token list. Before calling the function, two arguments
        are appended:
        
            1. The tag (ex: "H3", "/TABLE", etc)
            2. A list of name/value pairs describing all tag arguments.

        An empty handler causes the default processing to occur for the tag.
        If the function argument is ommitted altogether, then the current
        value for the token handler for the given tag is returned.

        Only one handler for each token type may be defined. If a new handler
        for a given tag is set, then the previous handler is replaced.
        """
        if not handler: return self.token("handler", tag)
        if handler in ("", "{}"):
            # Delete the current handler for this tag.
            return self.token("handler", tag, handler)
        elif callable(handler):
            name = self.register(handler)
            self.token("handler", tag, name)
        else:
            raise ValueError("handler must be None, '' or callable.")

    def token_handler_delete(self, tag):
        "Deletes a handler for a token type."
        return self.token("handler", tag, "{}")

    def token_insert(self, index, tag, *arguments):
        """Inserts a single token given by tag and arguments into the
        token list immediately before the token given by index.
        """
        return self.token("insert", index, *arguments)

    def xview(self, *args):
        "Used to control horizontal scrolling."
        if args: return self.tk.call(self._w, "xview", *args)
        coords = map(float, self.tk.call(self._w, "xview").split())
        return tuple(coords)

    def xview_moveto(self, fraction):
        """Adjusts horizontal position of the widget so that fraction
        of the horizontal span of the document is off-screen to the left.
        """
        return self.xview("moveto", fraction)

    def xview_scroll(self, number, what):
        """Shifts the view in the window according to number and what;
        number is an integer, and what is either 'units' or 'pages'.
        """
        return self.xview("scroll", number, what)

    def yview(self, *args):
        "Used to control the vertical position of the document."
        if args: return self.tk.call(self._w, "yview", *args)
        coords = map(float, self.tk.call(self._w, "yview").split())
        return tuple(coords)

    def yview_name(self, name):
        """Adjust the vertical position of the document so that the tag
         is visible and preferably near the top of the window.
        """
        return self.yview(name)

    def yview_moveto(self, fraction):
        """Adjust the vertical position of the document so that fraction of
        the document is off-screen above the visible region.
        """
        return self.yview("moveto", fraction)

    def yview_scroll(self, number, what):
        """Shifts the view in the window up or down, according to number and
        what. 'number' is an integer, and 'what' is either 'units' or 'pages'.
        """
        return self.yview("scroll", number, what)

##
##  FINIS
##


class TestApp:
    def __init__(self):
        import Tkinter, tkFileDialog, TkHtml
        root = self._root = Tkinter.Tk()
        root.title("Html widget test")

        root["menu"] = mb = self._mb = Tkinter.Menu(root)
        file = self._file = Tkinter.Menu(mb)
        mb.add_cascade(menu=file, label="File", underline=0)

        html = self._html = TkHtml.Html(root)
        vsb = self._vsb = Tkinter.Scrollbar(root, orient="v", command=html.yview)
        html.configure(yscrollcommand=vsb.set)
        
        vsb.pack(side="right", fill="y", expand="yes")
        html.pack(side="left", fill="both", expand="yes")

        self._dialog = tkFileDialog.Open(root)

        # Bind some menu options.
        file.add_command(label="Default", underline=0, command=self.default)
        file.add_command(label="Open", underline=0, command=self.open)
        file.add_command(label="Clear", underline=0, command=html.clear)
        file.add_separator()
        file.add_command(label="Quit", underline=0, command=root.destroy)

        # Create some image placeholders.
        biggray = Tkinter.PhotoImage(data="R0lGODdhPAA+APAAALi4uAAAACwAAA"
                        "AAPAA+AAACQISPqcvtD6OctNqLs968+w+G4kiW5omm6sq27g"
                        "vH8kzX9o3n+s73/g8MCofEovGITCqXzKbzCY1Kp9Sq9YrNFg"
                        "sAO///")

        smallgray = Tkinter.PhotoImage(data="R0lGODdhOAAYAPAAALi4uAAAACwA"
                        "AAAAOAAYAAACI4SPqcvtD6OctNqLs968+w+G4kiW5omm6sq2"
                        "7gvH8kzX9m0VADv/")

        nogifbig = Tkinter.PhotoImage(data="R0lGODdhJAAkAPEAAACQkADQ0PgAA"
                        "AAAACwAAAAAJAAkAAACmISPqcsQD6OcdJqKM71PeK15AsSJH"
                        "0iZY1CqqKSurfsGsex08XuTuU7L9HywHWZILAaVJssvgoREk"
                        "5PolFo1XrHZ29IZ8oo0HKEYVDYbyc/jFhz2otvdcyZdF68qe"
                        "Kh2DZd3AtS0QWcDSDgWKJXY+MXS9qY4+JA2+Vho+YPpFzSji"
                        "TIEWslDQ1rDhPOY2sXVOgeb2kBbu1AAADv/")

        nogifsm = Tkinter.PhotoImage(data="R0lGODdhEAAQAPEAAACQkADQ0PgAAA"
                        "AAACwAAAAAEAAQAAACNISPacHtD4IQz80QJ60as25d3idKZd"
                        "R0IIOm2ta0Lhw/Lz2S1JqvK8ozbTKlEIVYceWSjwIAO///")

        tl = Tkinter.Toplevel(root)
        for img in (biggray, smallgray, nogifbig, nogifsm):
            Tkinter.Label(tl, image=img).pack()

    def default(self):
        self._html.clear()
        self._html.parse(open(r"tkhtml-spec.html").read())

    def open(self):
        file = self._dialog.show()
        if file:
            self._html.clear()
            self._html.parse(open(file).read())

if __name__ == "__main__":
    test = TestApp()

No comments :

Post a Comment