[i]您可以在幾分鐘內編寫一段 Python 腳本和讓桌面擁有令人難以置信的相當漂亮的 GUI 應用程序。這篇文章向您展示如何使用一 Python-著稱的 GUI 庫 wXPython,來做到這一點的。向您的朋友和鄰居介紹![/i]
這篇文章是關於 wxPython,但 wxPython 實際是兩件事物的組合體:Python 腳本語言和 GUI 功能的 wxWindows 庫(關於 wxWindows 的介紹,請參閱 developerWorks 上的 “細述 wxWindows”)。wxWindows 庫是為了最大可移植性的 C/C++ 庫,而抽取 GUI 功能。所以 wxWindows 應用程序與生俱來地可以運行在 Windows、帶 X、KDE 或 Gnome 的 UNIX 或者 wxWindows 已移植到的平台上(很不幸,還不包括 Macintosh)。當然 Python, 作為腳本引擎,具有很強的移植性(可以運行在 Macintosh 上,但如果您想要編寫桌面 GUI 代碼,它是不行的)。把 wxWindows 與 Python 腳本語言組合起來,意味著:wxPython 應用程序不僅快速和易於編寫,而且可以在不作任何更改情況下,運行在 Windows 或 UNIX 環境下。
您可能想,“但是那也是我有 Java 的原因,Java 也是可移植的。”沒錯,如果您曾試過在 Windows 上安裝 Java 應用程序,您就可能認識到完全不是這麼回事。Java 虛擬機是大的,它並不總是以您所想的方式工作,最糟糕的是,恕我直言,Java 窗口不是真正意義上的窗口,所以 Java 虛擬機與主機系統之間的交互總是有點力不從心。
另一方面,Python 占有相對小的空間。wxPython 庫的窗口是真正實在的本地窗口,它可以做本地窗口能做的任何事情,使您的 wxPython 程序如同窗口的程序一樣。wxPython 的全部家當可以打包成一個易於安裝的軟件包。也許我是一個固執的人,但我發現做同樣的事情,wxPython 要比 Java 容易得多。
但是您可能沒有聽說過桌面上的 Python,它是服務器端編程社區的一員,作為腳本語言這一塊的新生兒(特別是與應用程序服務器框架連接,如 Zope)。現在人們正趕上 Python 的熱潮。Python 的好處在於,不象其它腳本語言,它從一開始就是面向對象的語言。所以您不會忽視 Java 由於喜愛 Python 而失去品嘗 OO 好處。
世界上最小的 wxPython 程序,剖析!
聽起來很酷,不是嗎?讓我們看一些代碼,您將會明白我所說的。為了易於討論,我在示例中插入了一些行標簽。它們 不是代碼中的一部分;這就是為什麼它們以藍色斜體表示。
[b][size=3]清單 1. 一段很小的代碼樣本[/size][/b]
[myPHP]
[1] import sys, os
[2] from wxPython.wx import *
[3] class main_window(wxFrame):
[4] def __init__(self, parent, id, title):
[5] wxFrame.__init__(self, parent, -1, title, size = (200, 100),
style=wxDEFAULT_FRAME_STYLEwxNO_FULL_REPAINT_ON_RESIZE)
[6] self.control = wxTextCtrl(self, -1, style=wxTE_MULTILINE)
[7] self.Show(true)
[8] class App(wxApp):
def OnInit(self):
frame =
main_window(None, -1, "wxPython: (A Demonstration)")
self.SetTopWindow(frame)
return true
[9] app = App(0)
app.MainLoop()
[/myphp]
我們一行行地看,這樣容易明白該代碼的工作原理。這就是為什麼它是世界上最小的 wxPython 程序(我已經把所有無關的細節剔除了)。這段代碼只能創建了一帶有一個編輯字段的窗口。您可以在這個字段中編輯,但很明顯沒有辦法保存。該應用程序看上去就象在 Windows 下一樣(我在裡面輸入了一些東西):
[myimg]upload/tiny.gif[/myimg]
讓我們查看代碼
第一行和第二行是很重要的,在後面會需要它們。事實上,在這個示例中, 不需要 sys 和 os,但由於幾乎每個程序都要用到,所以先把它們放進這段代碼,在後面會針對它們提一些問題。第二行比較有趣,導入 wxPython 的 wx 庫。當然,wx 庫(基本 wxPython 聲明)包括基本類,如框架和應用程序。
/注意這些行的結尾沒有分號。如果您編寫過 Perl 程序,那您要花費一點功夫來熟悉 Python 的輸入習慣。但等等,它對您來說是陌生的。
在第三行,定義了第一個 Python 類 -- main_window。main_window 類是在 wx 模塊中定義的 wxFrame 類的派生類。正如您猜想的,任何窗口都是 wxFrame 類。
在第四行,定義了初始化方法,main_window 需要定義的唯一方法(當然,其它的在 wxFrame 類中)。初始化方法取參數 parent、id、title 以及當然還有(作為該對象的引用的)self。self 參數是所有 Python 方法的第一個參數。
到現在為止,如果您編寫過 C/C++,您一定奇怪為什麼沒有花括號。是很奇怪,Python 把縮進當作重要的句法。任何有子語句的語句以冒號結束,所有該行下的縮進行都屬於以該冒號終止的語句。當縮進回復到原來的縮進時,這一塊就完成了。更為奇怪的是,這種安排實際上很好用,剛開始編程的程序員發現,這要比用花括號來說明結構要容易。幸運地是,這還意味著更少的擊鍵次數,所以老程序員也能接受它。
所以縮進的第 5、6 和 7 行屬於在第 4 行中定義的方法。它們分別調用 wxFrame 父類的初始化例程(實際進行設置一個窗口的所有繁重工作),定義一個控件以適合新的主窗口,以及確保窗口是可見的。
wxPython 會重新調整父窗口的大小,除非專門告訴不要這樣做。如果您曾編寫過任何 Microsoft Windows 代碼,通過重新調整控件大小來匹配父窗口,那您會很快喜歡 wxPython。第 6 行的實際意義是完成一個如同 Notepad 一樣的編輯器。這還不算什麼。用 C/C++ 代碼,則需要更多才能實現,不是嗎?記住 -- 我們在這做的不是固定大小的對話框,它是真正在窗口主體中和可調整大小的帶編輯器的 Windows- 化應用程序。
讓我們繼續。第 8 行定義了由 wxApp 類派生的 App 對象。它指定了應用程序對象,當運行時,創建一個 main_window 對象,並將它設置為頂部窗口。
最後定義完類,創建應用程序對象,開始運行它的主循環。如果您做過任何 C/C++ Windows 編程,會認識到 MainLoop 方法是所有 Windows 程序的正常事件循環。這個啟動代碼的風格確實與腳本語言保持一致。記住,Python 解釋器逐行讀取代碼,並邊讀邊執行它。所以,一旦定義了類,我們只需在腳本中調用它。
這就是 它。在這十五行代碼中,實現了一個簡單的文本編輯器,這段代碼無需修改就可以在 Windows 或 UNIX 上運行。而且很容易添加更多特性,這太好了,在下一節將要講述這些。
性能怎樣?
您可能認為,“解釋型語言,效率不高。對於較大的程序,執行起來會很慢。”在一定程度上,這是正確的。事實上,任何影響性能的代碼通常用 C/C++ 重新實現,並鏈接到 Python 解釋器,這是很容易做的。所以 Python 通常用作綁定功能性模塊和 GUI 顯示(或應用程序服務器功能,如果您需要該功能)的粘合劑。但作為粘合劑,Python 是非常有效的。您可以在很短的時間內用 Python 實現真正的程序,由於其面向對象和格式方面有限的創造機會,它們通常可使用好幾個星期。
而且,如果您懷疑使用解釋型語言將大程序結合在一起的想法,那您不妨考慮一下 Microsoft Word 的早期版本是如何實現的。至少最近的 Windows 的 Word 版本 6.0,其 Word Basic 函數事實上只是編譯過的代碼;而 GUI 是由 pcode 解釋性型語言構建的。(MS Word 6.0 是用 Word Basic 編寫的,很有效,這是一個很聰明的設計,其原因之一 -- 它是最早用內置解釋器的桌面程序。)
這裡您所損失的是在性能方面(實際上,很少),但您可以很容易地通過簡化實現和(更重要)簡化定制來彌補。事實上,通過包含 Python 您已經自動包括了易於展現給您的用戶的腳本語言,同時,對於編程的新手來說,該語言也證明了其易於學習。如果鑽研它,可以用比您現在花費的要少的功夫創作出世界級的軟件。因為,如果該語言能為 Microsoft 服務,那麼,它也能為您服務!
更有趣的事:初步的項目組織器
無論如何,言歸正傳,這裡向您展示一個程序,它事實上做一些值得做的事情。這個程序讓您創建一個稱之為項目的文本文件列表。您可以編輯和保存它們。更重要的是,您可以很容易地看到如何進一步增強基本組織器。我使用一個擴展版本為 CVS(標准開放源碼版本控制系統)的前端。代碼在下面。我們(仍然相當小)的應用程序從 15 行擴展到大約 300行,但它現在能實現許多事情。
[myimg]upload/org.gif[/myimg]
程序中的趣事
清單 2 中我沒有列出行號,因為很明顯無論如何您都要月閱讀該代碼。我只是一般性地講述一下這個程序是做什麼以及它所用的 Python 與 wxPython 的功能是什麼。有關Python 更詳細說明,請您本地的書店找 Mark Lutz 寫的 O'Reilly 這本書,或者閱讀隨 Python(Guido Rossum 著,Python 的實際作者)一起的文檔。
第一個有趣的事是這個應用程序處理命令行。列表 sys.argv 是命令行,為了使用它您需要理解 Python 列表語法。該示例用的語法很基本,但這足夠讓您理解這個程序了。
接下來,為了在調試時易於使用,定義一個 MsgBox 函數。注意,用於函數聲明和類方法聲明的語法正好相同。唯一的區別是類方法需要帶參數 self,該參數包含了正在調用的對象的引用。(當然,您不一定要稱它為 "self"。但如果不這樣做,您會迷惑的。)
真正有趣的是在更為復雜的 __init__ 方法。這裡,我們沒有構建象上例一樣的簡單的、缺乏控件的菜單,而是構建了一個菜單欄,並附加菜單事件到回調例程,以及構建窗口分割欄、樹控件和編輯控件。您可以撇去這些來看整個工作怎樣。(如果您以前未做過 GUI 編程,往下看,您會覺得很困難。)Visual Basic 用一種幕後的方式可以做所有這些,但如果在文本編輯器僅僅打開表格文件,您仍然可以看到它。如果您曾用 C/C++ 做過 GUI 工作,那會覺得很熟悉。
一旦有構造了的窗口,接下來我們就可以來看程序的實際代碼。首先,在方法 __init__ 後有兩個用於載入和保存項目文件的方法。在那可以看到 Python 如何用 open 等等來處理文件 I/O。注意,事實上,關閉文件是一種輕松的事 -- 正如它所發生的那樣,對於 Python 來講,文件句柄僅僅是內存管理的對象,且該對象由計數器引用。當該引用變為無效時,Python 知道,並會清除它,這時文件會自動關閉。也有不能完全信任的情形(文件不能自動關閉),例如,您將再次打開已寫的文件,並讀它。這時,您要明確地關閉它。這個問題就是無用信息收集的問題(非 C 的人喜歡討論的問題)。
載入/保存函數的另一個有趣的特性是他們會碰到由壞文件調用產生的例外( IOError 例外)。我讓代碼來說明自己,但那是您如何做的,孩子們。
新代碼剩下的問題是事件處理程序,用於處理在程序執行過程中所碰到的。我再次讓程序自己來說明大部分。注意,使用一般的對話框( wxMessageDialog、wxFileDialog 和 wxTextEntryDialog)來處理許多常規用戶交互。這些調用與“常規”Windows 編程的相應用法有一點不同,這裡我只給您一些線索:首先,對話框是一個由合理的調用創建的對象,它用 ShowModal() 顯示,用完後並破壞它;其次,用戶單擊的按鈕作為返回值從 ShowModal() 返回,用對話框附屬的方法可得到其它值。例如,在文件對話框交互期間,用戶選擇的路徑是作為 dlg.GetPath() 而獲得。這與 Windows API 的工作方式相當不同。正是這樣您知道的。
文檔狀況
讓我說,wxWindows API 的文檔處於……開發中。這個平台最大的弱點是缺乏好的文檔,我正在積極地改變這種狀況。下半年情況會有所好轉。同時,Python 本身有一些好的書籍,其中 Python 的在線文檔就不差。對於 wxWindows,C++ 的文檔很好。有時,在 Python 框架中,如何使這些文檔合理些,是相當神秘的。在那裡,有一些具體的 Python 注釋,但在很多情況下,您會發現必須要讀隨 wxPython 一起的演示代碼,或者,必須向郵件列表中的專家詢問您的問題。幸運地是,這些專家是“有跡可尋”的。
一旦通過了最初的學習曲線,您會覺得這要比在 Windows API 中做同樣的任務要簡單的多。相信我,這份材料是很好的。
[b][size=5]附錄[/size][/b]
[myphp]
#!/bin/python
import sys, os
from wxPython.wx import *
from string import *
# Process the command line. Not mUCh to do;
# just get the name of the project file if it's given. Simple.
projfile = 'Unnamed'
if len(sys.argv) > 1:
projfile = sys.argv[1]
def MsgBox (window, string):
dlg=wxMessageDialog(window, string, 'wxProject', wxOK)
dlg.ShowModal()
dlg.Destroy()
class main_window(wxFrame):
def __init__(self, parent, id, title):
wxFrame.__init__(self, parent, -1, title, size = (500, 500),
style=wxDEFAULT_FRAME_STYLEwxNO_FULL_REPAINT_ON_RESIZE)
# ------------------------------------------------------------------------------------
# Set up menu bar for the program.
# ------------------------------------------------------------------------------------
self.mainmenu = wxMenuBar() # Create menu bar.
mainwindow = self
menu=wxMenu() # Make a menu (will be the Project menu)
exitID=wxNewId() # Make a new ID for a menu entry.
menu.Append(exitID, '&Open', 'Open project') # Name the ID by adding it to the menu.
EVT_MENU(self, exitID, self.OnProjectOpen) # Create and assign a menu event.
exitID=wxNewId()
menu.Append(exitID, '&New', 'New project')
EVT_MENU(self, exitID, self.OnProjectNew)
exitID=wxNewId()
menu.Append(exitID, 'E&xit', 'Exit program')
EVT_MENU(self, exitID, self.OnProjectExit)
self.mainmenu.Append (menu, '&Project') # Add the project menu to the menu bar.
menu=wxMenu() # Make a menu (will be the File menu)
exitID=wxNewId()
menu.Append(exitID, '&Add', 'Add file to project')
EVT_MENU(self, exitID, self.OnFileAdd)
exitID=wxNewId()
menu.Append(exitID, '&Remove', 'Remove file from project')
EVT_MENU(self, exitID, self.OnFileRemove)
exitID=wxNewId()
menu.Append(exitID, '&Open', 'Open file for editing')
EVT_MENU(self, exitID, self.OnFileOpen)
exitID=wxNewId()
menu.Append(exitID, '&Save', 'Save file')
EVT_MENU(self, exitID, self.OnFileSave)
self.mainmenu.Append (menu, '&File') # Add the file menu to the menu bar.
self.SetMenuBar (self.mainmenu) # Attach the menu bar to the window.
# ------------------------------------------------------------------------------------
# Create the splitter window.
# ------------------------------------------------------------------------------------
splitter = wxSplitterWindow (self, -1, style=wxNO_3DwxSP_3D)
splitter.SetMinimumPaneSize (1)
# ------------------------------------------------------------------------------------
# Create the tree on the left.
# ------------------------------------------------------------------------------------
tID = wxNewId()
self.tree = wxTreeCtrl (splitter, tID, style=wxTR_HAS_BUTTONS
wxTR_EDIT_LABELS
wxTR_HAS_VARIABLE_ROW_HEIGHT)
EVT_TREE_BEGIN_LABEL_EDIT(self.tree, tID, self.OnTreeLabelEdit)
EVT_TREE_END_LABEL_EDIT(self.tree, tID, self.OnTreeLabelEditEnd)
EVT_TREE_ITEM_ACTIVATED(self.tree, tID, self.OnTreeItemActivated)
# ------------------------------------------------------------------------------------
# Create the editor on the right.
# ------------------------------------------------------------------------------------
self.editor = wxTextCtrl(splitter, -1, style=wxTE_MULTILINE)
self.editor.Enable (0)
# ------------------------------------------------------------------------------------
# Install the tree and the editor.
# ------------------------------------------------------------------------------------
splitter.SplitVertically (self.tree, self.editor)
splitter.SetSashPosition (180, true)
self.Show(true)
# Some global state variables.
self.projectdirty = false
# ----------------------------------------------------------------------------------------
# Some nice little handlers.
# ----------------------------------------------------------------------------------------
def project_open(self, project_file):
try:
input = open (project_file, 'r')
self.tree.DeleteAllItems()
self.project_file = project_file
name = replace (input.readline(), "\n", "")
self.SetTitle (name)
self.root = self.tree.AddRoot(name)
self.activeitem = self.root
for line in input.readlines():
self.tree.AppendItem (self.root, replace(line, "\n", ""))
input.close
self.tree.Expand (self.root)
self.editor.Clear()
self.editor.Enable (false)
self.projectdirty = false
except IOError:
pass
def project_save(self):
try:
output = open (self.project_file, 'w+')
output.write (self.tree.GetItemText (self.root) + "\n")
count = self.tree.GetChildrenCount (self.root)
iter = 0
child = ''
for i in range(count):
if i == 0:
(child,iter) = self.tree.GetFirstChild(self.root,iter)
else:
(child,iter) = self.tree.GetNextChild(self.root,iter)
output.write (self.tree.GetItemText(child) + "\n")
output.close()
self.projectdirty = false
except IOError:
dlg_m = wxMessageDialog (self, 'There was an error saving the project file.',
'Error!', wxOK)
dlg_m.ShowModal()
dlg_m.Destroy()
# ----------------------------------------------------------------------------------------
# Event handlers from here on out.
# ----------------------------------------------------------------------------------------
def OnProjectOpen(self, event):
open_it = true
if self.projectdirty:
dlg=wxMessageDialog(self, 'The project has been changed. Save?', 'wxProject',
wxYES_NO wxCANCEL)
result = dlg.ShowModal()
if result == wxID_YES:
self.project_save()
if result == wxID_CANCEL:
open_it = false
dlg.Destroy()
if open_it:
dlg = wxFileDialog(self, "Choose a project to open", ".", "", "*.wxp", wxOPEN)
if dlg.ShowModal() == wxID_OK:
self.project_open(dlg.GetPath())
dlg.Destroy()
def OnProjectNew(self, event):
open_it = true
if self.projectdirty:
dlg=wxMessageDialog(self, 'The project has been changed. Save?', 'wxProject',
wxYES_NO wxCANCEL)
result = dlg.ShowModal()
if result == wxID_YES:
self.project_save()
if result == wxID_CANCEL:
open_it = false
dlg.Destroy()
if open_it:
dlg = wxTextEntryDialog (self, "Name for new project:", "New Project",
"New project", wxOK wxCANCEL)
if dlg.ShowModal() == wxID_OK:
newproj = dlg.GetValue()
dlg.Destroy()
dlg = wxFileDialog (self, "Place to store new project", ".", "", "*.wxp",
wxSAVE)
if dlg.ShowModal() == wxID_OK:
try:
proj = open (dlg.GetPath(), 'w')
proj.write (newproj + "\n")
proj.close()
self.project_open (dlg.GetPath())
except IOError:
dlg_m = wxMessageDialog (self, 'There was an error saving the new
project file.', 'Error!', wxOK)
dlg_m.ShowModal()
dlg_m.Destroy()
dlg.Destroy()
def OnProjectExit(self, event):
close = true
if self.projectdirty:
dlg=wxMessageDialog(self, 'The project has been changed. Save?', 'wxProject',
wxYES_NO wxCANCEL)
result = dlg.ShowModal()
if result == wxID_YES:
self.project_save()
if result == wxID_CANCEL:
close = false
dlg.Destroy()
if close:
self.Close()
def OnFileAdd(self, event):
dlg = wxFileDialog (self, "Choose a file to add", ".", "", "*.*", wxOPEN)
if dlg.ShowModal() == wxID_OK:
path = os.path.split(dlg.GetPath())
self.tree.AppendItem (self.root, path[1])
self.tree.Expand (self.root)
self.project_save()
def OnFileRemove(self, event):
item = self.tree.GetSelection()
if item != self.root:
self.tree.Delete (item)
self.project_save()
def OnFileOpen(self, event):
item = self.tree.GetSelection()
def OnFileSave(self, event):
if self.activeitem != self.root:
self.editor.SaveFile (self.tree.GetItemText (self.activeitem))
def OnTreeLabelEdit(self, event):
item=event.GetItem()
if item != self.root:
event.Veto()
def OnTreeLabelEditEnd(self, event):
self.projectdirty = true
def OnTreeItemActivated(self, event):
go_ahead = true
if self.activeitem != self.root:
if self.editor.IsModified():
dlg=wxMessageDialog(self, 'The edited file has changed. Save it?',
'wxProject', wxYES_NO wxCANCEL)
result = dlg.ShowModal()
if result == wxID_YES:
self.editor.SaveFile (self.tree.GetItemText (self.activeitem))
if result == wxID_CANCEL:
go_ahead = false
dlg.Destroy()
if go_ahead:
self.tree.SetItemBold (self.activeitem, 0)
if go_ahead:
item=event.GetItem()
self.activeitem = item
if item != self.root:
self.tree.SetItemBold (item, 1)
self.editor.Enable (1)
self.editor.LoadFile (self.tree.GetItemText(item))
self.editor.SetInsertionPoint (0)
self.editor.SetFocus()
else:
self.editor.Clear()
self.editor.Enable (0)
class App(wxApp):
def OnInit(self):
frame = main_window(None, -1, "wxProject - " + projfile)
self.SetTopWindow(frame)
if (projfile != 'Unnamed'):
frame.project_open (projfile)
return true
app = App(0)
app.MainLoop()
[/myphp]
def OnFileSave(self, event):
if self.activeitem != self.root:
self.editor.SaveFile (self.tree.GetItemText (self.activeitem))
def OnTreeLabelEdit(self, event):
item=event.GetItem()
if item != self.root:
event.Veto()
def OnTreeLabelEditEnd(self, event):
self.projectdirty = true
def OnTreeItemActivated(self, event):
go_ahead = true
if self.activeitem != self.root:
if self.editor.IsModified():
dlg=wxMessageDialog(self, 'The edited file has changed. Save it?',
'wxProject', wxYES_NO wxCANCEL)
result = dlg.ShowModal()
if result == wxID_YES:
self.editor.SaveFile (self.tree.GetItemText (self.activeitem))
if result == wxID_CANCEL:
go_ahead = false
dlg.Destroy()
if go_ahead:
self.tree.SetItemBold (self.activeitem, 0)
if go_ahead:
item=event.GetItem()
self.activeitem = item
if item != self.root:
self.tree.SetItemBold (item, 1)
self.editor.Enable (1)
self.editor.LoadFile (self.tree.GetItemText(item))
self.editor.SetInsertionPoint (0)
self.editor.SetFocus()
else:
self.editor.Clear()
self.editor.Enable (0)
class App(wxApp):
def OnInit(self):
frame = main_window(None, -1, "wxProject - " + projfile)
self.SetTopWindow(frame)
if (projfile != 'Unnamed'):
frame.project_open (projfile)
return true
app = App(0)
app.MainLoop()
[/myphp]
if item != self.root:
self.tree.Delete (item)
self.project_save()
def OnFileOpen(self, event):
item = self.tree.GetSelection()
def OnFileSave(self, event):
if self.activeitem != self.root:
self.editor.SaveFile (self.tree.GetItemText (self.activeitem))
def OnTreeLabelEdit(self, event):
item=event.GetItem()
if item != self.root:
event.Veto()
def OnTreeLabelEditEnd(self, event):
self.projectdirty = true
def OnTreeItemActivated(self, event):
go_ahead = true
if self.activeitem != self.root:
if self.editor.IsModified():
dlg=wxMessageDialog(self, 'The edited file has changed. Save it?',
'wxProject', wxYES_NO wxCANCEL)
result = dlg.ShowModal()
if result == wxID_YES:
self.editor.SaveFile (self.tree.GetItemText (self.activeitem))
if result == wxID_CANCEL:
go_ahead = false
dlg.Destroy()
if go_ahead:
self.tree.SetItemBold (self.activeitem, 0)
if go_ahead:
item=event.GetItem()
self.activeitem = item
if item != self.root:
self.tree.SetItemBold (item, 1)
self.editor.Enable (1)
self.editor.LoadFile (self.tree.GetItemText(item))
self.editor.SetInsertionPoint (0)
self.editor.SetFocus()
else:
self.editor.Clear()
self.editor.Enable (0)
class App(wxApp):
def OnInit(self):
frame = main_window(None, -1, "wxProject - " + projfile)
self.SetTopWindow(frame)
if (projfile != 'Unnamed'):
frame.project_open (projfile)
return true
app = App(0)
app.MainLoop()
[/myphp]
self.project_open (dlg.GetPath())
except IOError:
dlg_m = wxMessageDialog (self, 'There was an error saving the new
project file.', 'Error!', wxOK)
dlg_m.ShowModal()
dlg_m.Destroy()
dlg.Destroy()
def OnProjectExit(self, event):
close = true
if self.projectdirty:
dlg=wxMessageDialog(self, 'The project has been changed. Save?', 'wxProject',
wxYES_NO wxCANCEL)
result = dlg.ShowModal()
if result == wxID_YES:
self.project_save()
if result == wxID_CANCEL:
close = false
dlg.Destroy()
if close:
self.Close()
def OnFileAdd(self, event):
dlg = wxFileDialog (self, "Choose a file to add", ".", "", "*.*", wxOPEN)
if dlg.ShowModal() == wxID_OK:
path = os.path.split(dlg.GetPath())
self.tree.AppendItem (self.root, path[1])
self.tree.Expand (self.root)
self.project_save()
def OnFileRemove(self, event):
item = self.tree.GetSelection()
if item != self.root:
self.tree.Delete (item)
self.project_save()
def OnFileOpen(self, event):
item = self.tree.GetSelection()
def OnFileSave(self, event):
if self.activeitem != self.root:
self.editor.SaveFile (self.tree.GetItemText (self.activeitem))
def OnTreeLabelEdit(self, event):
item=event.GetItem()
if item != self.root:
event.Veto()
def OnTreeLabelEditEnd(self, event):
self.projectdirty = true