# 第十六章 在應用程序中加入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**

例16.1顯示了用于產生圖16.1的代碼。
**例16.1** **顯示簡單地`HtmlWindow`**
`import?wx`
```
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`相同的,如下所示:
```
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`窗口控件的有效的標記**
| | |
| --- | --- |
| 文檔結構標記 | `a?href?name?target???body?alignment?bgcolor?` |
| `link?text???meta?content?http-equiv??title?` |
| 文本結構標記 | `br???div?align???hr?align?noshade?size?width???p??` |
| 文本顯示標記 | `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?` |
| 圖像和地圖標記 | `area?coords?href?shape???img?align?` |
| `height?src?width?usemap???map?name?` |
| 表格標記 | `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**

例16.2顯示了產生圖16.2的代碼
**例16.2** **從一個`web`頁裝載`HTML`窗口的內容**
```
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?`標記所使用的)-24之間。如果該參數沒有指定或是`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`窗口**

**例16.3** **從一個`web`頁載入`HTMLWindow`的內容**
```
#-*- 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**

下例16.4是產生圖16.4的代碼。
例16.4 定義并使用自定義的標記處理器
```
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()`。該方法返回由處理器管理的標記的列表。標記必需是大寫的,并且標記之間以逗號分隔,中間不能有空格,如下所示:
```
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()`的一個示例如下:
```
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`窗口。它的構造函數如下:
```
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`的封裝。
- 活學活用wxPython
- 前言
- 致謝
- 關于本書
- 第一部分
- 第一章 歡迎使用wxPython
- 第二章 給wxPython程序一個堅實的基礎
- 第三章 在事件驅動環境中開發
- 第四章 用PyCrust使得wxPython更易處理
- 第五章 繪制藍圖
- 第六章 使用wxPython基本構件
- 第二部分 基礎wxPython
- 第七章 使用基礎控件
- 第八章 將構件放入窗體中
- 第九章 通過對話框讓用戶選擇
- 第十章 創建和使用wxPython菜單
- 第十一章 使用sizer放置構件
- 第十二章 操作基本圖像
- 第三部分 高級wxPython
- 第十三章 建造列表控件并管理列表項
- 第十四章 網格控件
- 第十五章 樹形控件
- 第十六章 在應用程序中加入HTML
- 第十七章 wxPython的打印構架
- 第十八章 使用wxPython的其他功能