# 第一章 歡迎使用wxPython
1. [歡迎使用wxPython](#A.2BayKPzk9.2FdSg-wxPython)
1. [開始wxPython](#A.2BXwBZyw-wxPython)
2. [創建最小的空的wxPython程序](#A.2BUhte.2BmcAXA92hHp6doQ-wxPython.2Begtejw-)
1. [導入wxPython](#A.2BW.2FxRZQ-wxPython)
2. [使用應用程序和框架工作](#A.2BT391KF6UdSh6C16PVIxoRme2XeVPXA-)
3. [擴展這個最小的空的wxPython程序](#A.2BYmlcVY.2FZTipnAFwPdoR6enaE-wxPython.2Begtejw-)
4. [創建最終的hello.py程序](#A.2BUhte.2BmcAfsh2hA-hello.py.2Begtejw-)
下面是一個例子,它創建了一個有一個文本框的窗口用來顯示鼠標的位置。
```
#!/bin/env python
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "My Frame", size=(300, 300))
panel = wx.Panel(self, -1)
panel.Bind(wx.EVT_MOTION, self.OnMove)
wx.StaticText(panel, -1, "Pos:", pos=(10, 12))
self.posCtrl = wx.TextCtrl(panel, -1, "", pos=(40, 10))
def OnMove(self, event):
pos = event.GetPosition()
self.posCtrl.SetValue("%s, %s" % (pos.x, pos.y))
if __name__ == '__main__':
app = wx.PySimpleApp()
frame = MyFrame()
frame.Show(True)
app.MainLoop()
```
圖示如下:

漂亮的界面是一個`GUI`程序必不可少的一部分,`wxPython`可以做到這一點,加之`Python`強大的功能和簡潔的語法,使用得它在`Python`的`gui`中成為一種主流。
## 開始wxPython
首先我們創建一個顯示一個圖像的文件。這將分三步:
1. 首先創建一個空的最小的可以工作的`wxPthon`程序
2. 組織和細化
3. 顯示`wxPython`的`logo`
圖示如下:

## 創建最小的空的wxPython程序
我們創建一個名為`bare.py`的程序并鍵入以下代碼:
```
import wx #1
class App(wx.App):#2
def OnInit(self): #3
frame = wx.Frame(parent=None, title='Bare')
frame.Show()
return True
app = App() #4
app.MainLoop() #5
```
上面的代碼運行的結果如下:

上面的代碼的任何一行都不能少,否則將不能工作。這個基本的`wxPython`程序說明了開發任一`wxPython`程序所必須的五個基本步驟:
1. 導入必須的`wxPython`包
2. 子類化`wxPython`應用程序類
3. 定義一個應用程序的初始化方法
4. 創建一個應用程序類的實例
5. 進入這個應用程序的主事件循環
下面讓我們看看這個最小的空的程序是如何一步一步實現的。
### 導入wxPython
你需要做的第一件事就是導入這個主要的`wxPython`包,這個包名為`wx:`
```
import wx
```
一旦這個包被導入,你就可以引用`wxPython`的類、函數和常量(它們以`wx`為前綴),如下所示:
```
class App(wx.App):
```
注意:老的引入方式仍然被支持,你可能會遇到用這種老的引入方式的代碼。因此我們將會簡短地說明這種老的方式及為什么要改變它。老的包的名字是`wxPython`,它包含了一個內在的名為`wx`模塊。那時,通常有兩種導入必要的代碼的方法,一種就是從`wxPython`包中導入`wx`模塊:`from` `wxPython` `import` `wx`;另一種就是直接從`wx`模塊中導入所有的東西:`from` `wxPython.wx` `import` *。這兩種方法都有嚴重的缺點。這第二種方法`Python`中是不建議使用的,這因為可能導致名字空間沖突,而老的`wx`模塊通過在其屬性前加一個`wx`前綴避免了這個問題。盡管使用這個安全防范,但是`import`*仍然有可能導致問題,但是許多`wxPython`程序員喜歡這種類型,并且你將在老的代碼中經常看到這種用法。這種風格的壞處是類名以小寫字母開頭,而大多數`wxPython`方法以大寫字母開頭,這和通常的`Python`編寫程序的習慣相反。
然而如果你試圖避免由于使用`import`*導致的名字空間膨脹,而使用`from` `wxPython` `import` `wx`。那么你就不得不為每個類、函數、常數名鍵入兩次`wx`,一次是作為包的前綴,另一次是作為通常的前綴,例如`wx.wxWindow`。
對于導入順序需要注意的是:你從`wxPython`導入其它東西之前必須先導入`wx`。通常情況下,`Python`中的模塊導入順序無關。但是`wxPython`中的不同,它是一個復雜的模塊。當你第一次導入`wx`模塊時,`wxPython`要對別的`wxPython`模塊執行一些初始化工作。例如`wxPython`中的一些子包,如`xrc`模塊,它在`wx`模塊導入之前不能夠正確的工作,我們必須按下面順序導入:
```
import wx
from wx import xrc
```
以上的導入順序只針對`wxPython`的模塊,`Python`的模塊導入順序沒關系。例如:
```
import sys
import wx
import os
from wx import xrc
import urllib
```
### 使用應用程序和框架工作
一旦你導入了`wx`模塊,你就能夠創建你的應用程序(`application`)對象和框架(`frame`)對象。每個`wxPython`程序必須有一個`application`對象和至少一個`frame`對象。`application`對象必須是`wx.App`的一個實例或你在`OnInit()`方法中定義的一個子類的一個實例。當你的應用程序啟動的時候,`OnInit()`方法將被`wx.App`父類調用。
**子類化`wxPython`** **`application`類**
下面的代碼演示了如何定義我們的`wx.App`的子類:
```
class MyApp(wx.App):
def OnInit(self):
frame = wx.Frame(parent=None, id=-1, title="Bare")
frame.Show()
return True
```
上面我們定義了一個名為`MyApp`的子類。我們通常在`OnInit()`方法中創建`frame`對象。上面的`wx.Frame`接受三個參數,僅第一個是必須的,其余的都有默認值。 調用`Show()`方法使`frame`可見,否則不可見。我們可以通過給`Show()`一個布爾值參數來設定`frame`的可見性:
```
frame.Show(False) # 使框架不可見.
frame.Show(True) # True是默認值,使框架可見.
frame.Hide() # 等同于frame.Show(False)
```
**定義一個應用程序的初始化方法**
注意:我們沒有為我們的應用程序類定義一個`__init__()`方法。在`Python`中,這就意味著父方法`wx.App.__init()__`將在對象創建時被自動調用。這是一個好的事情。如果你定義你自己的`__init__()`方法,不要忘了調用其基類的`__init()__`方法,示例如下:
```
class App(wx.App):
def __init__(self):
wx.App.__init__(self)
```
如果你忘了這樣做,`wxPython`將不被初始化并且你的`OnInit()`方法也將得不到調用。
**創建一個應用程序實例并進入它的主事件循環**
這步是創建`wx.App`子類的實例,并調用它的`MainLoop()`方法:
```
app = App()
app.MainLoop()
```
一旦進入主事件循環,控制權將轉交給`wxPython`。`wxPython` `GUI`程序主要響應用戶的鼠標和鍵盤事件。當一個應用程序的所有框架被關閉后,這個`app.MainLoop()`方法將返回且程序退出。
## 擴展這個最小的空的wxPython程序
現在我們將給空的最小程序增加適當數量的功能,它包含了通常`Python`編程的標準并能夠作為你自己的程
序的一個基準。下面我們創建一個名為`spare.py`程序:
```
#!/usr/bin/env python #1
"""Spare.py is a starting point for a wxPython program.""" #2
import wx
class Frame(wx.Frame): #3
pass
class App(wx.App):
def OnInit(self):
self.frame = Frame(parent=None, title='Spare') #4
self.frame.Show()
self.SetTopWindow(self.frame) #5
return True
if __name__ == '__main__': #6
app = App()
app.MainLoop()
```
這個程序仍然很小,只有14行代碼,但是它增加了幾個重要的項目讓我們考慮到什么樣的代碼是好的、完整的。
**#1** 這行看似注釋,但是在如`linux`和`unix`等操作系統上,它告訴操作系統如何找到執行該程序的解釋器。如果這個程序被給予可執行權限(例如使用`chmod`命令),我們可以在命令行下僅僅鍵入該程序的名字來運行這個程序:
```
% spare.py
```
這行在其它的操作系統上將被忽略。但是包含它可以實現代碼的跨平臺。
**#2** 這是文檔字符串,當模塊中的第一句是字符串的時候,這個字符串就成了該模塊的文檔字符串并存儲
在該模塊的`__doc__`屬性中。你能夠在你的代碼中、某些開發平臺、甚至交互模式下運行的`Python`解釋器
中訪問文檔字符串:
```
import spare
print spare.__doc__
```
`Spare.py` 簡單 `wxPython` 程序的起點。
**#3** 我們改變了你們創建`frame`對象的方法。`bare`版的程序簡單地創建了一個`wx.Frame`類的實例。在`spare`版中,我們定義了我們自己的`Frame`類作為`wx.Frame`的子類。此時,最終的結果沒有什么不同,但是如果你想在你的框架中顯示諸如文本、按鈕、菜單的話,你可能就想要你自己的`Frame`類了。
**#4** 我們將對`frame`實例的引用作為應用程序實例的一個屬性
**#5** 在`OnInit()`方法中,我們調用了這個`App`類自己的`SetTopWindow()`方法,并傳遞給它我們新創建的`frame`實例。我們不必定義`SetTopWindow()`方法,因為它繼承自`wx.App`父類。`SetTopWindow()`方法是一個可選的方法,它讓`wxPython`方法知道哪個框架或對話框將被認為是主要的。一個`wxPython`程序可以有幾個框架,其中有一個是被設計為應用程序的頂級窗口的。
**#6** 這個是`Python`中通常用來測試該模塊是作為程序獨立運行還是被另一模塊所導入。我們通過檢查該模塊的`__name__`屬性來實現:
```
if __name__ == '__main__':
app = App()
app.MainLoop()
```
## 創建最終的hello.py程序
代碼如下:
```
#!/usr/bin/env python
"""Hello, wxPython! program."""
import wx
class Frame(wx.Frame): #2 wx.Frame子類
"""Frame class that displays an image."""
def __init__(self, image, parent=None, id=-1,
pos=wx.DefaultPosition,
title='Hello, wxPython!'): #3圖像參數
"""Create a Frame instance and display image."""
#4 顯示圖像
temp = image.ConvertToBitmap()
size = temp.GetWidth(), temp.GetHeight()
wx.Frame.__init__(self, parent, id, title, pos, size)
self.bmp = wx.StaticBitmap(parent=self, bitmap=temp)
class App(wx.App): #5 wx.App子類
"""Application class."""
def OnInit(self):
#6 圖像處理
image = wx.Image('wxPython.jpg', wx.BITMAP_TYPE_JPEG)
self.frame = Frame(image)
self.frame.Show()
self.SetTopWindow(self.frame)
return True
def main(): #7
app = App()
app.MainLoop()
if __name__ == '__main__':
main()
```
說明:
* **#2** 定義一個`wx.Frame`的子類,以便我們更容量控制框架的內容和外觀。
**#3** 給我們的框架的構造器增加一個圖像參數。這個值通過我們的應用程序類在創建一個框架的實例時提供。同樣,我們可以傳遞必要的值給`wx.Frame.__init__()`
**#4** 我們將用`wx.StaticBitmap`控件來顯示這個圖像,它要求一個位圖。所以我們轉換圖像到位圖。我們也使用圖像的寬度和高度創建一個`size`元組。這個`size`元組被提供給`wx.Frame.__init__()`調用,以便于框架的尺寸匹配位圖尺寸。
**#5** 定義一個帶有`OnInit()`方法的`wx.App`的子類,這是`wxPython`應用程序最基本的要求。
**#6** 我們使用與`hello.py`在同一目錄下的名為`wxPython.jpg`的文件創建了一個圖像對象。
**#7** `main()`函數創建一個應用程序的實例并啟動`wxPython`的事件循環。
- 活學活用wxPython
- 前言
- 致謝
- 關于本書
- 第一部分
- 第一章 歡迎使用wxPython
- 第二章 給wxPython程序一個堅實的基礎
- 第三章 在事件驅動環境中開發
- 第四章 用PyCrust使得wxPython更易處理
- 第五章 繪制藍圖
- 第六章 使用wxPython基本構件
- 第二部分 基礎wxPython
- 第七章 使用基礎控件
- 第八章 將構件放入窗體中
- 第九章 通過對話框讓用戶選擇
- 第十章 創建和使用wxPython菜單
- 第十一章 使用sizer放置構件
- 第十二章 操作基本圖像
- 第三部分 高級wxPython
- 第十三章 建造列表控件并管理列表項
- 第十四章 網格控件
- 第十五章 樹形控件
- 第十六章 在應用程序中加入HTML
- 第十七章 wxPython的打印構架
- 第十八章 使用wxPython的其他功能