2023年6月24日 星期六

Python 學習筆記 : 如何在 Tkinter 中使用 HTML

今天在 Youtube 看到下面這個教學影片, 介紹如何利用第三方套件 tkhtmlview 在 Tkiner 視窗中使用 HTML + CSS 語法來美化視窗內容與連結網站 :





我覺得這功能很實用, 那就依樣畫葫蘆來測試一番唄!

首先用 pip install 來安裝 tkhtmlview, 注意, 要用系統管理員身分開啟命令提示字元視窗 :




Microsoft Windows [版本 10.0.19045.3086]
(c) Microsoft Corporation. 著作權所有,並保留一切權利。

C:\WINDOWS\system32>pip install tkhtmlview    
Collecting tkhtmlview
  Using cached tkhtmlview-0.2.0-py3-none-any.whl (10 kB)
Requirement already satisfied: Pillow<10.0.0,>=9.4.0 in c:\python311\lib\site-packages (from tkhtmlview) (9.5.0)
Collecting requests<3.0.0,>=2.28.2 (from tkhtmlview)
  Using cached requests-2.31.0-py3-none-any.whl (62 kB)
Requirement already satisfied: charset-normalizer<4,>=2 in c:\python311\lib\site-packages (from requests<3.0.0,>=2.28.2->tkhtmlview) (3.1.0)
Requirement already satisfied: idna<4,>=2.5 in c:\python311\lib\site-packages (from requests<3.0.0,>=2.28.2->tkhtmlview) (3.4)
Requirement already satisfied: urllib3<3,>=1.21.1 in c:\python311\lib\site-packages (from requests<3.0.0,>=2.28.2->tkhtmlview) (2.0.3)
Collecting certifi>=2017.4.17 (from requests<3.0.0,>=2.28.2->tkhtmlview)
  Using cached certifi-2023.5.7-py3-none-any.whl (156 kB)
Installing collected packages: certifi, requests, tkhtmlview
Successfully installed certifi-2023.5.7 requests-2.31.0 tkhtmlview-0.2.0

C:\WINDOWS\system32>

如果沒有用系統管理員身分開啟命令提示字元視窗, 則安裝時可能會出現無法寫入錯誤而失敗 : 

Installing collected packages: urllib3, Pillow, idna, charset-normalizer, certifi, requests, tkhtmlview
  WARNING: Failed to write executable - trying to use .deleteme logic
ERROR: Could not install packages due to an OSError: [WinError 2] 系統找不到指定的檔案。: 'C:\\Python311\\Scripts\\normalizer.exe' -> 'C:\\Python311\\Scripts\\normalizer.exe.deleteme'

目前 tkhtmlview 支援的 HTML 標籤尚未涵蓋全部 HTML5, 但常用的標籤例如 H1~H6, A, P 等都可使用, 參考教學文件 :



1. 文字效果 :  

下面範例使用 Label 元件來測試 H1~H6 的文字效果 : 


測試 1 : 在 HTMLLabel 元件上顯示 HTML 的 H1~H6 文字效果 

import tkinter as tk
from tkhtmlview import HTMLLabel

root=tk.Tk()
root.geometry('600x400')
html_1='<h1 style="color: red; text-align: center"> Hello World </h1>'
label_1=HTMLLabel(root, html=html_1)
label_1.pack()
label_1.fit_height()
html_2='<h2 style="color: green; text-align: center"> Hello World </h2>'
label_2=HTMLLabel(root, html=html_2)
label_2.pack()
label_2.fit_height()
html_3='<h3 style="color: blue; text-align: center"> Hello World </h3>'
label_3=HTMLLabel(root, html=html_3)
label_3.pack()
label_3.fit_height()
html_4='<h4 style="color: pink; text-align: center"> Hello World </h4>'
label_4=HTMLLabel(root, html=html_4)
label_4.pack()
label_4.fit_height()
html_5='<h5 style="color: cyan; text-align: center"> Hello World </h5>'
label_5=HTMLLabel(root, html=html_5)
label_5.pack()
label_5.fit_height()
html_6='<h6 style="color: black; text-align: center"> Hello World </h6>'
label_6=HTMLLabel(root, html=html_6)
label_6.pack()
label_6.fit_height()
root.mainloop()

此例使用 H1~H6 在 HTMLLabel 元件上顯示 6 種不同大小的標題, 注意, 連續用 pack() 將 HTMLLabel 放置到 root 容器時因為預設高度較大,  後面的元件會被推到是窗外而看不到, 因此必須呼叫 HTMLLabel 物件的 fit_height() 方法來調適元件高度, 結果如下 : 




HTMLLabel 已支援多國語言 (即多位元組字元例如中文) , 若將上面程式中的 "Hello World" 改成 "你是在說哈囉嗎?" 結果如下 :




2. 顯示超連結 :  

下面範例測試超連結 A 標籤 :


測試 2 : 在 HTMLLabel 元件上顯示超連結

import tkinter as tk
from tkhtmlview import HTMLLabel

root=tk.Tk()
root.geometry('400x200')
html_1='<a href="https://tw.yahoo.com/" target="_blank">雅虎奇摩</a>'
label_1=HTMLLabel(root, html=html_1)
label_1.pack(padx=5, pady=5)
label_1.fit_height()
html_2='<a href="https://www.google.com.tw/" target="_blank">Google</a>'
label_2=HTMLLabel(root, html=html_2)
label_2.pack(padx=5, pady=5)
label_2.fit_height()
html_3='<a href="https://chateverywhere.app/zh" target="_blank">Chat Everwhere</a>'
label_3=HTMLLabel(root, html=html_3)
label_3.pack(padx=5, pady=5)
label_3.fit_height()
root.mainloop()

此例在 HTMLLabel 元件上顯示 Yahoo, Google, 與 Chat Everywhere 的網址超連結, 由於使用了 target='_blank' 屬性, 因此點擊超連結會在瀏覽器中開啟新分頁來顯示網頁, 結果如下 :



 
這個功能在 Tkinter GUI 視窗需要連結網站時非常好用. 


3. 顯示清單 :  

tkhtmlview 支援 OL, UL, LI 等清單標籤, 例如 :

測試 3 : 在 HTMLLabel 元件上顯示清單超連結

import tkinter as tk
from tkhtmlview import HTMLLabel

root=tk.Tk()
root.geometry('400x400')
html='''
<ol>
  <li><a href="https://tw.yahoo.com/" target="_blank">雅虎奇摩</a></li>
  <li><a href="https://www.google.com.tw/" target="_blank">Google</a></li>
  <li><a href="https://chateverywhere.app/zh" target="_blank">Chat Everwhere</a></li>
</ol>
<ul>
  <li><a href="https://tw.yahoo.com/" target="_blank">雅虎奇摩</a></li>
  <li><a href="https://www.google.com.tw/" target="_blank">Google</a></li>
  <li><a href="https://chateverywhere.app/zh" target="_blank">Chat Everwhere</a></li>
</ul>
'''
label=HTMLLabel(root, html=html)
label.pack(padx=5, pady=5)
label.fit_height()
root.mainloop()

此例分別用 ol 與 ul 元素來呈現編號與無編號清單, 結果如下 :




4. 顯示圖片 :  

接下來測試 IMG 標籤的圖片顯示功能, 主要是透過其 src 屬性來指定圖片來源, 可以是網址或圖片在本機中的相對路徑, 下面是顯示本機程式工作目錄例如 : 


測試 4 : 在 HTMLLabel 元件上顯示圖片

import tkinter as tk
from tkhtmlview import HTMLLabel

root=tk.Tk()
root.geometry('800x700')
html_1='<img src="orchid.jpg">'
label_1=HTMLLabel(root, html=html_1)
label_1.pack(padx=5, pady=5, anchor=tk.CENTER)
label_1.fit_height()
label_2=HTMLLabel(root, html=html_2)
label_2.pack(padx=125, pady=5)
label_2.fit_height()
root.mainloop()

此例在視窗中放置兩張圖片, 第一張圖片來源為本機程式目錄下的 orchid.jpg; 第二張是放在 GitHub 的同一張圖片, 分別使用 anchor 與 padx 參數來控制圖片置中, 結果如下 :




可見 anchor 參數對於 HTMLLabel 上的圖片沒有作用, 只能用 padx 調整其水平位置. 另外, 用來給圖片加上文字標題的 figure 標籤目前也尚未支援. 


5. 顯示表格 (支援度不全) :  

tkhtmlview 對表格的支援還不足 (雖然 colspan 合併儲存格似乎可用), 連 border 都無法顯示, 例如下列範例 :


測試 5 : 在 HTMLLabel 元件上顯示表格

import tkinter as tk
from tkhtmlview import HTMLLabel

root=tk.Tk()
root.geometry('800x400')
html='''
    <table border=1>
      <caption><strong>表格標題</strong></caption>
      <tr>
        <th>第1欄</th>
        <th>第2欄</th>
        <th>第3欄</th>
      </tr>
      <tr>
        <td>第1列第1欄</td>
        <td>第1列第2欄</td>
        <td>第1列第3欄</td>
      </tr>
      <tr>
        <td>第2列第1欄</td>
        <td>第2列第2欄</td>
        <td>第2列第3欄</td>
      </tr>
      <tr>
        <td colspan="3">合併儲存格</td>
      </tr>
    </table>'''
label=HTMLLabel(root, html=html)
label.pack(padx=5, pady=5)
label.fit_height()
root.mainloop()

此處用 border=1 設定表格邊框但無作用, 結果如下 : 




希望未來 tkhtmlview 可以完善對 TABLE 的支援. 


6. 用 HTMLText 與 HTMLRender 顯示 HTML 檔內容 :  

除了用 HTMLLabel 元件直接顯示 HTML 碼外, tkhtmlview 也可以透過 HTMLRender 物件讀取外部 HTML 檔顯示於視窗中, 例如下面這個網頁 index.htm :


測試 6 : 用 HTMLRender 與 HTMLText 讀取 HTML 檔

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
  </head>
  <body>
    <h2>Hello World!</h2>
    <img src="orchid.jpg">
  </body>
</html>

將其存放於程式工作目錄下, 然後執行下列程式碼 :

import tkinter as tk
from tkhtmlview import HTMLText, RenderHTML

root=tk.Tk()
root.geometry('800x500')
label=HTMLText(root, html=RenderHTML('index.htm'))
label.pack(padx=5, pady=5)
label.fit_height()
root.mainloop()

結果如下 :




但目前 HTMLRender 物件僅限於顯示英文資料, 無法像 HTMLLabel 那樣顯示中文內容, 例如若若將上面 index.htm 檔的 H2 標籤內容從 "Hello World!" 改為 "你是在說哈囉嗎?" 時就會顯示如下錯誤 : 

UnicodeDecodeError: 'cp950' codec can't decode byte 0xa0 in position 142: illegal multibyte sequence

可能 HTMLRender 物件尚未支援 Unicode. 

沒有留言 :