用Python中的wxPython实现最基本的浏览器功能


Posted in Python onApril 14, 2015

通常,大多数应用程序通过保持 HTML 简单来解决大多数浏览器问题 ? 或者说,根据最低共同特性来编写。然而,即便如此,也仍然存在字体和布局的问题,发行新浏览器和升级现有浏览器时,也免不了测试应用程序的痛苦。替代方案 ? 只支持一种浏览器 ? 通常不是一种用户友好的解决方案。

明显的解决方案是在应用程序中嵌入自己的表现 HTML 的窗口构件。当然,从头开始编写这样的窗口构件工作量很大,因此,求助于预先封装的解决方案好象是合理的。

商界有许多选择及几个开放源码软件包。本文将向您显示如何以 Python 作为绑定的语言选择(也支持 C++、Perl 和其它语言)使用作为 wxWindows 软件包一部分分发的 wxHtml 窗口构件。

虽然没有任何 wxPython 经验而熟谙 Python 的开发人员应该能够从头开始,但本文还是假定您具有基本的 wxPython 知识。在本文中,我们将创建一个独立的浏览器应用程序,同时,保持体系结构足够简单以致将浏览器功能迁移到现有的应用程序中是一项简单的任务。
世界上最基本的浏览器

第一步是组装支持使用 wxHtml 窗口构件的应用程序所必需的最少代码。下列代码实现用 wxHtml 窗口构件作为其主窗口内容的基本 wxPython 应用程序。
清单 1. 基本示例浏览器代码

from wxPython.wx import *
from wxPython.html import *
import os,sys
class exHtmlWindow(wxHtmlWindow):
  def __init__(self, parent, id, frame):
   wxHtmlWindow.__init__(self,parent,id)
class exHtmlPanel(wxPanel):
  def __init__(self, parent, id, frame):
   wxPanel.__init__(self,parent,-1)
   self.html = exHtmlWindow(self, -1, frame)
   self.box = wxBoxSizer(wxVERTICAL)
   self.box.Add(self.html, 1, wxGROW)
   self.SetSizer(self.box)
   self.SetAutoLayout(true)
class exFrame (wxFrame):
  def __init__(self, parent, ID, title):
   wxFrame.__init__(self,parent,ID,title,wxDefaultPosition,wxSize(600,750))
   panel = exHtmlPanel(self, -1, self)
class exApp(wxApp):
  def OnInit(self):
   frame = exFrame(NULL, -1, "Example Browser")
   frame.Show(true)
   self.SetTopWindow(frame)
   return true
app = exApp(0)
app.MainLoop()

假定您已正确安装 wxPython,那么在 Python 解释器中运行上述代码将产生一个具有空的白面板(wxHtml 窗口构件)的大窗口。如果出现任何语法错误,请检查空格问题 ? 尤其是如果您将代码剪切粘贴到解释器或编辑器的情况。如果 Python 解释器显示无法导入 wxPython,请检查安装以确保安装正确。

当然,一启动该浏览器,立刻出现的是:我们缺少某些东西 ... 例如装入页面的机制。对于某些应用程序,这一非常基本的设置实际上可能已经够了 — 如果您已知道您要交付什么,那么用户就无需选择自己的页面。简单的更改是向 exHtmlPanel 传递额外的参数,那就是您想访问的页面:
清单 2. 修改 exHtmlPanel 以装入页面

class exHtmlPanel(wxPanel):
+  def __init__(self, parent, id, frame, file):
   wxPanel.__init__(self, parent, -1)
   self.html = exHtmlWindow(self, -1, frame)
   self.box = wxBoxSizer(wxVERTICAL)
   self.box.Add(self.html, 1, wxGROW)
   self.SetSizer(self.box)
   self.SetAutoLayout(true)
+   self.html.LoadPage(file)

为了使之更独立也为了使之更象浏览器,我们将扩展 ttHtmlPanel 类以添加一些执行标准浏览器任务的按钮。当然,如果您实际上是计划构建一个真正的浏览器应用程序,那么在 GUI 设计和可用性方面您可能要考虑的比我们这里做的更多。
清单 3. 修改 ttHtmlPanel 以添加按钮

class ttHtmlPanel(wxPanel):
  def __init__(self, parent, id, frame):
   wxPanel.__init__(self, parent, -1)
   self.frame = frame
   self.cwd = os.path.split(sys.argv[0])[0]
   if not self.cwd:
     self.cwd = os.getcwd
   self.html = ttHtmlWindow(self, -1, self.frame)
   self.box = wxBoxSizer(wxVERTICAL)
   self.box.Add(self.html, 1, wxGROW)
   subbox = wxBoxSizer(wxHORIZONTAL)
   btn = wxButton(self, 1202, "Load File")
   EVT_BUTTON(self, 1202, self.OnLoadFile)
   subbox.Add(btn, 1, wxGROW | wxALL, 2)
   btn = wxButton(self, 1203, "Load Page")
   EVT_BUTTON(self, 1203, self.OnLoadPage)
   subbox.Add(btn, 1, wxGROW | wxALL, 2)
   btn = wxButton(self, 1204, "Back")
   EVT_BUTTON(self, 1204, self.OnBack)
   subbox.Add(btn, 1, wxGROW | wxALL, 2)
   btn = wxButton(self, 1205, "Forward")
   EVT_BUTTON(self, 1205, self.OnForward)
   subbox.Add(btn, 1, wxGROW | wxALL, 2)
   self.box.Add(subbox, 0, wxGROW)
   self.SetSizer(self.box)
   self.SetAutoLayout(true)
  def OnLoadPage(self, event):
   dlg = wxTextEntryDialog(self, 'Location:')
   if dlg.ShowModal() == wxID_OK:
     self.destination = dlg.GetValue()
   dlg.Destroy()
   self.html.LoadPage(self.destination)
  def OnLoadFile(self, event):
   dlg = wxFileDialog(self, wildcard = '*.htm*', style=wxOPEN)
   if dlg.ShowModal():
     path = dlg.GetPath()
     self.html.LoadPage(path)
   dlg.Destroy()
  def OnBack(self, event):
   if not self.html.HistoryBack():
     wxMessageBox("No more items in history!")
  def OnForward(self, event):
   if not self.html.HistoryForward():
     wxMessageBox("No more items in history!")

如果您以前使用过 wxPython 或任何其它 Python 图形工具箱,那么您可以发现我们做的所有事情就是向面板添加另一个容器并将四个按钮置于其中,带有对 exHtmlPanel 类中所添加的方法的回调函数。基础 wxHtml 类巧妙地为我们管理历史,因此, OnBack 和 OnForward 仅仅是对基础方法的调用。

假定读到这些时您已一直在使用 Python 解释器,那么您可能注意到:如果关闭应用程序,它从不将控制返回给控制台。这个问题解决起来很简单,但我们可能应该添加一个菜单栏来提供具有退出选项的文件菜单:
清单 4. 修改 exFrame 以添加带有退出的文件菜单

class exFrame(wxFrame):
  def __init__(self, parent, ID, title):
   wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, wxSize(600,750))
   panel = exHtmlPanel (self, -1, self)
   mnu_file = wxMenu()
   mnu_file.Append(101, "E&xit", "Exit the browser")
   menuBar = wxMenuBar()
   menuBar.Append(mnu_file, "F&ile")
   self.SetMenuBar(menuBar)
   EVT_MENU(self, 101, self.Exit)
  def Exit(self, event):
   self.Close(true)

当我们没有试图将它变为一个真正的浏览器的时候,我们在结尾处发现少了两个添加项:大多数浏览器都有状态栏,并且您可能注意到了没有绘制任何图像。下列对 exApp 、 exFrame 和 exHtmlPanel 的修改添加了一个状态栏以及所有来自 wxPython 的内置图像支持:
清单 5. 添加状态栏及图像支持

class exApp(wxApp):
  def OnInit(self):
+   wxInitAllImageHandlers()
   frame = exFrame(NULL, -1, "Example Browser")
   frame.Show(true)
   self.SetTopWindow(frame)
   return true
class exHtmlPanel(wxPanel):
  def __init__(self, parent, id, frame):
   wxPanel.__init__(self, parent, -1)
   self.frame = frame
   self.cwd = os.path.split(sys.argv[0])[0]
   if not self.cwd:
     self.cwd = os.getcwd
   self.html = exHtmlWindow(self, -1, self.frame)
+   self.html.SetRelatedFrame(self.frame, "%s")
+   self.html.SetRelatedStatusBar(0)
...
class exFrame(wxFrame):
  def __init__(self, parent, ID, title):
   wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, wxSize(600,750))
   panel = exHtmlPanel (self, -1, self)
+   self.CreateStatusBar()
+   self.SetStatusText("Default status bar")
...

现在,基本浏览器的功能应该齐全了。wxPython 的高级特性允许您创建自己的标记,可以通过定制代码来处理这些标记以执行您选择的任何操作。对您自己的可定制嵌入式浏览器的控制为增强的报表生成及联机帮助提供了无限的可能性。

这些代码本身就可以轻易为任意数目的应用程序提供基础,并且 ? 没有理由将您限制在仅仅提供联机帮助上。请自由使用这些类,看看能让它们发生什么有趣的行为。:-)

Python 相关文章推荐
Python中Iterator迭代器的使用杂谈
Jun 20 Python
安装Python和pygame及相应的环境变量配置(图文教程)
Jun 04 Python
Python实现全排列的打印
Aug 18 Python
将python文件打包成EXE应用程序的方法
May 22 Python
django一对多模型以及如何在前端实现详解
Jul 24 Python
python 实现手机自动拨打电话的方法(通话压力测试)
Aug 08 Python
python中的函数递归和迭代原理解析
Nov 14 Python
python3 实现函数写文件路径的正确方法
Nov 27 Python
使用python 将图片复制到系统剪贴中
Dec 13 Python
python 的topk算法实例
Apr 02 Python
python使用建议与技巧分享(二)
Aug 17 Python
pytorch Dataset,DataLoader产生自定义的训练数据案例
Mar 03 Python
Python中SOAP项目的介绍及其在web开发中的应用
Apr 14 #Python
Python中的XML库4Suite Server的介绍
Apr 14 #Python
Python pickle模块用法实例
Apr 14 #Python
使用Python的PEAK来适配协议的教程
Apr 14 #Python
Python全局变量操作详解
Apr 14 #Python
Python and、or以及and-or语法总结
Apr 14 #Python
Python线程的两种编程方式
Apr 14 #Python
You might like
php Notice: Undefined index 错误提示解决方法
2010/08/29 PHP
php数组函数序列之end() - 移动数组内部指针到最后一个元素,并返回该元素的值
2011/10/31 PHP
PHP把数字转成人民币大写的函数分享
2014/06/30 PHP
一个经典实用的PHP图像处理类分享
2014/11/18 PHP
jquery提示 "object expected"的解决方法
2009/12/13 Javascript
web网页按比例显示图片实现原理及js代码
2013/08/09 Javascript
5款JavaScript代码压缩工具推荐
2014/07/07 Javascript
JS实现点击按钮自动增加一个单元格的方法
2015/03/09 Javascript
JS实现把鼠标放到链接上出现滚动文字的方法
2016/04/06 Javascript
关于JavaScript数组你所不知道的3件事
2016/08/24 Javascript
AngularJs  Understanding Angular Templates
2016/09/02 Javascript
AngularJS表格添加序号的方法
2017/03/03 Javascript
使用 Node.js 对文本内容分词和关键词抽取
2017/05/27 Javascript
jQuery实现选中行变色效果(实例讲解)
2017/07/06 jQuery
JS异步函数队列功能实例分析
2017/11/28 Javascript
Three.js中矩阵和向量的使用教程
2019/03/19 Javascript
taro开发微信小程序的实践
2019/05/21 Javascript
javascript实现点亮灯泡特效示例
2019/10/15 Javascript
[08:53]DOTA2每周TOP10 精彩击杀集锦vol.9
2014/06/26 DOTA
[01:19:54]DOTA2上海特级锦标赛主赛事日 - 2 败者组第二轮#1Alliance VS EHOME
2016/03/03 DOTA
Windows系统下安装Python的SSH模块教程
2015/02/05 Python
go语言计算两个时间的时间差方法
2015/03/13 Python
Django 路由控制的实现代码
2018/11/08 Python
pyqt5移动鼠标显示坐标的方法
2019/06/21 Python
python调用自定义函数的实例操作
2019/06/26 Python
Python实现RGB与HSI颜色空间的互换方式
2019/11/27 Python
解决pyecharts运行后产生的html文件用浏览器打开空白
2020/03/11 Python
html5 利用重力感应实现摇一摇换颜色可用来做抽奖等等
2014/05/07 HTML / CSS
中科前程Java笔试题
2016/11/20 面试题
演讲稿怎么写
2014/01/07 职场文书
校园文明倡议书
2014/05/16 职场文书
计划生育证明书写要求
2014/09/17 职场文书
2014乡镇干部对照检查材料思想汇报
2014/09/26 职场文书
2015年国庆节慰问信
2015/03/23 职场文书
上诉状格式
2015/05/23 职场文书
电影建国大业观后感
2015/06/01 职场文书