<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            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-交互式圖表

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线