<dd id="sga4y"><optgroup id="sga4y"></optgroup></dd>
<nav id="sga4y"><code id="sga4y"></code></nav>
  • <optgroup id="sga4y"></optgroup>

    TraitsUI-輕松制作用戶界面?

    Python有著豐富的界面開發庫,除了缺省安裝的Tkinter以外,wxPython、pyQt4等都是非常優秀的界面開發庫。但是它們有一個共同的問題:需要開發者掌握眾多的API函數,許多細節,例如配置控件的屬性、位置以及事件響應都需要開發者一一處理。

    在開發科學計算程序時,我們希望快速實現一個夠用的界面,讓用戶能夠交互式的處理數據,而又不希望在界面制作上花費過多的精力。以traits為基礎、以Model-View-Controller為設計思想的TraitUI庫就是實現這一理想的最佳伴侶。

    缺省界面?

    TraitsUI是一套建立在Traits庫基礎上的用戶界面庫。它和Traits緊密相連,如果你已經設計好了一個繼承于HasTraits的類的話,那么直接調用其configure_traits方法,系統將會使用TraitsUI自動生成一個界面,以供用戶交互式地修改對象的trait屬性。讓我們先來看下面這個例子:

    from enthought.traits.api import HasTraits, Str, Int
    
    class SimpleEmployee(HasTraits):
        first_name = Str
        last_name = Str
        department = Str
    
        employee_number = Str
        salary = Int
    
    sam = SimpleEmployee()
    sam.configure_traits()
    

    此程序創建一個SimpleEmployee類的對象sam,然后調用sam.configure_traits顯示出如下的缺省界面:

    _images/traitsUI_intro_01.png

    自動生成的SimpleEmployee類的對話框

    可以看到此界面是自動根據trait屬性生成。所有的屬性都以文本框的形式編輯,并且每個文本框前面都有一個文字標簽,其文字根據trait屬性名自動生成:第一個字母變為大寫,所有的下劃線變為空格。最下面為我們提供了OK和Cancel按鈕以確定或者取消對trait屬性值的修改。

    salary屬性雖然和其它屬性一樣都采用文本框進行編輯,但是由于salary屬性定義為Int類型,所以它將檢查非法輸入,并以紅色背景警示,鼠標左擊Salary標簽,將彈出salary屬性相關的詳細說明,由于我們沒有設置此說明,系統缺省給出salary所能接受的值的類型。

    _images/traitsUI_intro_02.png

    界面中的每個屬性編輯器都有詳細說明,并且能檢查非法輸入

    我們連一行界面相關的代碼都沒有寫,卻能得到這樣一個已經夠實用的界面,應該還是很令人滿意的吧。為了人工控制界面的設計和布局,就需要我們添加自己的代碼了。

    自定義界面?

    下面的程序在前面的基礎上自定義了一個視圖對象view1,然后將此對象傳遞給configure_traits方法,于是界面就按照視圖中描述的那樣生成了:

    # -*- coding: utf-8 -*-
    from enthought.traits.api import HasTraits, Str, Int
    from enthought.traits.ui.api import View, Item
    
    class SimpleEmployee(HasTraits):
        first_name = Str
        last_name = Str
        department = Str
        employee_number = Str
        salary = Int
    
    view1 = View(
        Item(name = 'department', label=u"部門", tooltip=u"在哪個部門干活"),
        Item(name = 'last_name', label=u"姓"),
        Item(name = 'first_name', label=u"名"))
    
    sam = SimpleEmployee()
    sam.configure_traits(view=view1)
    

    選擇后臺界面庫

    用traits.ui庫創建的界面可以選擇后臺界面庫,目前支持的有qt4和wx兩種。在啟動程序時添加 -toolikt qt4 或者 -toolikt wx 選擇使用何種界面庫生成界面。本文中全部使用wx作為后臺界面庫。

    _images/traitsUI_intro_03.png

    通過label和tooltip手工指定屬性編輯器的標簽和說明

    有關界面視圖的對象都在traits.ui庫中,所以首先從其中載入View和Item。View用來生成視圖,而Item則用來描述視圖中的項目(控件)。程序中,用Item依次創建三個視圖項目,都作為參數傳遞給View,于是所生成的界面中按照參數的順序顯示控件,而不是按照trait屬性名排序了。

    Item對象?

    Item對象是視圖的基本組成單位,每個Item描述界面中的中的一個控件,通常都是用來顯示HasTraits對象中的某一個trait屬性。每個Item由一系列的關鍵字參數來進行配置,這些參數對Item的內容、表現以及行為進行描述。其中最重要的一個參數就是name。我們看到name參數的值都配置為SimpleEmployee類的trait屬性名,于是Item就知道到哪里去尋找真正要顯示的值了。可以看出視圖與數據是通過屬性名聯系起來的。剩下的兩個參數label和tooltip設置Item在界面中的一些顯示相關的屬性。Item對象還有很多屬性其它屬性,請參考TraitsUI的用戶手冊,或者在iPython中輸入Item??直接查看其源代碼。如果你查看了Item的源代碼的話,你就會發現,原來Item的這些屬性也都是用trait定義的:

    class Item ( ViewSubElement ):
        """ An element in a Traits-based user interface.
        """
    
        #  Trait definitions:
    
        # A unique identifier for the item. If not set, it defaults to the value
        # of **name**.
        id = Str
    
        # User interface label for the item in the GUI. If this attribute is not
        # set, the label is the value of **name** with slight modifications:
        # underscores are replaced by spaces, and the first letter is capitalized.
        # If an item's **name** is not specified, its label is displayed as
        # static text, without any editor widget.
        label = Str
    
        # Name of the trait the item is editing:
        name = Str
    

    除了Item之外,TraitsUI庫還定義了下面幾個Item的子類:

    • Label
    • Heading
    • Spring

    這些類用來協助View的布局,因此不需要和某個trait屬性關聯。

    Group對象?

    前面的例子中,我們通過把三個Item對象傳遞給View,創建了一個控件垂直排列的布局。然而在真正的界面開發中,需要更加高級的布局方式,例如,將一組相關的元素組織在一起,放到一個組中,我們可以為此組添加標簽,定義組的幫助文本,通過設置組的屬性使組類的元素同時有效或無效。在TraitUI中,這樣的組的功能通過Group對象實現,讓我們來修改一下前面的例子:

    # -*- coding: utf-8 -*-
    from enthought.traits.api import HasTraits, Str, Int
    from enthought.traits.ui.api import View, Item, Group
    
    class SimpleEmployee(HasTraits):
        first_name = Str
        last_name = Str
        department = Str
    
        employee_number = Str
        salary = Int
        bonus = Int
    
    view1 = View(
        Group(
            Item(name = 'employee_number', label=u'編號'),
            Item(name = 'department', label=u"部門", tooltip=u"在哪個部門干活"),
            Item(name = 'last_name', label=u"姓"),
            Item(name = 'first_name', label=u"名"),
            label = u'個人信息',
            show_border = True
        ),
        Group(
            Item(name = 'salary', label=u"工資"),
            Item(name = 'bonus', label=u"獎金"),
            label = u'收入',
            show_border = True
        )
    )
    
    sam = SimpleEmployee()
    sam.configure_traits(view=view1)
    

    此程序的運行效果如下:

    _images/traitsUI_intro_04.png

    分標簽頁顯示兩個Group的內容

    我們分別創建兩個Group傳遞給View,每個Group中仍然通過Item創建控件,通過Group的關鍵字參數指定其label和show_border屬性。由于View中的所有內容都是Group,它自動地將兩個Group放到Tab中,對兩個Group進行分標簽顯示。

    如果我們希望能同時看到兩個Group的話,可以另外再創建一個Group將這兩個Group包括起來:

    view2 = View( Group( view1.content ) )
    

    這里我們創建視圖view2,它包括一個Group,此Group的內容則直接使用view1的內容(也就是那兩個Group)。當然也可以把view1中的內容復制進去:

    view2 = View(Group(
        Group(
            Item(name = 'employee_number', label=u'編號'),
            Item(name = 'department', label=u"部門", tooltip=u"在哪個部門干活"),
            Item(name = 'last_name', label=u"姓"),
            Item(name = 'first_name', label=u"名"),
            label = u'個人信息',
            show_border = True
            ),
        Group(
            Item(name = 'salary', label=u"工資"),
            Item(name = 'bonus', label=u"獎金"),
            label = u'收入',
            show_border = True
            )
    ))
    

    然后我們將view2傳遞給configure_traits,用view2顯示界面:

    sam.configure_traits(view=view2)
    
    _images/traitsUI_intro_06.png

    豎排顯示兩個Group的內容

    在創建Group時,我們可以通過設置其orientation和layout等屬性,改變Group的內容呈現方式。由于某些設置會經常用到,因此還提供了專門的Group子類重載這些屬性的缺省值。例如下面是從Group類繼承的HSplit類的代碼:

    class HSplit ( Group ):
        # ... ...
        layout      = 'split'
        orientation = 'horizontal'
    

    HSplit對象將其所包括的內容按照水平排列,并且在每兩個子內容之間添加一個可調整的分隔條,HSplit和如下的代碼是等價的:

    Group( ... , layout = 'split', orientation = 'horizontal')
    

    為了正確顯示分隔條,其子內容中需要有一個具有scrollable屬性,如下面的代碼(省略Item定義等部分)所示:

    view1 = View(
        HSplit(
            VGroup(
                ... ...,
                scrollable = True
            ),
            VGroup(
                ... ...
            ),
    
        ),
        resizable = True,
        width = 400,
        height = 150
    )
    _images/traitsUI_intro_07.png

    帶分隔條的橫排顯示兩個Group的內容

    下面是Group的各種子類和其對應的Group屬性配置:

    • HGroup : 內容水平排列:

      Group(orientation= 'horizontal')
      
    • HFlow : 內容水平排列,當超過水平寬度時,將自動換行:

      Group(orientation= 'horizontal, layout='flow', show_labels=False)
    • HSplit : 內容水平分隔,中間插入分隔條:

      Group(orientation= 'horizontal', layout='split')
      
    • Tabbed : 內容分標簽頁顯示:

      Group(orientation= 'horizontal', layout='tabbed)
    • VGroup : 內容垂直排列:

      Group(orientation= 'vertical')
      
    • VFlow : 內容垂直排列,當超過垂直高度時,將自動換列:

      Group(orientation= 'vertical', layout='flow', show_labels=False)
      
    • VFold : 內容垂直排列,可折疊 :

      Group(orientation= 'vertical', layout='fold', show_labels=False)
      
    • VGrid : 按照兩列的網格進行垂直排列 :

      Group(orientation= 'vertical', columns=2)
      
    • VSplit : 內容垂直排列,中間插入分隔條:

      Group(orientation= 'vertical', layout='split')
      

    配置視圖?

    前面介紹了如何使用Item和Group等類組織窗口界面中的內容,這一節我們來看看如何配置窗口本身的屬性。

    視圖類型?

    通過kind屬性可以修改View對象的顯示類型:

    • 'modal' : 模式窗口, 非即時更新
    • 'live' : 非模式窗口,即時更新
    • 'livemodal' : 模式窗口,即時更新
    • 'nonmodal' : 非模式窗口,非即時更新
    • 'wizard' : 向導類型
    • 'panel' : 嵌入到其它窗口中的面板,即時更新,非模式
    • 'subpanel'

    其中 'modal', 'live', 'livemodal', 'nonmodal' 四種類型的View都將采用窗口顯示其內容。所謂模式窗口,表示此窗口關閉之前,程序中的其它窗口都不能被激活。而即時更新則是指當窗口中的控件內容改變時,修改會立即反應到窗口所對應的模型數據上,非即時更新的窗口則會復制模型數據,所有的改變在模型副本上進行,只有當用戶確定修改(通常通過OK或者Apply按鈕)時,才會修改原始數據。

    'wizard'由一系列特定的向導窗口組成,屬于模式窗口,并且即時更新數據。

    'panel'和'subpanel' 則是嵌入到窗口中的面板,panel可以擁有自己的命令按鈕,而subpanel則沒有命令按鈕。

    命令按鈕?

    在對話框中經常可以看到 OK, Cacel, Apply 之類的按鈕,我們稱之為命令按鈕,它們完成所有對話框窗口都共同的操作。在TraitsUI中,這些按鈕可以通過View對象的buttons屬性進行設置,其值為要顯示的按鈕列表。

    TraitsUI定義了UndoButton, ApplyButton, RevertButton, OKButton, CancelButton等六個標準的命令按鈕,每個按鈕對應一個名字,在指定buttons屬性時,可以使用按鈕的類名或者其對應的名字。與按鈕類對應的名字就是類名除去Button,例如UndoButton對應為"Undo"。

    在 enthought.tratis.ui.menu 中還預定義了一些命令按鈕列表,方便直接使用:

    OKCancelButtons = ``[OKButton, CancelButton ]``
    ModalButtons = ``[ ApplyButton, RevertButton, OKButton, CancelButton, HelpButton ]``
    LiveButtons = ``[ UndoButton, RevertButton, OKButton, CancelButton, HelpButton ]``
    

    首頁目錄

    上一篇文章

    Traits-為Python添加類型定義

    下一篇文章

    Chaco-交互式圖表

    97av