什么是favicon? 所谓favicon,即Favorites Icon的缩写,顾名思义,便是其可以让浏览器的收藏夹中除显示相应的标题外,还以图标的方式区别不同的网站。
用IE6的时候一直都没有没有这个概念,直到用了Firefox,才发现,每个Tab上面都有个图标,像网易,就是一个易字,当时也觉得就是在某个地方设置了一下图标的地址就可以这样显示了,但一直都不知道具体是怎么实现的。
昨天看Google App Engine里面的数据统计时,发现一个对网站根目录的favicon.ico文件的请求,看文件名就感觉这个文件就是用来做图标用的,当即google了一把,原来如果把这个图标放在网站的根目录下,名字就叫favicon.ico的话,浏览器会默认请求这个文件,并把它做为图标文件,当然IE6就不用说了,没效果的。
问题又来了,到哪去找这个Favicon呢,Google一下,发现一个在线制作的网站http://www.html-kit.com/favicon/,,把你的图片上传上去,就可以自动生成出对应的图标,而且还是动态的,很好。就随便找了个图片,把博客的图标换了,呵呵。具体效果嘛,自己看咯。
最近在用wxPython做一个小工具,给公司内部用,Python的确很简洁,Java Swing比wxPython可是要麻烦多了,不过还是碰到一些问题,都是一说就明白的问题,只是我写这个工具也是东拼西凑的找的别人的代码,好写代码而不求胜解,才会碰到这些问题了。如下:
- wxPython关于RadioBox事件处理的Bug
- python格式化当前时间
- Example 8.12. locals 是只读的,globals 不是
- repr函数
- wx.Sizer怎样才有Padding效果
创建基本的wxPython程序
主题:
- 创建一个基本的wxPython程序
- 将这个程序打造成一个简单的文本编辑器
本节将介绍如何使用wxPython构建一个小型的文本编辑器。通过这个看似复杂的任务你将会体验到wxPython有多方便和简单。
概述
每当大家提前GUI编程的时候,总是会牵扯到窗体,菜单,鼠标,图标等等。或许你的第一感觉wx.Windows就对应一个显示在屏幕上的窗口,但你错了,在wxPython中,wx.Window表示任意可以显示在屏幕上的东西的对象,wx.Window这个类是所有屏幕上可见的对象的基类,诸如输入框,下拉列表都是由它派生而来。屏幕上的可见对象都有一些共同的属性和行为,比如位置,尺寸,是否可见,是否处于输入焦点等等,这些在wx.Window里面都有定义。 所以如果你要找一个类来表示窗口,就应该用继承自wx.Window的wx.Frame而不是wx.Window. wx.Frame实现了所有与屏幕相关的行为和属性(当然如果wx.Frame位于MDI中则另当别论) .要创建一个窗体,可以用wx.Frame,也可以用其子类如wx.Dialog,但不能再按照思维定势去想wx.Window了。
一个简单的例子
添加编辑控件
要编写一个文本编辑器,首先当然需要一个编辑控件,如下:import wx class MainWindow(wx.Frame): """ We simply derive a new class of Frame. """ def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(200,100)) self.control = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE) self.Show(True) app = wx.PySimpleApp() frame=MainWindow(None, wx.ID_ANY, 'Small editor') app.MainLoop()
(需要注意的是这里我们定义了一个继承自wx.Frame的类,在类的初始化方法最后调用了父类的show方法,这也就不需要在额外调用show方法。) 如你所见,这段代码还是非常简洁, 我们所做的只是继承了一个wxFrame然后覆写了它的构造函数,在构造函数中新建一个简单的文本编辑框控件,就这样,就有了如下的效果图:
添加菜单栏
多数你所见到的GUI程序都有一个菜单栏和一个状态栏,下面就开始添加这两个组件:import wx ID_ABOUT=101 ID_EXIT=110 class MainWindow(wx.Frame): def __init__(self,parent,id,title): wx.Frame.__init__(self,parent,wx.ID_ANY, title, size = (300,200)) self.control = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE) self.CreateStatusBar() # A Statusbar in the bottom of the window # Setting up the menu. filemenu= wx.Menu() filemenu.Append(ID_ABOUT, "&About"," Information about this program") filemenu.AppendSeparator() filemenu.Append(ID_EXIT,"E&xit"," Terminate the program") # Creating the menubar. menuBar = wx.MenuBar() menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content. self.Show(True) app = wx.PySimpleApp() frame = MainWindow(None, -1, "Sample editor") app.MainLoop()
- 菜单有了,但是点击菜单却没有任何反应,下面添加事件处理:
实战事件处理
- 对事件做处理就是人们常说的事件处理,wxPython的一大特色就是在事件处理上有极高的灵活性。接下来我们将添加一下实战的代码,这些代码或许已经超越了基于前面一章的理解能力,所以对他们的讨论将放到后续章节。 简单的说,一个事件就是一条发送到wxPython得消息告知有什么事情发生了,需要处理了 [6].通常来说,你所要做的就是把这个事件连接到一个特定的方法,让这个方法去处理,仅仅需要调用
EVT_*. (Also see Avoiding EVT_MENU.) 方法,如下:
EVT_MENU(self, ID_ABOUT, self.OnAbout)
这个函数的作用在将对菜单ID 为ID_ABOUT的事件都扔给self.OnAbout去处理。self.OnAbout函数可能就像下面这个样子:
def OnAbout(self, event)
OnAbout的参数是event对象,它所做的就是在事件发生时: - 跳过这个事件, 让事件在事件处理周期里转到另外的处理程序。
或者处理这个事件,事件消息在被程序处理后就不会在事件处理周期继续传播。
让我们看看现在的程序:
import os
import wx
ID_ABOUT=101
ID_EXIT=110
class MainWindow(wx.Frame):
def __init__(self,parent,id,title):
wx.Frame.__init__(self,parent,wx.ID_ANY, title, size = (200,100))
self.control = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE)
self.CreateStatusBar() # A StatusBar in the bottom of the window
# Setting up the menu.
filemenu= wx.Menu()
filemenu.Append(ID_ABOUT, "&About"," Information about this program")
filemenu.AppendSeparator()
filemenu.Append(ID_EXIT,"E&xit"," Terminate the program")
# Creating the menubar.
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content.
wx.EVT_MENU(self, ID_ABOUT, self.OnAbout) # attach the menu-event ID_ABOUT to the
# method self.OnAbout
wx.EVT_MENU(self, ID_EXIT, self.OnExit) # attach the menu-event ID_EXIT to the
# method self.OnExit
self.Show(True)
def OnAbout(self,e):
d= wx.MessageDialog( self, " A sample editor \n"
" in wxPython","About Sample Editor", wx.OK)
# Create a message dialog box
d.ShowModal() # Shows it
d.Destroy() # finally destroy it when finished.
def OnExit(self,e):
self.Close(True) # Close the frame.
app = wx.PySimpleApp()
frame = MainWindow(None, -1, "Sample editor")
app.MainLoop()
更多有趣的东西
- 如果一个文本编辑器不能保存用户的输入,不能打开一个已有的文档,那这个编辑器可以算一个废品。下面我们加上打开已有文档的代码,通过一个系统的文件浏览对话框打开文件:
def OnOpen(self,e): """ Open a file""" self.dirname = '' dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN) if dlg.ShowModal() == wx.ID_OK: self.filename=dlg.GetFilename() self.dirname=dlg.GetDirectory() f=open(os.path.join(self.dirname,self.filename),'r') self.control.SetValue(f.read()) f.close() dlg.Destroy()- 上面的代码其实只有简单的三个步骤:
- 首先,创建一个系统的文件浏览对话框
然后,调用ShowModal方法,弹出一个模态对话框,等待用户按下OK按钮或者Cancel按钮。
- 最后,得到用户所选择的文件夹和文件名,调用destroy方法然后销毁这个窗口
可能的扩展
我们的编辑器还远远不能算是一个专业的编辑器,还有更多的技术可以用到这个编辑器上让它更专业,诸如:- 拖拽操作.
- MDI (多窗口窗体)
- Tab view/multiple files (通过标签视图显示更多文件)
- Find/Replace dialog (查找,替换功能)
Print dialog (打印功能)
- Macro-commands in python ( 在编辑器里面编写Python代码并运行)
- etc ...
- 上面的代码其实只有简单的三个步骤:
第一个wxPython程序: "Hello, World" Hello World不知道是谁发明的,不过它已经成为所有程序教程的典范了,呵呵,几乎所有的Hello World都尽量做到简洁明了,wxPython也不例外,试看如下代码:
import wx app = wx.PySimpleApp() frame = wx.Frame(None, wx.ID_ANY, "Hello World") frame.Show(True) app.MainLoop()
- 下面就是在Windows上运行的结果:

代码很短很强大,首先导入wx 模块,然后初始化一个wx.PySimpleApp对象,接下来是窗口对象wx.Frame,一个有标题栏,最小最大关闭按钮的窗口就创建好了[4],调用show方法让这个窗口显示出来。最后一句MainLoop作用则是使整个程序进入事件循环,学过Swing的可能会觉得这句话似乎有点多余,个人感觉可能是由于与平台底层GUI控件的兼容,诸如MFC之类的GUI的事件其实就是一个无限循环,无限的去循环检查有没有新的事件产生,并调用相应的处理函数。回到wx.Frame创建这里,这应该是这几句Code中看起来稍微复杂的一句了:
- wxPython里面的大多数控件在构造函数里面都有类似的参数构成:一个Parent 对象作为第一个参数,然后是控件的Id作为第二个参数,就像你所看到的,可以使用None或者wx.ID_ANY来做默认值(表示这个Frame对象没有父对象,只需要一个系统自定义的Id)
Reference:wxPython Getting Start
The McMillan Installer
The mcillian installer development is discontinued.
mirror: http://davidf.sjsoft.com/mirrors/mcmillan-inc/installer_dnld.html
Continued development(not tested yet): http://pyinstaller.hpcf.upr.edu/cgi-bin/trac.cgi
This works on Win32. Unzip the Installer in a directory of your choice, and cd there.
Configure the Installer by running:
python Configure.py
Python must be in your PATH for this to work, if it's not, type from the command prompt:
PATH=%PATH%;c:\python23
where c:\python23 must be replaced with the root of your python installation. Then, assuming the source code is app.py (placed in c:\source):
python Makespec.py --upx --onefile --noconsole c:\source\app.py python Build.py app\app.spec
Replace 'app' everywhere above with your application name.
You will end up with app\app.exe under the Installer dir.This is a one file .exe containing all the application. If you don't want a one-file build, suppress the option --onefile above. If you don't have upx installed (or don't want to use it), suppress the option --upx above. The option --noconsole is needed to produce a windows gui application, instead of a console one (so the command shell won't pop up when you run the application).
[ More details to be written... ]
py2exe
http://py2exe.sourceforge.net/
Create a setup.py script for using py2exe to generating the exe file. (The script to compile in this case is wxTail.py):
# setup.py from distutils.core import setup import py2exe setup(name="wxTail",scripts=["wxTail.py"],)
Sample of the win32 command for running py2exe:
python setup.py py2exe
If you use the unicode version of wxpython you have to manually include the file unicows.dll form your python installation directory. Otherwise the application will crash at least on Windows 98.
[ More details to be written... ]
Installer
To turn your binary and accompanying library files into a Windows installer you can use:
innosetup from http://www.jrsoftware.org/isinfo.php
NSIS from http://nsis.sourceforge.net/ (and HM-NSIS-Edit http://hmne.sourceforge.net/ for the wizard).
Issues
When using py2exe with pythoncom (or with wxPython's ActiveXWrapper which uses pythoncom) py2exe has trouble finding the code for the generated COM wrapper modules and you end up with import errors. Here is the solution, which was sent to the mail list by Clark C. Evans:
- When pythonwin is called to create an Python binding for a COM component, it generates a new python class and puts this class in the gen_py directory (which magically appears). I believe the problem is that the py2exe program doesn't expand the Python path to include the deployment directory, otherwise this directory would be found... To work-aroud this problem, simply use the makepy program to generate a python wrapper for the activeX component you have (for example, IE Explorer). Then, rename this module file to something more palatable (like ie.py). Then, instead of using "ensure module" simply import the re-named file -- the imported module is the class module. For example, to make the IE ActiveX demo work...
- Generate ie.py using makepy using the "-o" option
- Replace the "ensure module" stuff in the demo code with...
from wxPython.wx import * if wxPlatform == '__WXMSW__': from wxPython.lib.activexwrapper import MakeActiveXClass import ie5 browserModule = ie5
Another work-around if you run into issues running py2exe compiled programs with the ActiveXWrapper controls (specifically the PDF Window control in wxPython 2.8) is to add a typelibs entry to the options argument in your setup.py file. See the sample setup.py below for an example.
from distutils.core import setup import py2exe manifest = """""" """ installs manifest and icon into the .exe but icon is still needed as we open it for the window icon (not just the .exe) changelog and logo are included in dist """ setup( options = {'py2exe': { 'compressed': 1, 'optimize': 2, 'bundle_files': 3, 'typelibs' : [("{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}", 0, 1, 1)], } }, windows = [ { "script": "myprogram.py", "icon_resources": [(1, "program.ico")], "other_resources": [(24,1,manifest)], } ], data_files=["help.txt", "program.ico", "program.ini"], ) myProgram
Basically the typelibs line ensures py2exe picks up the dynamically imported module in pdfwin.py that is included with the Windows wxPython distribution.
_browserModule = win32com.client.gencache.EnsureModule(
"{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}", 0, 1, 1)
On Linux
Summary
A binary distribution of a Python/wxPython program on Linux has these advantages:
- There is no need for the user to have Python, wxPython or any other extensions you use installed
- The versions of Python, wxPython and extensions are the ones you ship, not any they may already have installed. That means you don't need to worry about users using different versions of the extensions with your software.
Prerequisites
cx_Freeze
cx_Freeze turns a Python script into a binary file and any referenced binary modules.
Download cx_Freeze from http://starship.python.net/crew/atuining/ I recommend getting the binary distribution. If you extract it in /opt, then it will end up installed in /opt/cx_Freeze-2.1/ (this location is assumed through the rest of this document).
Also note that while cx_Freeze is free software, you do need to abide by the license agreement on the same page.
chrpath
The wxPython shared libraries have some pathnames hardcoded into them (also known as an rpath). chrpath removes this hardcoded path for where other shared libraries are searched.
Download chrpath from http://freshmeat.net/projects/chrpath/ By default it installs in /usr/local/bin which should be on your path.
Making your binary distribution
Make an output directory
Create a clean directory for the resulting files. I make one named dist.
Run cxFreeze
Assuming the main entrypoint to your program is example.py, this is what you run:
$ cxpath=/opt/cx_Freeze-2.1 $ env PATH=$cxpath:$PATH FreezePython --install-dir=dist --base-binary=$cxpath/ConsoleSetLibPathBase example.py
Everything should end up in the dist subdirectory, and the main binary will be named dist/example
Run chrpath
You now need to remove hard coded path information from the wxPython and other shared libraries. I use this shell script:
for i in *.so
do
if chrpath $i 2>/dev/null | grep = >/dev/null
then
echo "Fixing $i"
chrpath -d $i
fi
doneChange into the dist subdirectory and run the script. It should fix at least wxPython.wxc.so, and same other wx-controls you may use (eg calendar).
Package it up
You can now just tar up the dist subdirectory. Users can place the contents anywhere they choose on the filesystem, and call the main executable for everything to work.
I normally put all the files in a subdirectory of /usr/lib (for example: /usr/lib/example-1.0 and then put a wrapper script in /usr/bin that execs the binary in /usr/lib/example-1.0.
On Mac
py2app
http://undefined.org/python/py2app.html
BundleBuilder.py
The Python included with Mac OS X contains a tool called BundleBuilder.py which lets you package Python scripts into ".app" bundles that can be distributed on computers even without Python installed. (Although OS X 10.3 contains a complete implementation of Python.) Documentation on this tool (including an example of a wxPython app building script) can be found here:
http://www.python.org/cgi-bin/moinmoin/BundleBuilder
The important part to note is that you must manually include the wxWindows dynamic libraries at this point. See the lines in the example script containing myapp.libs.append to see how to do so. Hopefully a more targeted and detailed tutorial will be forthcoming. =) In the meantime, please feel free to post your questions to either wxPython-mac@lists.sourceforge.net or pythonmac-sig@python.org .
Examples
BitPim
The bitpim project produces Windows and Linux binary installers that don't require the user to have Python or wxPython installed (or even have to know what they are!)
Code is available in http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/bitpim/bitpim/
makedist.py does the actual build an invokes the various other tools. bitpim.iss is the innosetup file. p2econfig.py is the py2exe file.
原文地址 http://wiki.wxpython.org/index.cgi/CreatingStandaloneExecutables
