XRC初步



本文轉自:金慶專欄的 XRC初步,金慶也是整理別人的,但是我就偷懶直接轉金慶的資料了,一併表示感謝!

轉自:雲雀 XRC初步(上) XRC初步(下)

XRC初步(上)

wxPython 中定義用戶界面佈局可以採用兩種方法。傳統的方法是將界面佈局代碼直接寫在源文件之中,這種方法不需要學習XML語法,概念上較爲簡單,避免了同時維護多個文件的麻煩;同時,對IDE的自動完成的支持較好。另一種方法則是採用XML資源文件,即XRC(XML Resource)。XRC的基本出發點是界面佈局和程序邏輯的分離,即將界面佈局代碼採用XML的方式放在分離的文件之中;在程序中不涉及控件的創建和佈局,只需要加載相應的資源並處理事件綁定即可。在wxPython中採用XRC分離界面佈局和程序邏輯主要有以下幾個方面的好處:

1. 提高了程序的可維護性
2. 界面佈局可由專業人員設計
3. 更好的支持GUI佈局設計工具
4. 作爲wxWidgets的規範,XRC資源可通用於C++、Python等語言

示例                         

使用XRC建立用戶界面必須建立兩個分離的文件:XML資源文件(.xrc)和python源文件。XRC文件包含了用戶界面佈局信息,如下例:

#design layout in a separate XML file

<?xml version="1.0" encoding="utf-8" ?>
<resource>
    
<object class="wxFrame" name="mainFrame">
        
<title>My Frame</title>
        
<object class="wxPanel" name="panel">
            
<object class="wxFlexGridSizer">
                
<cols>2</cols>
                
<rows>3</rows>
                
<vgap>5</vgap>
                
<hgap>5</hgap>
                
<object class="sizeritem">
                    
<object class="wxStaticText" name="label1">
                        
<label>First name:</label>
                    
</object>
                
</object>
                
<object class="sizeritem">
                    
<object class="wxTextCtrl" name="text1" />
                
</object>
                
<object class="sizeritem">
                    
<object class="wxStaticText" name="label2">
                        
<label>Last name:</label>
                    
</object>
                
</object>
                
<object class="sizeritem">
                    
<object class="wxTextCtrl" name="text2" />
                
</object>
                
<object class="spacer">
                    
<size>0,0</size>
                
</object>
                
<object class="sizeritem">
                    
<object class="wxButton" name="button">
                        
<label>Submit</label>
                    
</object>
                
</object>
            
</object>
        
</object>
    
</object>
</resource>

  Python源文件中則包括加載資源文件和事件綁定代碼,同時可以使用xrc.XRCCTRL方法從名字獲取控件,使用xrc.XRCID方法獲取控件ID:

#logic by itself in module

import wx
from wx import xrc

class MyApp(wx.App):

    
def OnInit(self):
        self.res 
= xrc.XmlResource('gui.xrc')
        
assert self.res
        self.init_frame()
        
return True
    
    
def init_frame(self):
        self.frame 
= self.res.LoadFrame(None, 'mainFrame')
        
assert self.frame
        self.panel 
= xrc.XRCCTRL(self.frame, 'panel')
        self.text1 
= xrc.XRCCTRL(self.panel, 'text1')
        self.text2 
= xrc.XRCCTRL(self.panel, 'text2')
        self.frame.Bind(wx.EVT_BUTTON, self.OnSubmit, id
=xrc.XRCID('button'))
        self.frame.Show()
    
    
def OnSubmit(self, evt):
        wx.MessageBox(
'Your name is %s %s!' %
            (self.text1.GetValue(), self.text2.GetValue()), 
'Feedback')
    

if __name__ == '__main__':
    app 
= MyApp(False)
    app.MainLoop()

創建XRC文件         

首先我們看看XRC的組成。XRC文件由一系列預定義的標籤組成,你可以注意到這些預定義的標籤與控件創建時的關鍵字參數相似。例如,在wxPython中創建按鍵的代碼如下:

button=wx.Button(parent=panel, id=wx.ID_ANY, label='Submit')


  與之相應的XRC代碼則是這個樣子:

<object class="wxButton" name="button">
    
<label>Submit</label>
</object>

  從例示中可以注意到幾個XRC的關鍵概念:

1. 每個控件與一個XML節點相對應
2. 控件間的層次關係與XML節點間層次關係相對應,放置控件的容器與相應的XML節點的父節點相對應
3. 節點class屬性值對應控件的C++類名
4. 節點name屬性值爲控件在XRC文件中的唯一標識,可通過該值自python源文件中獲取控件
5. label等其餘參數在XRC文件中作爲節點的子節點出現

  有了這些基本概念,現在我們可以使用XRC文件來佈局我們的用戶界面了。存在大量的工具以可視化的方式來幫助我們完成這個繁瑣的工作。wxPython 自帶的XRCED以一種半可視化的方式(可視化的設定控件屬性並預覽,但不支持直接拖放控件)支持用戶界面設計;開源的wxglade則支持直接的控件拖放,並可生成C++、python、perl、lisp和XRC的源文件;wxDesigner、dialogBlock,wxDesigner,BOA 等工具同樣值得一試。

XRC初步(下)

python源文件中的處理       

完成了XRC界面佈局文件的編寫,下一步必須在python源文件中做相應的處理。與XRC處理相關的wxPython代碼段主要包括三個方面:資源文件的加載,控件的獲取和事件綁定代碼:

  1.導入與XRC處理相關的xrc模塊:

importwx.xrc as xrc


  2.加載資源文件:

self.res=xrc.XmlResource('XRCfilename.xrc')


  3.獲取控件。此過程不需要顯式的創建控件,通過設計XRC文件時相應的name屬性值獲取即可:

#加載Frame,第一個參數爲父窗口,當前爲頂層窗口,故爲None
#
第二個參數爲設計XRC文件時Frame的name屬性值
self.frame=self.res.LoadFrame(None,'mainFrame')

#獲取控件,第一個參數爲控件的父窗口
#
第二個參數爲設計XRC文件時控件的name屬性值
self.panel=xrc.XRCCTRL(self.frame,'panel')
self.text1
=xrc.XRCCTRL(self.panel,'text1')

# 獲取panel中的控件時不必顯式獲取panel本身,直接傳入self.frame即可遞歸向下查找
self.text2=xrc.XRCCTRL(self.frame,'text2')

# 獲取控件ID,參數爲設計XRC文件時控件的name屬性值
self.id=xrc.XRCID('button')


  4.綁定事件處理有兩種方式:

  a. 綁定按鍵事件:

self.button=xrc.XRCCTRL(self.panel,'button')
self.frame.Bind(wx.EVT_BUTTON, self.OnSubmit, self.button)


  b. 因爲xrc.XRCCTRL僅能返回wx.Window的派生類,而wxMenuItem不是派生自wx.Window,不能採用xrc.XRCCTRL 獲取菜單項,因此事件必須委託給Frame綁定。派生自wx.Window的按鍵等控件也可以採用本方法綁定:

self.frame.Bind(wx.EVT_BUTTON, self.OnSubmit, id=xrc.XRCID('button'))


動態創建

加載Frame窗體時將自動加載其子控件和子窗體,那麼,你如何控制子窗體和子控件的加載呢?爲此,你必須將子窗體定義爲和窗體節體平行的頂級節點 (Frames、Dialogs、Panels、Toolbars、Menus和MenuBars可以作爲頂級節點),並通過程序控制加載。如下例:

dynamic.xrc文件: 

<?xml version="1.0" encoding="utf-8" ?>
<resource>
    
<object class="wxFrame" name="mainFrame">
        
<title>Primary Frame</title>
        
<object class="wxPanel" name="mainPanel">
            
<object class="wxButton" name="button">
                
<label>New Frame</label>
            
</object>
        
</object>
    
</object>
    
<object class="wxFrame" name="nextFrame">
        
<title>Secondary Frame</title>
        
<object class="wxPanel" name="nextPanel">
            
<object class="wxStaticText" name="label">
                
<label>This is a dynamically created frame.</label>
            
</object>
        
</object>
    
</object>
</resource>

Python源文件: 

import wx
from wx import xrc


class MyApp(wx.App):

    
def OnInit(self):
        self.res 
= xrc.XmlResource('dynamic.xrc')
        self.init_frame()
        
return True
        
    
def init_frame(self):
        self.frame 
= self.res.LoadFrame(None, 'mainFrame')
        self.panel 
= xrc.XRCCTRL(self.frame, 'mainPanel')
        self.button 
= xrc.XRCCTRL(self.panel, 'button')
        self.frame.Bind(wx.EVT_BUTTON, self.OnNewFrame, self.button)
        self.frame.Show()
        
    
def OnNewFrame(self, evt):
        self.frame2 
= self.res.LoadFrame(None, 'nextFrame')
        self.frame2.Show()
        

if __name__ == '__main__':
    app 
= MyApp(False)
    app.MainLoop()

  動態添加子控件時必須首先調用父窗口的GetSizer方法,創建控件後添加到Sizer,並調用Sizer的Fit方法爲控件留出顯示空間:

MainWindow=res.LoadFrame(None,"frame_1")
my_sizer
=MainWindow.GetSizer()
my_text
=wx.TextCtrl(MainWindow,-1,"Test", size=(325,200))
my_sizer.Add(my_text,
1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
my_sizer.Fit(MainWindow)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章