'''16 在你的应用程序中加入{{{HTML}}}''' '''本章内容:''' * 在{{{wxPython}}}窗口中显示{{{HTML}}} * 处理和打印{{{HTML}}}窗口 * 使用{{{HTML}}}分析器({{{parser)}}} * 支持新的标记和其它的文件格式 * 在{{{HTML}}}中使用控件 {{{HTML}}}最初是打算被作为超文本系统使用的一个简单的语义标记来使用的。迄今为止,{{{HTML}}}已经变得更加的复杂和被广泛使用。{{{HTML}}}文档标记已经被证明在网页浏览器之外也是有用的。目前{{{HTML}}}文档标记通常被用于文本标记(如在文本控件中),或用于管理一系列的超链接页面(帮助系统中)。在{{{wxPython}}}中,有许多专用于处理你的{{{HTML}}}需求的特性。你可以在一个窗口中显示简单的{{{HTML}}},并用超链接创建你自己的帮助页面,如果你需要的话,甚至你还可以嵌入一个功能更全的浏览器。 下一节内容提示:如何在{{{wxPython}}}窗口中显示{{{HTML}}}? == 显示HTML == 在{{{wxPython}}}中,你对{{{HTML}}}能做的最重要的事情就是将它显示在一个窗口中。下面的两节,我们将讨论{{{HTML}}}窗口对象,以及给你展示如何对本地的文本或远程的{{{URL}}}使用它。 === 如何在一个wxPython窗口中显示HTML? === 正如我们在第六章中讨论的,对于使用样式文本或简单的网格来快速地描述文本的布局,{{{wxPython}}}中的{{{HTML}}}是一个有用的机制。{{{wxPython}}}的{{{wx.html.HtmlWindow}}}类就是用于此目的的。图16.1显示了一个例子。 '''图16.1''' {{attachment:w16.1.gif}} 例16.1显示了用于产生图16.1的代码。 '''例16.1''' '''显示简单地{{{HtmlWindow}}}''' {{{import wx}}} {{{#!python import wx.html 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( "Here is some b formatted /b i u text /u /i " "loaded from a font color=\"red\" string /font .") app = wx.PySimpleApp() frm = MyHtmlFrame(None, "Simple HTML") frm.Show() app.MainLoop() }}} {{{wx.html.HtmlWindow}}}的构造函数基本上是与{{{wx.ScrolledWindow}}}相同的,如下所示: {{{#!python wx.html.HtmlWindow(parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.html.HW_SCROLLBAR_AUTO, name="htmlWindow") }}} 上面的这些参数现在看着应该比熟悉。这最重要的不同点是默认样式{{{wx.html.HW_SCROLLBAR_AUTO}}},它将告诉{{{HTML}}}窗口在需要的时候自动增加滚动条。与之相反的样式是{{{wx.html.HW_SCROLLBAR_NEVER}}},使用该样式将不会显示滚动条。还有一个{{{HTML}}}窗口样式是{{{wx.html.HW_NO_SelectION}}},它使得用户不能选择窗口中的文本。 当在{{{HTML}}}窗口中写要显示的{{{HTML}}}时,记住所写的{{{HTML}}}要是简单的。因为{{{wx.html.HtmlWindow}}}控件仅设计用于简单样式文本显示,而非用于全功能的多媒体超文本系统。它只支持最基本的文本标记,更高级的特性如层叠样式表({{{css)}}}和{{{JavaScript}}}不被支持。表16.1包含了官方支持的{{{HTML}}}标记。通常,这里的标记和它的属性的行为和{{{web}}}浏览器中的一样,但是由于它不是一个完全成熟的浏览器,所以有时会出现一些奇怪行为的情况。表16.1中列出了后跟有属性的标记。 '''表16.1''' '''用于{{{HTML}}}窗口控件的有效的标记''' ||<|2>文档结构标记|| {{{a href name target body alignment bgcolor }}}|| ||{{{link text meta content http-equiv title }}}|| ||文本结构标记|| {{{br div align hr align noshade size width p }}}|| ||<|3>文本显示标记|| {{{address b big blockquote center cite}}}|| ||{{{code em font color face size h1 h2 h3 h4 h5 h6 }}}|| ||{{{i kbd pre samp small strike string tt u }}}|| ||列表标记|| {{{dd dl dt li ol ul }}}|| ||<|2>图像和地图标记|| {{{area coords href shape img align }}}|| ||{{{height src width usemap map name }}}|| ||<|4>表格标记|| {{{table align bgcolor border cellpadding }}}|| ||{{{cellspacing valign width td align bgcolor colspan}}}|| ||{{{rowspan valign width nowrap th align bgcolor colspan}}}|| ||{{{valign width rowspan tr align bgcolor valign }}}|| {{{HTML}}}窗口使用{{{wx.Image}}}来装载和显示图像,所以它可以支持所有{{{wx.Image}}}支持的图像文件格式。 === 如何显示来自一个文件或URL的HTML? === 一旦你创建了一个{{{HTML}}}窗口,接下来就是在这个窗口中显示{{{HTML}}}文本。下面的四个方法用于在窗口中得到{{{HTML}}}文本。 * {{{SetPage(source)}}} * {{{AppendToPage(source)}}} * {{{LoadFile(filename)}}} * {{{LoadPage(location)}}} 其中最直接的方法是{{{SetPage(source)}}},参数{{{source}}}是一个字符串,它包含你想显示在窗口中的{{{HTML}}}资源。 你可以使用方法{{{AppendToPage(source)}}}添加{{{HTML}}}到窗口中的文本的后面。至于{{{SetPage()}}}和{{{AppendToPage()}}}方法,其中的参数{{{source}}}被假设是{{{HTML}}},这意味着,如果你传递的是纯文本,那么其中的间距将被忽略,以符合{{{HTML}}}标准。 如果你想让你的窗口在浏览外部的资源时更像一个浏览器,那么你有两种方法。方法{{{LoadFile(filename)}}}读取本地文件的内容并将它们显示在窗口中。在这种情况中,窗口利用{{{MIME}}}文件类型来装载一个图像文件或一个{{{HTML}}}文件。如果它不能确定文件是何种类型,那么它将以纯文本的方式装载该文件。如果被装载的文档包含有相关图像或其它文档的链接,那么被用于解析那些链接的位置是原文件的位置。 当然,一个实际的浏览器不会只局限于本地文件。你可以使用方法{{{LoadPage(location)}}}来装载一个远程的{{{URL}}},其中参数{{{location}}}是一个{{{URL}}},但是对于本地文件,它是一个路径名。{{{MIME}}}类型的{{{URL}}}被用来决定页面如何被装载。本章的稍后部分,我们将讨论如何增加对新文件类型的支持。 图16.2显示了被装载入{{{HTML}}}窗口中的一个页面。 '''图16.2''' {{attachment:w16.2.gif}} 例16.2显示了产生图16.2的代码 '''例16.2''' '''从一个{{{web}}}页装载{{{HTML}}}窗口的内容''' {{{#!python import wx import wx.html class MyHtmlFrame(wx.Frame): def __init__(self, parent, title): wx.Frame.__init__(self, parent, -1, title, size=(600,400)) html = wx.html.HtmlWindow(self) if "gtk2" in wx.PlatformInfo: html.SetStandardFonts() wx.CallAfter( html.LoadPage, "http://www.wxpython.org") app = wx.PySimpleApp() frm = MyHtmlFrame(None, "Simple HTML Browser") frm.Show() app.MainLoop() }}} 例16.2中关键的地方是方法{{{LoadPage()}}}。拥有更完整特性的浏览器窗口还应有显示{{{URL}}}的文本框,并在当用户键入一个新的{{{URL}}}后,可以改变窗口中的内容。 == 管理HTML窗口 == 一旦你有了一个{{{HTML}}}窗口,你就可以通过不同的方法来管理它。你可以根据用户的输入来触发相应的动作,处理窗口的内容,自动显示有关窗口的信息和打印页面等。在随后的几节中,我们将讨论如何实现这些。 === 如何响应用户在一个链接上的敲击? === {{{wx.html.HtmlWindow}}}的用处不只限于显示。还可以用于响应用户的输入。在这种情况下,你不需要定义你自己的处理器,你可以在你的{{{wx.html.HtmlWindow}}}的子类中覆盖一些处理函数。 表16.2说明了已定义的处理函数。{{{wx.html.HtmlWindow}}}类没有使用事件系统定义事件,所以你必须使用这些重载的成员函数来处理相关的事件,而非绑定事件类型。 另外,如果你想让一个{{{HTML}}}窗口响应用户的输入,你必须创建你自己的子类并覆盖这些方法。 '''表16.2''' '''{{{wx.html.HtmlWindow}}}的事件处理函数''' ||{{{OnCellClicked(cell, x, y, event)}}}||当用户在{{{HTML}}}文档中敲击时调用。参数{{{cell}}}是一个{{{wx.html.HtmlCell}}}对象,该对象代表所显示的文档的一部分,诸如文本、单元格或图像等。{{{wx.html.HtmlCell}}}类被{{{HTML}}}解析器创建,这将在本章后部分讨论。参数{{{x,y}}}是鼠标敲击的准确位置(像素单位),参数{{{event}}}是相关的鼠标敲击事件。如果{{{cell}}}包含一个链接,那么这个方法的默认版本将简单地委托给{{{OnLinkClicked()}}},否则它什么也不做。|| ||{{{OnCellMouseHover(cell, x, y)}}}||当鼠标经过一个{{{HTML}}}单元时调用。参数同{{{OnCellClicked()}}}。|| ||{{{OnLinkClicked(link)}}}||当用户在一个超链接上敲击时调用。该方法的默认版对链接的{{{URL}}}调用{{{LoadPage}}}。覆盖该方法通常用于使用{{{HtmlWindow}}}来为应用程序制作一个关于框。在那种情况下,你可以改变行为以便用户通过敲击其中的主页来使用{{{Python}}}的{{{webbrowser}}}模块去运行系统默认的浏览器。|| ||{{{OnOpeningURL(type, url)}}}||当用户请求打开一个{{{URL}}}时调用,不管打开页面或页面中的一个图像。参数{{{type}}}可以是{{{wx.html.HTML_URL_PAGE, wx.html.HTML_URL_IMAGE, }}}或{{{wx.html.HTML_URL_OTHER}}}。该方法返回下列值之一——{{{wx.html.HTML_OPEN}}}允许资源装载,{{{wx.html.HTML_BLOCK}}};阻止载入资源;或用于{{{URL}}}重定向的一个字符串,并且在重定向后该方法再一次被调用。该方法的默认版总是返回{{{wx.html.HTML_OPEN}}}。|| ||{{{OnSetTitle(title)}}}||当{{{HTML}}}源文件中有 {{{title }}}标记时调用。通常用于在应用程序中显示标题。|| === 如何使用编程的方式改变一个HTML窗口? === 当你正显示一个{{{HTML}}}页时,你还可以改变你的窗口像浏览器样去显示其它的内容,如一另一个{{{Web}}}页,或帮助文件或其它类型的数据,以响应用户的需要。 有两个方法来当{{{HTML}}}窗口在运行时,访问和改变{{{HTML}}}窗口中的信息。首先,你可以使用{{{GetOpenedPage()}}}方法来得到当前打开的页面的{{{URL}}}。该方法只在当前页是被{{{LoadPage()}}}方法装载的才工作。如果是这样的,那么方法的返回值是当前页的{{{URL}}}。否则,或当前没有打开的页面,该方法返回一个空字符串。另一个相关的方法是{{{GetOpenedAnchor()}}},它返回当前打开页面中的锚点({{{anchor}}})。如果页面不是被{{{LoadPage()}}}打开的,你将得到一个空的字符串。 要得到当前页的{{{HTML}}}标题,可以使用方法{{{GetOpenedPageTitle()}}},这将返回当前页的 {{{title }}}标记中的值。如果当前页没有一个 {{{title }}}标记,你将得到一个空的字符串。 这儿有几个关于改变窗口中文本的选择的方法。方法{{{SelectAll()}}}选择当前打开的页面中的所有文本。你可以使用{{{SelectLine(pos)}}}或{{{SelectWord(pos)}}}做更有针对性的选择。其中{{{pos}}}是鼠标的位置{{{wx.Point}}},这两个方法分别选择一行或一个词。要取得当前选择中的纯文本内容,可以使用方法{{{SelectionToText()}}},而方法{{{ToText()}}}返回整个文档的纯文本内容。 {{{wx.html.HtmlWindow}}}维护着历史页面的一个列表。使用下表16.3中的方法,可以如通常的浏览器一样浏览这个历史列表。 '''表16.3''' ||{{{HistoryBack()}}}||装载历史列表中的前一项。如果不存在则返回{{{False}}}。|| ||{{{HistoryCanBack()}}}||如果历史列表中存在前一项,则返回{{{True}}},否则返回{{{False}}}。|| ||{{{HistoryCanForward()}}}||如果历史列表中存在下一项,则返回{{{True}}},否则返回{{{False}}}。|| ||{{{HistoryClear()}}}||清空历史列表。|| ||{{{HistoryForward()}}}||装载历史列表中的下一项。如果不存在则返回{{{False}}}。|| 要改变正在使用的字体,可以使用方法{{{SetFonts(normal_face, fixed_face, sizes=None)}}}。参数{{{normal_face}}}是你想用在窗口显示中的字体的名字字符串。如果{{{normal_face}}}是一个空字符串,则使用系统默认字体。参数{{{fixed_face}}}指定固定宽度的文本,类似于 {{{pre }}}标记的作用。如果指定了{{{fixed_face}}}参数,那么参数{{{sizes}}}则应是一个代表字体的绝对尺寸的包含7个整数的列表,它对应于{{{HTML}}}逻辑字体尺寸(如 {{{font }}}标记所使用的)-2~+4之间。如果该参数没有指定或是{{{None}}},则使用默认的。关于默认常量{{{wx.html.HTML_FONT_SIZE_n}}},n位于1~7之间。这些默认常量指定了对应于{{{HTML}}}逻辑字体尺寸所使用的默认字体。准确的值可能因不同的底层系统而不同。要选择一套基于用户的系统的字体和尺寸,可以调用{{{SetStandardFonts()}}}。这在{{{GTK2}}}下运行{{{wxPython}}}时是特别有用的,它能够提供一套更好的字体。 如果由于某种原因,你需要改变窗口中文本边缘与窗口边缘之间的间隔的话,{{{HTML}}}窗口定义了{{{SetBorders(b)}}}方法。参数b是间隔的像素宽度(整数值)。 === 如何在窗口的标题栏中显示页面的标题? === 在你的{{{web}}}浏览器中,你可能也注意到了一件事,那就是浏览器中不光只有显示窗口,还有标题栏和状态栏。通常,标题栏显示打开页面的标题,状态栏在鼠标位于链接上时显示链接信息。在{{{wxPython}}}中有两个便捷的方法来实现这些。图16.3对此作了展示。窗口显示的标题是基于{{{web}}}页面的标题的,状态栏文本也来自{{{Html}}}窗口。 例16.3是产生图16.3的代码。 '''图16.3''' '''带有状态栏和标题栏的{{{HTML}}}窗口''' {{attachment:w16.3.gif}} '''例16.3''' '''从一个{{{web}}}页载入{{{HTMLWindow}}}的内容''' {{{#!python #-*- encoding:UTF-8 -*- import wx import wx.html class MyHtmlFrame(wx.Frame): def __init__(self, parent, title): wx.Frame.__init__(self, parent, -1, title, size=(600,400)) self.CreateStatusBar() html = wx.html.HtmlWindow(self) if "gtk2" in wx.PlatformInfo: html.SetStandardFonts() html.SetRelatedFrame(self, self.GetTitle() + " -- %s") #关联HTML到框架 html.SetRelatedStatusBar(0) #关联HTML到状态栏 wx.CallAfter( html.LoadPage, "http://www.wxpython.org") app = wx.PySimpleApp() frm = MyHtmlFrame(None, "Simple HTML Browser") frm.Show() app.MainLoop() }}} 要设置标题栏的关联,使用方法{{{SetRelatedFrame(frame, format)}}}。参数{{{frame}}}你想显示页面标题的框架。参数{{{format}}}是你想在框架的标题栏中显示的字符串。通常的格式是这样:“{{{My wxPython Browser: }}}%s”。:%s前面的字符串可以是你想要的任何字符串,%s将会被{{{HTML}}}页面的标题所取代。在窗口中,一个页面被载入时,框架的标题自动被新的页面的信息取代。 要设置状态栏,使用方法{{{SetRelatedStatusBar(bar)}}}。该方法必须在{{{SetRelatedFrame()}}}之后调用。参数{{{bar}}}是状态栏中用于显示状态信息的位置。通常它是0,但是如果状态栏中存在多个显示区域,那么{{{bar}}}可以有其它的值。如果{{{bar}}}的取值为-1,那么不显示任何信息。一旦与状态栏的关联被创建,那么当鼠标移动到显示的页面的链接上时,相关链接的{{{URL}}}将显示在状态栏中。 === 如何打印一个HTML页面? === 一旦{{{HTML}}}被显示在屏幕上,接下来可能做的事就是打印该{{{HTML}}}。类{{{wx.html.HtmlEasyPrinting}}}就是用于此目的的。你可以使用下面的构造函数来创建{{{wx.html.HtmlEasyPrinting}}}的一个实例: {{{ wx.html.HtmlEasyPrinting(name="Printing", parentWindow=None) }}} 参数{{{name}}}只是一个用于显示在打印对话框中的字符串。参数{{{parentWindow}}}如果被指定了,那么{{{parentWindow}}}就是这些打印对话框的父窗口。如果{{{parentWindow}}}为{{{None}}},那么对话框为顶级对话框。你只应该创建{{{wx.html.HtmlEasyPrinting}}}的一个实例。尽管{{{wxPython}}}系统没有强制要这样做,但是该类是被设计为独自存的。 '''使用{{{wx.html.HtmlEasyPrinting}}}的实例''' 从该类的名字可以看出,它应该是容易使用的。首先,通过使用{{{PrinterSetup()}}}和{{{PageSetup()}}}方法,你能够给用户显示用于打印设置的对话框。调用这些方法将导致相应的对话框显示给用户。实例将存储用户所做的设置,以备后用。如果你想访问这些设置数据,以用于你自己特定的处理,你可以使用方法{{{GetPrintData()}}}和{{{GetPageSetupData()}}}。{{{GetPrintData()}}}方法返回一个{{{wx.PrintData}}}对象,{{{GetPageSetupData()}}}方法返回一{{{wx.PageSetupDialogData}}}对象,我们将在第17章中更详细地讨论。 '''设置字体''' 你可以使用方法{{{SetFonts(normal_face, fixed_face, sizes)}}}来设置打印所使用的字体。这个方法的行为同用于{{{HTML}}}窗口的{{{SetFonts()}}}相同(在打印对象中的设置不会影响到{{{HTML}}}窗口中的设置)。你可以使用方法{{{SetHeader(header, pg)}}}和{{{SetFooter(footer, pg)}}}来页眉和页脚。参数{{{header}}}和{{{footer}}}是要显示的字符串。字符串中你可以使用点位符@{{{PAGENUM}}}@,占位符在执行时被打印的页号替代。你也可以使用@{{{PAGENUM}}}@占位符,它是打印的页面总数。参数{{{pg}}}的取值可以是这三个:{{{wx.PAGE_ALL}}}、{{{wx.PAGE_EVEN}}}或{{{wx.PAGE_ODD}}}。它控制页眉和页脚显示在哪个页上。通过对不同的{{{pg}}}参数多次调用该方法,可以为奇数页和偶数页设置单独的页眉和页脚。 '''输出预览''' 如果在打印前,你想预览一下输出的结果,你可以使用{{{PreviewFile(htmlfile)}}}方法。在这种情况下,参数{{{htmlfile}}}是你本地的包含{{{HTML}}}的文件的文件名。另一是{{{PreviewText(htmlText, basepath=}}}"")。参数{{{htmlText}}}是你实际想打印的{{{HTML}}}。{{{basepath}}}文件的路径或{{{URL}}}。如预览成功,这两个方法均返回{{{True}}},否则返回{{{False}}}。如果出现了错误,那么全局方法{{{wx.Printer.GetLastError()}}}将得到更多的错误信息。关于该方法的更详细的信息将在第17章中讨论。 '''打印''' 现在你可能想知道如何简单地打印一个{{{HTML}}}页面。方法就是{{{PrintFile(htmlfile)}}}和{{{PrintText(htmlText, basepath)}}}。其中的参数同预览方法。所不同的是,这两个方法使用对话框中的设置直接让打印机打印。打印成功,则返回{{{True}}}。 == 拓展HTML窗口 == 在这一节,我们将给你展示如何处理{{{HTML}}}窗口中的{{{HTML}}}标记,如何创造你自己的标记,如何在{{{HTML}}}中嵌入{{{wxPython}}}控件,如何处理其它的文件格式,以及如何在你的应用程序中创建一个真实的{{{HTML}}}浏览器。 === HTML解析器(parser)是如何工作的? === 在{{{wxPython}}}中,{{{HTML}}}窗口有它自己内在的解析器。实际上,这里有两个解析器类,但是其中的一个是另一个的改进。通常,使用解析器工作仅在你想扩展{{{wx.html.HtmlWindow}}}自身的功能时有用。如果你正在使用{{{Python}}}编程,并基于其它的目的想使用一个{{{HTML}}}解析器,那么我们建议你使用随同{{{Python}}}发布的{{{htmllib}}}和{{{HTMLParser}}}这两个解析器模块之一,或一个外部的{{{Python}}}工具如“{{{Beautiful Soup}}}”。 两个解析器类分别是{{{wx.html.HtmlParser}}},它是一个更通用的解析器,另一个是{{{wx.html.HtmlWinParser}}},它是{{{wx.html.HtmlParser}}}的子类,增加了对在{{{wx.html.HtmlWindow}}}中显示文本的支持。由于我们所关注的基本上是{{{HTML}}}窗口,所以我们将重点关注{{{wx.html.HtmlWinParser}}}。 要创建一个{{{HTML}}}解析器,可以使用两个构造函数之一。其中基本的一个是{{{wx.html.HtmlWinParser()}}},没有参数。{{{wx.html.HtmlWinParser}}}的父类{{{wx.html.HtmlParser}}}也有一个没有参数的构造函数。你可以使用另一个构造函数{{{wx.html.HtmlWinParser(wnd)}}}将一个{{{wx.html.HtmlWinParser()}}}与一个已有的{{{wx.html.HtmlWindow}}}联系在一起,参数{{{wnd}}}是{{{HTML}}}窗口的实例。 要使用解析器,最简单的方法是调用{{{Parse(source)}}}方法。参数{{{source}}}是要被处理的{{{HTML}}}字符串。返回值是已解析了的数据。对于一个{{{wx.html.HtmlWinParser}}},返回值是类{{{wx.html.HtmlCell}}}的一个实例。 {{{HTML}}}解析器将{{{HTML}}}文本转换为一系列的单元,一个单元可以表示一些文本,一个图像,一个表,一个列表,或其它特定的元素。{{{wx.html.HtmlCell}}}的最重要的子类是{{{wx.html.HtmlContainerCell}}},它是一个可以包含其它单元在其中的一个单元,如一个表或一个带有不同文本样式的段落。对于你解析的几乎任何文档,返回值都将是一个{{{wx.html.HtmlContainerCell}}}。每个单元都包含一个{{{Draw(dc, x, y, view_y1, view_y2)}}}方法,这使它可以在{{{HTML}}}窗口中自动绘制它的信息。 另一个重要的子类单元是{{{wx.html.HtmlWidgetCell}}},它允许一个任意的{{{wxPython}}}控件像任何其它单元一样被插入到一个{{{HTML}}}文档中。除了可以包括用于格式化显示的静态文本,这也包括任何类型的用于管理{{{HTML}}}表单的控件。{{{wx.html.HtmlWidgetCell}}}的构造函数如下: {{{ wx.html.HtmlWidgetCell(wnd, w=0) }}} 其中参数{{{wnd}}}是要被绘制的{{{wxPython}}}控件。参数w是一个浮动宽度。如果w不为0,那么它应该是介于1和100之间的一个整数,{{{wnd}}}控件的宽度则被动态地调整为相对于其父容器宽度的w%。 另外还有其它许多类型的用于显示{{{HTML}}}文档的部分的单元。更多的信息请参考{{{wxWidget}}}文档。 === 如何增加对新标记的支持? === 被解析器返回的单元是被标记处理器内在的创建的,通过{{{HTML}}}标记,一个可插入的结构与{{{HTML}}}解析器单元的创建和处理相联系起来。你可以创建你自己的标记处理器,并将它与{{{HTML}}}标记相关联。使用这个机制,你可以扩展{{{HTML}}}窗口,以包括当前不支持的标准标记,或你自己发明的自定义的标记。图16.4显示了自定义{{{HTML}}}标记的用法。 '''图16.4''' {{attachment:w16.4.gif}} 下例16.4是产生图16.4的代码。 例16.4 定义并使用自定义的标记处理器 {{{#!python 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, blue 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 specifed 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) self.GetParser().GetContainer().InsertCell(wx.html.HtmlColourCell(clr)) self.ParseInner(tag) self.GetParser().SetActualColor(old) self.GetParser().GetContainer().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() }}} 标记内在的由类{{{wx.Html.Tag}}}的方法来表现,标记的实例由{{{HTML}}}解析器来创建,通常,你不需要自己创建。表16.4显示了{{{wx.Html.Tag}}}类的方法,它们有用于检索标记的信息。 '''表16.4''' '''{{{wx.Html.Tag}}}的一些方法''' ||{{{GetAllParams()}}}||返回与标记相关的所有参数,返回值是一个字符串。出于某些目的,解析字符串比得到各个单独的参数更容易。|| ||{{{GetName()}}}||以大写的方式,返回标记的名字。|| ||{{{HasParam(param)}}}||如果标记给定了参数,则返回{{{True}}}。|| ||{{{GetParam(param, with_commas=False)}}}||返回参数{{{param}}}的值。如果参数 {{{with_commas}}}为 {{{True}}},那么你得到一个首尾都有引号的原始字符串。如果没有指定该参数,那么返回一个空字符串。方法{{{GetParamAsColour(param)}}}返回的参数值是一个{{{wx.Color}}},方法{{{GetParamAsInt(param)}}}返回整数值。|| ||{{{HasEnding()}}}||如果标记有结束标记的话,返回{{{True}}},否则返回{{{false}}}。|| 用于扩展{{{HTML}}}窗口的标记处理器都是{{{wx.html.HtmlWinTagHandler}}}的子类。你的子类需要覆盖两个方法,并且你需要知道进一步的方法。需要覆盖的第一个方法是{{{GetSupportedTags()}}}。该方法返回由处理器管理的标记的列表。标记必需是大写的,并且标记之间以逗号分隔,中间不能有空格,如下所示: {{{#!python GetSupportedTags(self): return "MYTAG,MYTAGPARAM" }}} 第二个你需要覆盖的方法是{{{HandleTag(tag)}}}。在{{{HandleTag(tag)}}}方法中,你通过增加新的单元元素到解析器来处理标记(或者交替地改变解析器已经打开的容器单元)。你可以通过调用标记处理器的{{{GetParser()}}}方法来得到解析器。 要写一个{{{HandleTag(tag)}}}方法,你应该像下面这样做: 1、得到解析器。 2、对你的标记的参数做必要的处理,可能要改变或创建一个新的单元。 3、如果被解析的标记包括着内在的文本,那么解析标记之间的文本。 4、执行对于解析器所需要的任何清理工作。 如上所述,你使用{{{GetParser()}}}方法得解析器。要添加或编辑解析器中的单元,你有三个可选方案。第一个,如果你想添加另一个单元到容器中,你可以工作于当前的容器。第二个,你可以调用解析器的{{{Container()}}}方法,然后创建你的{{{wx.html.HTMLCell}}}子类实例,并通过调用容器的{{{InsertCell(cell)}}}方法将它添加到容器。 有时,你可能想在当前打开的容器中创建一个附属的或内嵌的容器。例如内嵌于表的一行中的一个单元格。要实现这个,你需要调用解析器的{{{OpenContainer()}}}方法。这个方法返回你的新的容器单元,你可以使用{{{InsertCell(cell)}}}方法来插入显示单元到你的新的容器单元中。对于每个在你的标记处理器中打开的容器,你应该使用{{{CloseContainer()}}}方法来关闭它。如果你没有成对的使用{{{OpenContainer()}}}和{{{CloseContainer()}}},那么这将导致解析器解析余下的{{{HTML}}}文本时出现混乱。 第三个方案是创建一个与解析器的当前容器同级的容器,意思是不是嵌入的。例如一个新的段落——它不是前一段的一部分,也不附属于前一段;它是该页中?囊桓鲂碌氖堤濉N嗽诮馕銎髦惺迪终飧龇桨福阈枰乇障执娴娜萜鳎俅蛞桓鲂碌娜萜鳎缦滤荆? {{{ parser = self.GetParser() parser.CloseContainer()#关闭现存的容器 parser.OpenContainer()#打一个新的容器 # 添加或编辑解析器中的单元 parser.CloseContainer() parser.OpenContainer() }}} === 如何支持其他的文件格式? === 默认情况下,{{{HTML}}}窗口可以处理带有{{{MIME}}}类型{{{text}}}/{{{html, text}}}/{{{txt, }}}和{{{image}}}/*(假设{{{wxPython}}}图像处理器已经被装载)的文件。当碰上一个不是图像或{{{HTML}}}文件的文件时,该{{{HTML}}}窗口试图以纯文本的方式显示它。这可以不是你想要的行为。如果有一些文件你想以自定义的方式显示它的话,你可以创建一个{{{wx.html.HtmlFilter}}}来处理它。比如,你可能想以源代码树的方式显示{{{XML}}}文件,或使用语法着色来显示{{{Python}}}源代码文件。 要创建一个筛选器({{{filter}}}),你必须建造{{{wx.html.HtmlFilter}}}的一个子类。{{{wx.html.HtmlFilter}}}类有两个方法,你必须都覆盖它们。这第一个方法是{{{CanRead(file)}}}。参数{{{file}}}是{{{wx.FSFile}}}(一个打开的文件的{{{wxPython}}}表示)的一个实例。类{{{wx.FSFile}}}有两个属性,你可以用来决定你的筛选器是否能够读该文件。方法{{{GetMimeType()}}}以一个字符串的形式返回该文件的{{{MIME}}}类型。{{{MIME}}}类型通常由文件的后缀所定义。方法{{{GetLocation()}}}返回带有相关文件位置的绝对路径或{{{URL}}}的一个字符串。如果筛选器会处理该文件的话,{{{CanRead()}}}方法应该返回{{{True}}},否则返回{{{False}}}。处理{{{Python}}}源文件的{{{CanRead()}}}的一个示例如下: {{{#!python CanRead(self, file): return file.GetLocation().endswith('.py') }}} 第二个你需要覆盖的方法是{{{ReadFile(file)}}}。这个方法要求一个同样的{{{file}}}参数,并返回该文件内容的一个字符串的{{{HTML}}}表达。如果你不想使用{{{wxWidgets C}}}++的文件机制来读该文件的话,你可以通过简单地打开位于{{{file.GetLocation()}}}的文件来使用{{{Python}}}的文件机制。 一旦筛选器被创建了,那么它必须被注册到{{{wx.html.HtmlWindow}}},使用{{{wx.html.HtmlWindow}}}窗口的{{{AddFilter(filter)}}}静态方法来实现。参数{{{filter}}}是你的新的{{{wx.html.HtmlFilter}}}类的一个实例。一旦注册了筛选器,那么该窗口就可以使用筛选器来管理通过了{{{CanRead()}}}测试的文件对象。 === 如何得到一个性能更加完整的HTML控件? === 尽管{{{wx.html.HtmlWindow}}}不是一个完整特性的浏览器面板,但是这儿有一对用于嵌入更加完整特性的{{{HTML}}}表现窗口的选择。如果你是在{{{Windows}}}平台上,你可以使用类{{{wx.lib.iewin.IEHtmlWindow}}},它是{{{Internet Explorer ActiveX}}}控件的封装。这使得你能够直接将{{{ie}}}窗口嵌入到你的应用程序中。 使用{{{IE}}}控件比较简单,类似于使用内部的{{{wxPython}}}的{{{HTML}}}窗口。它的构造函数如下: {{{#!python wx.lib.iewin.IEHtmlWindow(self, parent, ID=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, name='IEHtmlWindow') }}} 其中参数{{{parent}}}是父窗口,{{{ID}}}是{{{wxPython ID}}}。对于{{{IE}}}窗口,这儿没有可用的样式标记。要装载{{{HTML}}}到{{{IE}}}组件中,可以使用方法{{{LoadString(html)}}},其中参数{{{html}}}是要显示的一个{{{HTML}}}字符串。你可以使用方法{{{LoadStream(stream)}}}装载自一个打开的文件,或一个{{{Python}}}文件对象;或使用{{{LoadString(URL)}}}方法装载自一个{{{URL}}}。你能够使用{{{GetText(asHTML)}}}来获取当前显示的文本。参数{{{asHTML}}}是布尔值。如果为{{{True}}},则返回{{{HTML}}}形式的文本,否则仅返回一个文本字符串。 在其它平台上,你可以尝试一下{{{wxMozilla}}}项目({{{http:}}}//{{{wxmozilla.sourceforge.net)}}},该项目尝试创建一个{{{Mozilla Gecko}}}表现器的{{{wxPython}}}封装。目前该项目仍在测试阶段。{{{wxMozilla}}}有用于{{{Windows}}}和{{{Linux}}}的安装包,对{{{Mac OS X}}}的支持正在开发中。 == 本章小结 == 1、{{{HTML}}}不再是只用于{{{Internet}}}了。在{{{wxPython}}}中,你可以使用一个{{{HTML}}}窗口来显示带有{{{HTML}}}标记的简单子集的文本。该{{{HTML}}}窗口属于{{{wx.html.HtmlWindow}}}类。除了{{{HTML}}}文本,该{{{HTML}}}窗口还可以管理任一的图像(图像处理器已装载的情况下)。 2、你可以让{{{HTML}}}窗口显示一个字符串,一个本地文件或一个{{{URL}}}的信息。你可以像通常的超文本浏览器的方式显示用户的敲击,或使用它自定义的响应。你也可以将{{{HTML}}}窗口与它的框架相连接起来,以便标题和状态信息自动地显示在适当的地方。{{{HTML}}}窗口维护着一个历史列表,你可以对它进行访问和处理。你可以使用类{{{wx.Html.HtmlEasyPrinting}}}来直接打印你的页面。 3、在{{{wxPython}}}中有一个{{{HTML}}}解析器,你可以用来创建用于你自己窗口的自定义标记。你也可以配置自定义的文件筛选器来在一个{{{HTML}}}窗口中表现其它的文件格式。 4、最后,如果你对{{{HTML}}}窗口的局限性不太满意的话,那么你可以使用一个对{{{IE}}}控件的{{{wxPython}}}封闭。如果你不在{{{Windows}}}上的话,这儿也有一个对{{{Mozilla Gecko HTML}}}表现器的{{{wxPython}}}的封装。