<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 第八章 將構件放入窗體中 1. [把窗口部件放入框架中](#A.2BYop6l1PjkOhO9mU.2BUWVoRme2Ti0-) 1. [框架的壽命](#A.2BaEZntnaEW.2F9UfQ-) 2. [使用框架](#A.2BT391KGhGZ7Y-) 3. [可選的框架類型](#A.2BU.2B.2BQCXaEaEZntnx7V4s-) 4. [使用分割窗](#A.2BT391KFIGUnJ6lw-) 5. [本章小結](#A.2BZyx64FwPftM-) 在你的wxPython中,所有的用戶交互行為都發生在一個窗口部件容器中,它通常被稱作窗口,在wxPython 中被稱為框架。在這一章中,我們將討論wxPython中的幾個不同樣式的框架。這個主要的wx.Frame有幾個不同的框架樣式,這些樣式可以改變wx.Frame的外觀。另外,wxPython提供了小型框架和實現多文檔界面的框架。框架可以使用分隔條來劃分為不同的部分,并且可以通過滾動條的使用來包含比框架本身大的面板(panel)。 ## 框架的壽命 我們將通過討論框架最基本的元素:創建和除去它們,來作為我們的開始。創建框架包括了解可以應用的所有樣式元素;框架的去除可能比你原本想像的要復雜。 ### 如何創建一個框架? 在本書中我們已經見過了許多的框架創建的例子,但是我們仍將再回顧一下框架創建的初步原則。 **創建一個簡單的框架** 框架是類wx.Frame的實例。例8.1顯示了一個非常簡單的框架創建的例子。 **例8.1** **創建基本的wx.Frame** ``` import wx if __name__ == '__main__': app = wx.PySimpleApp() frame = wx.Frame(None, -1, "A Frame", style=wx.DEFAULT_FRAME_STYLE, size=(200, 100)) frame.Show() app.MainLoop() ``` 上面的代碼創建一個帶有標題的框架,其大小是(200,100)。表8.1中的默認樣式提供了標準框架的裝飾如關閉框、最小化和最大化框。結果如圖8.1所示。 圖8.1 ![](https://box.kancloud.cn/2016-08-21_57b9960c7a240.gif) wx.Frame的構造函數類似于我們在第7章見到的其它窗口部件的構造函數: ``` wx.Frame(parent, id=-1, title="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="frame") ``` 這里有超過十余種之多的專用于wx.Frame的樣式標記,我們將在下一部分涵蓋它們。默認樣式為你提供了最小化和最大化框、系統下拉菜單、可調整尺寸的粗邊框和一個標題。 這里沒有與一個wx.Frame掛鉤的事件類型。但是,由于一個wx.Frame是你的屏幕上用戶最可能去關閉的元素,所以你通常想去為關閉事件定義一個處理器,以便子窗口和數據被妥善的處理。 **創建框架的子類** 你將很少直接創建wx.Frame的實例。正如我們在本書中所見過的其它例子一樣,一個典型的wxPython應用程序創建wx.Frame的子類并創建那些子類的實例。這是因為wx.Frame的獨特的情形——雖然它自身定義了很少的行為,但是帶有獨自的初始化程序的子類是放置有關你的框架的布局和行為的最合理的地方。不創建子類而構造你應用程序的特定的布局是有可能,但除了最簡單的應用程序以外,那是不容易的。例8.2展示了wx.Frame子類的例子。 **例8.2** **一個簡單的框架子類** ``` import wx class SubclassFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, 'Frame Subclass', size=(300, 100)) panel = wx.Panel(self, -1) button = wx.Button(panel, -1, "Close Me", pos=(15, 15)) self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button) self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) def OnCloseMe(self, event): self.Close(True) def OnCloseWindow(self, event): self.Destroy() if __name__ == '__main__': app = wx.PySimpleApp() SubclassFrame().Show() app.MainLoop() ``` 運行結果如圖8.2所示 圖8.2 ![](https://box.kancloud.cn/2016-08-21_57b9960c8e67b.gif) 我們在許多其它的例子中已經見過了這種基本的結構,因此讓我們來討論上面代碼中特定于框架的部分。wx.Frame.init方法與wx.Frame構造函數有相同的信息。子類自身的構造器除了self沒有其它參數,它允許你作為程序員去定義參數,所定義的參數將傳遞給其父類,并且使你可以不用重復指定與父類相同的參數。 同樣值得注意的是,框架的子窗口部件被放置在一個面板(panel)中。面板(panel)是類wx.Panel的實例,它是其它有較少功能的窗口部件的容器。你基本上應該使用一個wx.Panel作為你的框架的頂級子窗口部件。有一件事情就是,多層次的構造可以使得更多的代碼能夠重用,如相同的面板和布局可以被用于多個框架中。在框架中使用wx.Panel給了你一些對話框的功能。這些功能以成對的方式表現。其一是,在MS Windows操作系統下,wx.Panel實例的默認背景色以白色代替了灰色。其二,面板(panel)可以有一個默認的項目,該項目在當回車鍵被按下時自動激活,并且面板(panel)以與對話框大致相同的辦法響應tab鍵盤事件,以改變或選擇默認項目。 ### 有些什么不同的框架樣式? wx.Frame有許多的可能的樣式標記。通常,默認樣式就是你想要的,但也有一些有用的變種。我們將討論的第一組樣式控制框架的形狀和尺寸。盡管不是強制性的,但是這些標記應該被認為是互斥的——一個給定的框架應該只使用它們中的一個。表8.1說明了形狀和尺寸標記。 **表8.1 框架的形狀和尺寸標記** | | | | --- | --- | | wx.FRAME_NO_TASKBAR | 一個完全標準的框架,除了一件事:在Windows系統和別的支持這個特性的系統下,它不顯示在任務欄中。當最小化時,該框架圖標化到桌面而非任務欄。 | | wx.FRAME_SHAPED | 非矩形的框架。框架的確切形狀使用[SetShape](http://wiki.woodpecker.org.cn/moin/SetShape)()方法來設置。窗口的形狀將在本章后面部分討論。 | | wx.FRAME_TOOL_WINDOW | 該框架的標題欄比標準的小些,通常用于包含多種工具按鈕的輔助框架。在Windows操作系統下,工具窗口將不顯示在任務欄中。 | | wx.ICONIZE | 窗口初始時將被最小化顯示。這個樣式僅在Windows系統中起作用。 | | wx.MAXIMIZE | 窗口初始時將被最大化顯示(全屏)。這個樣式僅在Windows系統中起作用。 | | wx.MINIMIZE | 同wx.ICONIZE。 | 上面這組樣式中,屏幕畫面最需要的樣式是wx.FRAME_TOOL_WINDOW。圖8.3顯示了一個小的結合使用了wx.FRAME_TOOL_WINDOW、wx.CAPTION和wx.SYSTEM_MENU樣式的例子。 **圖8.3** ![](https://box.kancloud.cn/2016-08-21_57b9960ca2c65.gif) 這里有兩個互斥的樣式,它們控制一個框架是否位于別的框架的上面,無論別的框架是否獲得了焦點。這對于那些小的不是始終可見的對話框是有用的。表8.2說明了這兩個樣式。最后,這還有一些用于放置在你的窗口上的裝飾。如果你沒有使用默認樣式,那么這些裝飾將不被自動放置到你的窗口上,你必須添加它們,否則容易導致窗口不能關閉或移動。表8.3給出了這些裝飾的列表。 **表8.2** **針對窗口漂浮行為的樣式** | | | | --- | --- | | wx.FRAME_FLOAT_ON_PARENT | 框架將漂浮在其父窗口(僅其父窗口)的上面。(很明顯,要使用這個樣式,框架需要有一個父窗口)。其它的框架可以遮蓋這個框架。 | | wx.STAY_ON_TOP | 該框架將始終在系統中其它框架的上面。(如果你有多個框架使用了這個樣式,那么它們將相互重疊,但對于系統中其它的框架,它們仍在上面。) | 默認的樣式wx.DEFAULT_FRAME_STYLE等同于wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.CLOSE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU |wx.CAPTION。這個樣式創建了一個典型的窗口,你可以調整大小,最小化,最大化,或關閉。一個很好的主意就是當你想要使用除默認樣式以外的樣式時,將默認樣式與其它的樣式組合在一起,以確保你有正確的一套裝飾。例如,要創建一個工具框架,你可以使用style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_TOOL_WINDOW。記住,你可以使用^操作符來去掉不要的樣式。 **表8.3 用于裝飾窗口的樣式** | | | | --- | --- | | wx.CAPTION | 給窗口一個標題欄。如果你要放置最大化框、最小化框、系統菜單和上下文幫助,那么你必須包括該樣式。 | | wx.FRAME_EX_CONTEXTHELP | 這是用于Windows操作系統的,它在標題欄的右角放置問號幫助圖標。這個樣式是與wx.MAXIMIZE_BOX和WX.MINIMIZE_BOX樣式互斥的。它是一個擴展的樣式,并且必須使用兩步來創建,稍后說明。 | | wx.FRAME_EX_METAL | 在Mac OS X上,使用這個樣式的框架有一個金屬質感的外觀。這是一個附加樣式,必須使用[SetExtraStyle](http://wiki.woodpecker.org.cn/moin/SetExtraStyle)方法來設置。 | | wx.MAXIMIZE_BOX | 在標題欄的標準位置放置一個最大化框。 | | wx.MINIMIZE_BOX | 在標題欄的標準位置放置一個最小化框。 | | wx.CLOSE_BOX | 在標題欄的標準位置放置一個關閉框。 | | wx.RESIZE_BORDER | 給框架一個標準的可以手動調整尺寸的邊框。 | | wx.SIMPLE_BORDER | 給框架一個最簡單的邊框,不能調整尺寸,沒有其它裝飾。該樣式與所有其它裝飾樣式是互斥的 | | wx.SYSTEM_MENU | 在標題欄上放置一個系統菜單。這個系統菜單的內容與你所使用的裝飾樣式有關。例如,如果你使用wx.MINIMIZE_BOX,那么系統菜單項就有“最小化”選項。 | ### 如何創建一個有額外樣式信息的框架? wx.FRAME_EX_CONTEXTHELP是一個擴展樣式,意思是樣式標記的值太大以致于不能使用通常的構造函數來設置(因為底層C++變量類型的特殊限制)。通常你可以在窗口部件被創建后,使用[SetExtraStyle](http://wiki.woodpecker.org.cn/moin/SetExtraStyle)方法來設置額外的樣式,但是某些樣式,比如wx.FRAME_EX_CONTEXTHELP,必須在本地UI(用戶界面)對象被創建之前被設置。在wxPython中,這需要使用稍微笨拙的方法來完成,即分兩步構建。之后標題欄中帶有我們熟悉的問號圖標的框架就被創建了。如圖8.4所示。 圖8.4 ![](https://box.kancloud.cn/2016-08-21_57b9960cb6354.gif) 標記值必須使用[SetExtraStyle](http://wiki.woodpecker.org.cn/moin/SetExtraStyle)()方法來設置。有時,額外樣式信息必須在框架被實例化前被設置,這就導致了一個問題:你如何對于一個不存在的實例調用一個方法?在接下來的部分,我們將展示實現這種操作的兩個機制。 **添加額外樣式信息** 在wxPython中,額外樣式信息在創建之前通過使用專門的類wx.[PreFrame](http://wiki.woodpecker.org.cn/moin/PreFrame)來被添加,它是框架的一種局部實例。你可以在預框架(preframe)上設置額外樣式位,然后使用這個預框架(preframe)來創建實際的框架。例8.3顯示了在一個子類的構造器中如何完成這兩步(two-step)的構建。注意,在wxPython中它實際上是三步(在C++ wxWidgets工具包中,它是兩步(two-step),我們只是沿用這個叫法而已)。 **例8.3** ``` import wx class HelpFrame(wx.Frame): def __init__(self): pre = wx.PreFrame() #1 預構建對象 pre.SetExtraStyle(wx.FRAME_EX_CONTEXTHELP) pre.Create(None, -1, "Help Context", size=(300, 100), style=wx.DEFAULT_FRAME_STYLE ^ (wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX)) #2 創建框架 self.PostCreate(pre) #3 底層C++指針的傳遞 if __name__ == '__main__': app = wx.PySimpleApp() HelpFrame().Show() app.MainLoop() ``` **#1** 創建wx.[PreFrame](http://wiki.woodpecker.org.cn/moin/PreFrame)()的一個實例(關于對話框,這有一個類似的wx.[PreDialog](http://wiki.woodpecker.org.cn/moin/PreDialog)()——其它的wxWidgets窗口部件有它們自己的預類)。在這個調用之后,你可以做你需要的其它初始化工作。 **#2** 調用Create()方法創建框架。 **#3** 這是特定于wxPython的,并且不由C++完成。[PostCreate](http://wiki.woodpecker.org.cn/moin/PostCreate)方法做一些內部的內務處理,它實例化一個你在第一步中創建的封裝了C++的對象。 **添加額外樣式信息的通用方法** 先前的算法有點笨拙,但是它可以被重構得容易一點,以便于管理維護。第一步是創建一個公用函數,它可以管理任何分兩步的創建。例8.4提供了一個例子,它使用Python的內省性能來調用以變量形式被傳遞的函數。這個例子用于在Python的一個新的框架實例化期間的init方法中被調用。 **例8.4** **一個公用的兩步式創建函數** ``` def twoStepCreate(instance, preClass, preInitFunc, *args,**kwargs): pre = preClass() preInitFunc(pre) pre.Create(*args, **kwargs) instance.PostCreate(pre) ``` 在例8.4中,函數要求三個必須的參數。instance參數是實際被創建的實例。preClass參數是臨時的預類的類對象——對框架預類是wx.[PreFrame](http://wiki.woodpecker.org.cn/moin/PreFrame)。preInitFunc是一個函數對象,它通常作為回調函數用于該實例的初始化。這三個參數之后,我們可以再增加任意數量的其它可選參數。 這個函數的第一行,pre = preClass(),內省地實例化這個預創建對象,使用作為參數傳遞過來的類對象。下面一行根據參數preInitFunc內省地調用回調函數,它通常設置擴展樣式標記。然后pre.Create()方法被調用,它使用了可選的參數。最后,[PostCreate](http://wiki.woodpecker.org.cn/moin/PostCreate)方法被調用來將內在的值從pre移給實例。至此,instance參數已經完全被創建了。假設twoStepCreate已被導入,那么上面的公用函數可以如例8.5被使用。 **例8.5** **另一個兩步式的創建,使用了公用函數** ``` import wx class HelpFrame(wx.Frame): def __init__(self, parent, ID, title,pos=wx.DefaultPosition, size=(100,100),style=wx.DEFAULT_DIALOG_STYLE): twoStepCreate(self, wx.PreFrame, self.preInit, parent, id, title, pos, size, style) def preInit(self, pre): pre.SetExtraStyle(wx.FRAME_EX_CONTEXTHELP) ``` 類wx.[PreFrame](http://wiki.woodpecker.org.cn/moin/PreFrame)和函數self.preInit被傳遞給公用函數,并且preInit方法被定義為回調函數。 ### 當關閉一個框架時都發生了什么? 當你關閉一個框架時,它最終消失了。除非這個框架被明確地告訴不關閉。換句話說,那關閉不是直接了當的。在wxPython的窗口部件關閉體系之后的用意是,給正在關閉的窗口部件充足的機會來關閉或釋放它所占用任何非wxPython資源。如果你占用了某種昂貴的外部資源,如一個大的數據結構或一個數據庫連接,那么該意圖是特別受歡迎的。 誠然,在C++ wxWidgets世界里,由于C++不為你管理內在分配的清理工作,管理資源是更嚴肅的問題。在wxPython中,對于多步的關閉過程的顯式需求就很少,但它對于在過程中使用額外的鉤子仍然是有用的。(隨便說一下,我們在這一節中從單詞“框架”切換到單詞“窗口部件”是故意的——因為在本節中的所有內容都適用于所有頂級窗口部件,如框架或對話框)。 **何時用戶觸發關閉過程** 關閉過程最常由用戶觸發,如敲擊一個關閉框或選擇系統菜單中的關閉項或當應用程序響應其它某個事件而調用框架的Close方法。當上述情況發生時,wxPython架構引發一個EVT_CLOSE事件。像wxPython 架構中的其它別的事件一樣,你可以在綁定一個事件處理器以便一個EVT_CLOSE事件發生時調用。 如果你不聲明你自己的事件處理器,那么默認的行為將被調用。默認的行為對于框架和對話框是不同的。 1、默認情況下,框架處理器調用Destroy()方法并刪除該框架和它的所有的組件。 2、默認情況下,對話框的關閉處理器不銷毀該對話框——它僅僅模擬取消按鈕的按下,并隱藏對話框。該對話框對象仍繼續存在在內存中。因此,如果需要的話,應用程序可以從它的數據輸入部件獲取值。當應用程序完成了對對話框的使用后,應該調用對話框的Destroy()方法。 如果你編寫你自己的關閉處理器,那么你可以使用它來關閉或刪除任何外部的資源,但是,如果你選擇去刪除框架的話,顯式地調用Destroy()方法是你的責任。盡管Destroy()經常被Close()調用,但是只調用Close()方法不能保證框架的銷毀。在一定的情形下,決定不銷毀框架是完全可以的,如當用戶取消了關閉。然而,你仍然需要一個方法來銷毀該框架。如果你選擇不去銷毀窗口,那么調用關閉事件的wx.[CloseEvent](http://wiki.woodpecker.org.cn/moin/CloseEvent).Veto()方法來通知相關部分:框架拒絕關閉,是一個好的習慣。 如果你選擇在你的程序的別處而非關閉處理器中關閉你的框架,例如從一個不同的用戶事件像一個菜單項,那么我們建議使用的機制是調用框架的Close()方法。這將啟動一個和系統關閉行為相同的過程。如果你要確保框架一定被刪除,那么你可以直接調用Destroy()方法;然而,如果你這樣做了,可能會導致框架所管理的資源或數據沒有被釋放或保存。 **什么時候系統觸發關閉過程** 如果關閉事件是由系統自己觸發的,對于系統關閉或類似情況,你也有一種辦法管理該事件。wx.App 類接受一個EVT_QUERY_END_SESSION事件,如果需要的話,該事件使你能夠否決應用程序的關閉,如果所有運行的應用已經批準了系統或GUI環境的關閉的話,那么隨后會有一個EVT_END_SESSION事件。你選擇去否決關閉的行為是與依賴于具體系統的。 最后,值得注意的是,調用一個窗口部件的Destroy()方法不意味該部件被立即銷毀。銷毀實際上是當事件循環在未來空閑時(任何未被處理的事件被處理之后)才被處理的。這就防止了處理已不存在的窗口部件的事件。 在接下來的兩節,我們的討論將從一個框架的生命周期切換到在框架生命周期里,你能夠用框架來做些什么。 ## 使用框架 框架包含了許多方法和屬性。其中最重要的是那些查找框架中任意窗口部件的方法,和滾動框架中內容的方法。在這一節,我們將討論如何實現這些。 ### wx.Frame有那些方法和屬性? 這部分中的表包含了wx.Frame和它的父類wx.Window的最基本的屬性。這些屬性和方法的許多在本書中的其它地方有更詳細的說明。表8.4包含了wx.Frame的一些公共的可讀、可修改的屬性。 **表8.4** **wx.Frame的公共屬性** | | | | --- | --- | | [GetBackgroundColor](http://wiki.woodpecker.org.cn/moin/GetBackgroundColor)(),[SetBackgroundColor](http://wiki.woodpecker.org.cn/moin/SetBackgroundColor)(wx.Color) | 背景色是框架中沒有被其子窗口部件覆蓋住的那些部分的顏色。你可以傳遞一個wx.Color或顏色名給設置方法。任何傳遞給需要顏色的wxPython方法的字符串,都被解釋為對函數wx.[NamedColour](http://wiki.woodpecker.org.cn/moin/NamedColour)()的調用。 | | [GetId](http://wiki.woodpecker.org.cn/moin/GetId)(),[SetId](http://wiki.woodpecker.org.cn/moin/SetId)(int) | 返回或設置窗口部件的標識符。 | | [GetMenuBar](http://wiki.woodpecker.org.cn/moin/GetMenuBar)(),[SetMenuBar](http://wiki.woodpecker.org.cn/moin/SetMenuBar)(wx.[MenuBar](http://wiki.woodpecker.org.cn/moin/MenuBar)) | 得到或設置框架當前使用的的菜單欄對象,如果沒有菜單欄,則返回None。 | | [GetPosition](http://wiki.woodpecker.org.cn/moin/GetPosition)(),[GetPositionTuple](http://wiki.woodpecker.org.cn/moin/GetPositionTuple)(),[SetPosition](http://wiki.woodpecker.org.cn/moin/SetPosition)(wx.Point) | 以一個wx.Point或Python元組的形式返回窗口左上角的x,y的位置。對于頂級窗口,該位置是相對于顯示區域的坐標,對于子窗口,該位置是相對于父窗口的坐標。 | [GetSize](http://wiki.woodpecker.org.cn/moin/GetSize)() [GetSizeTuple](http://wiki.woodpecker.org.cn/moin/GetSizeTuple)() [SetSize](http://wiki.woodpecker.org.cn/moin/SetSize)(wx.Size):C++版的get*或set*方法被覆蓋。默認的get*或set*使用一個wx.Size對象。[GetSizeTuple](http://wiki.woodpecker.org.cn/moin/GetSizeTuple)()方法以一個Python元組的形式返回尺寸。也可以參看訪問該信息的另外的方法[SetDimensions](http://wiki.woodpecker.org.cn/moin/SetDimensions)()。 [GetTitle](http://wiki.woodpecker.org.cn/moin/GetTitle)() [SetTitle](http://wiki.woodpecker.org.cn/moin/SetTitle)(String):得到或設置框架標題欄的字符串。 表8.5顯示了一些wx.Frame的非屬性類的更有用的方法。其中要牢記的是Refresh(),你可以用它來手動觸發框架的重繪。 **表8.5** **wx.Frame的方法** Center(direction=wx.BOTH):框架居中(注意,非美語的拼寫Centre,也被定義了的)。參數的默認值是wx.BoTH,在此情況下,框是在兩個方向都居中的。參數的值若是wx.HORIZONTAL或wx.VERTICAL,表示在水平或垂直方向居中。 Enable(enable=true):如果參數為true,則框架能夠接受用戶的輸入。如果參數為False,則用戶不能在框架中輸入。相對應的方法是Disable()。 [GetBestSize](http://wiki.woodpecker.org.cn/moin/GetBestSize)():對于wx.Frame,它返回框架能容納所有子窗口的最小尺寸。 Iconize(iconize):如果參數為true,最小化該框架為一個圖標(當然,具體的行為與系統有關)。如果參數為False,圖標化的框架恢復到正常狀態。 [IsEnabled](http://wiki.woodpecker.org.cn/moin/IsEnabled)():如果框架當前有效,則返回True。 [IsFullScreen](http://wiki.woodpecker.org.cn/moin/IsFullScreen)():如果框架是以全屏模式顯示的,則返回True,否則False。細節參看[ShowFullScreen](http://wiki.woodpecker.org.cn/moin/ShowFullScreen)。 [IsIconized](http://wiki.woodpecker.org.cn/moin/IsIconized)():如果框架當前最小化為圖標了,則返回True,否則False。 [IsMaximized](http://wiki.woodpecker.org.cn/moin/IsMaximized)():如果框架當前是最大化狀態,則返回True,否則False。 [IsShown](http://wiki.woodpecker.org.cn/moin/IsShown)():如果框架當前可見,則返回True。 [IsTopLevel](http://wiki.woodpecker.org.cn/moin/IsTopLevel)():對于頂級窗口部件如框架或對話框,總是返回True,對于其它類型的窗口部件返回False。 Maximize(maximize):如果參數為True,最大化框架以填充屏幕(具體的行為與系統有關)。這與敲擊框架的最大化按鈕所做的相同,這通常放大框架以填充桌面,但是任務欄和其它系統組件仍然可見。 Refresh(eraseBackground=True, rect=None):觸發該框架的重繪事件。如果rect是none,那么整個框架被重畫。如果指定了一個矩形區域,那么僅那個矩形區域被重畫。如果eraseBackground為True,那么這個窗口的北影也將被重畫,如果為False,那么背景將不被重畫。 [SetDimensions](http://wiki.woodpecker.org.cn/moin/SetDimensions)(x, y, width, height, sizeFlags=wx.SIZE_AUTO):使你能夠在一個方法調用中設置窗口的尺寸和位置。位置由參數x和y決定,尺寸由參數width和height決定。前四個參數中,如果有的為-1,那么這個-1將根據參數sizeFlags的值作相應的解釋。表8.6包含了參數sizeFlags的可能取值。 Show(show=True):如果參數值為True,導致框架被顯示。如果參數值為False,導致框架被隱藏。Show(False)等同于Hide()。 [ShowFullScreen](http://wiki.woodpecker.org.cn/moin/ShowFullScreen)(show, style=wx.FULLSCREEN_ALL):如果布爾參數是True,那么框架以全屏的模式被顯示——意味著框架被放大到填充整個顯示區域,包括桌面上的任務欄和其它系統組件。如果參數是False,那么框架恢復到正常尺寸。style參數是一個位掩碼。默認值wx.FULLSCREEN_ALL指示wxPython當全屏模式時隱藏所有窗口的所有樣式元素。后面的這些值可以通過使用按位運算符來組合,以取消全屏模式框架的部分裝飾:wx.FULLSCREEN_NOBORDER, wx.FULLSCREEN_NOCAPTION, wx.FULLSCREEN_NOMENUBAR, wx.FULLSCREEN_NOSTATUSBAR, wx.FULLSCREEN_NOTOOLBAR。 表8.5中說明的[SetDimensions](http://wiki.woodpecker.org.cn/moin/SetDimensions)()方法在用戶將一個尺寸指定為-1時,使用尺寸標記的一個位掩碼來決定默認行為。表8.6說明了這些標記。 這些方法沒有涉及框架所包含的孩子的位置問題。這個問題要求框架的孩子自已去說明它。 **表8.6** **關于[SetDimensions](http://wiki.woodpecker.org.cn/moin/SetDimensions)方法的尺寸標記** wx.ALLOW_MINUS_ONE:一個有效的位置或尺寸。 wx.SIZE_AUTO:轉換為一個wxPython默認值。 wx.SIZE_AUTO_HEIGHT:一個有效的高度,或一個wxPython默認高度。 wx.SIZE_AUTO_WIDTH:一個有效的寬度,或一個wxPython默認寬度。 wx.SIZE_USE_EXISTING:使用現有的尺寸。 ### 如何查找框架的子窗口部件? 有時候,你將需要查找框架或面板(panel)上的一個特定的窗口部件,并且你沒有它的相關引用。如第6章所示的這種情況的一個公用的應用程序,它查找與所選菜單相關的實際的菜單項對象(因為事件不包含對它的一個引用)。另一種情況就是,當你想基于一個項的事件去改變系統中其它任一窗口部件的狀態時。例如,你可能有一個按鈕和一個菜單項,它們互相改變彼此的開關狀態。當按鈕被敲擊時,你需要去得到菜單項以觸發它。例8.6顯示了一個摘自第7章的一個小的例子。在這個代碼中,[FindItemById](http://wiki.woodpecker.org.cn/moin/FindItemById)()方法用來去獲得與事件對象所提供的ID相關的菜單項。該項的標簽被用來驅動所要求的顏色的改變。 **例8.6** **通過ID查找項目的函數** ``` def OnColor(self, event): menubar = self.GetMenuBar() itemId = event.GetId() item = menubar.FindItemById(itemId) color = item.GetLabel() self.sketch.SetColor(color) ``` 在wxPython中,有三種查找子窗口部件的方法,它們的行為都很相似。這些方法對任何作為容器的窗口部件都是適用的,不單單是框架,還有對話框和面板(panel)。你可以通過內部的wxPython ID查尋一個窗口部件,或通過傳遞給構造函數的名字(在name參數中),或通過文本標簽來查尋。文本標簽被定義為相應窗口部件的標題,如按鈕和框架。 這三種方法是: * 1.wx.[FindWindowById](http://wiki.woodpecker.org.cn/moin/FindWindowById)(id, parent=None) 1.wx.[FindWindowByName](http://wiki.woodpecker.org.cn/moin/FindWindowByName)(name, parent=None) 1.wx.[FindWindowByLabel](http://wiki.woodpecker.org.cn/moin/FindWindowByLabel)(label, parent=None) 這三種情況中,parent參數可以被用來限制為對一個特殊子層次的搜索(也就是,它等同于父類的Find方法)。還有,[FindWindowByName](http://wiki.woodpecker.org.cn/moin/FindWindowByName)()首先按name參數查找,如果沒有發現匹配的,它就調用[FindWindowByLabel](http://wiki.woodpecker.org.cn/moin/FindWindowByLabel)()去查找一個匹配。 ### 如何創建一個帶有滾動條的框架? 在wxPython中,滾動條不是框架本身的一個元素,而是被類wx.[ScrolledWindow](http://wiki.woodpecker.org.cn/moin/ScrolledWindow)控制。你可以在任何你要使用wx.Panel的地方使用wx.[ScrolledWindow](http://wiki.woodpecker.org.cn/moin/ScrolledWindow),并且滾動條移動所有在滾動窗口中的項目。圖8.5和圖8.6顯示了滾動條,包括它的初始狀態和滾動后的狀態。從圖8.5到圖8.6,左上的按鈕移出了視野,右下的按鈕移進了視野。 在這一節,我們將討論如何去創建一個帶有滾動條的窗口以及如何在你的程序中處理滾動行為。 **圖8.5** ![](https://box.kancloud.cn/2016-08-21_57b9960cc97da.gif) **圖8.6** ![](https://box.kancloud.cn/2016-08-21_57b9960cc97da.gif) **如何創建滾動條** 例8.7顯示了用于創建滾動窗口的代碼。 **例8.7** **創建一個簡單的滾動窗口** ``` import wx class ScrollbarFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, 'Scrollbar Example', size=(300, 200)) self.scroll = wx.ScrolledWindow(self, -1) self.scroll.SetScrollbars(1, 1, 600, 400) self.button = wx.Button(self.scroll, -1, "Scroll Me", pos=(50, 20)) self.Bind(wx.EVT_BUTTON, self.OnClickTop, self.button) self.button2 = wx.Button(self.scroll, -1, "Scroll Back", pos=(500, 350)) self.Bind(wx.EVT_BUTTON, self.OnClickBottom, self.button2) def OnClickTop(self, event): self.scroll.Scroll(600, 400) def OnClickBottom(self, event): self.scroll.Scroll(1, 1) if __name__ == '__main__': app = wx.PySimpleApp() frame = ScrollbarFrame() frame.Show() app.MainLoop() ``` wx.[ScrolledWindow](http://wiki.woodpecker.org.cn/moin/ScrolledWindow)的構造函數幾乎與wx.Panel的相同: ``` wx.ScrolledWindow(parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.HSCROLL | wx.VSCROLL, name="scrolledWindow") ``` 所有的這些屬性的行為都如你所愿,盡管size屬性是它的父親中的面板的物理尺寸,而非滾動窗口的邏輯尺寸。 **指定滾動區域的尺寸** 有幾個自動指定滾動區域尺寸的方法。手工指定最多的方法如例8.1所示,使用了方法[SetScrollBars](http://wiki.woodpecker.org.cn/moin/SetScrollBars): ``` SetScrollbars(pixelsPerUnitX, pixelsPerUnitY, noUnitsX, noUnitsY, xPos=0, yPos=0, noRefresh=False) ``` 其中關鍵的概念是滾動單位,它是滾動條的一次移動所引起的窗口中的轉移距離。前面的兩個參數pixelsPerUnitX和PixelsPerUnitY使你能夠在兩個方向設置滾動單位的大小。接下來的兩個參數noUnitsX和noUnitsY使你能夠按滾動單位設置滾動區域的尺寸。換句話說,滾動區域的象素尺寸是(pixelsPerUnitX* noUnitsX, pixelsPerUnitY * noUnitsY)。例8.7通過將滾動單位設為1像素而避免了可能造成的混淆。參數xPos和yPos以滾動單位(非像素)為單位,它設置滾動條的初始位置,如果參數noRefresh為true,那么就阻止了在因[SetScrollbars](http://wiki.woodpecker.org.cn/moin/SetScrollbars)()的調用而引起的滾動后的窗口的自動刷新。 還有另外的三個方法,你可以用來設置滾動區域的尺寸,然后單獨設置滾動率。你可能發現這些方法更容易使用,因為它們使你能夠更直接地指定尺寸。你可以如下以像素為單位使用滾動窗口的[SetVirtualSize](http://wiki.woodpecker.org.cn/moin/SetVirtualSize)()方法來直接設置尺寸。 ``` self.scroll.SetVirtualSize((600, 400)) ``` 使用方法[FitInside](http://wiki.woodpecker.org.cn/moin/FitInside)(),你可以在滾動區域中設置窗口部件,以便滾動窗口綁定它們。這個方法設置滾動窗口的邊界,以使滾動窗口剛好適合其中的所有子窗口: ``` self.scroll.FitInside() ``` 通常使用[FitInside](http://wiki.woodpecker.org.cn/moin/FitInside)()的情況是,當在滾動窗口中正好有一個窗口部件(如文本域),并且該窗口部件的邏輯尺寸已被設置。如果我們在例8.7中使用了[FitInside](http://wiki.woodpecker.org.cn/moin/FitInside)(),那么一個更小的滾動區域將被創建,因為該區域將正好匹配右下按鈕的邊緣,而沒有多余的內邊距。 最后,如果滾動窗口中有一個sizer設置,那么使用[SetSizer](http://wiki.woodpecker.org.cn/moin/SetSizer)()設置滾動區域為sizer所管理的窗口部件的尺寸。這是在一個復雜的布局中最常用的機制。關于sizer的更多細節參見第11章。 對于上述所有三種機制,滾動率需要去使用[SetScrollRate](http://wiki.woodpecker.org.cn/moin/SetScrollRate)()方法單獨設置,如下所示: ``` self.scroll.SetScrollRate(1, 1) ``` 參數分別是x和y方向的滾動單位尺寸。大于0的尺寸都是有效的。 **滾動條事件** 在例8.7中的按鈕事件處理器,使用Scroll()方法程序化地改變滾動條的位置。這個方法需要滾動窗口的x和y坐標,使用的是滾動單位。 在第7章中,我們答應了你可以捕獲的來自滾動條的事件列表,因為它們也被用來去控制滑塊。表8.7列出了所有被滾動窗口內在處理的滾動事件。通常,許多你不會用到,除非你建造自定義窗口部件。 **表8.7 滾動條的事件** | | | | --- | --- | | EVT_SCROLL | 當任何滾動事件被觸發時發生。 | | EVT_SCROLL_BOTTOM | 當用戶移動滾動條到它的范圍的最末端時觸發(底邊或右邊,依賴于方向)。 | | EVT_SCROLL_ENDSCROLL | 在微軟的Windows中,任何滾動會話的結束都將觸發該事件,不管是因鼠標拖動或按鍵按下。 | | EVT_SCROLL_LINEDOWN | 當用戶向下滾動一行時觸發。 | | EVT_SCROLL_LINEUP | 當用戶向上滾動一行時觸發。 | | EVT_SCROLL_PAGEDOWN | 當用戶向下滾動一頁時觸發。 | | EVT_SCROLL_PAGEUP | 當用戶向上滾動一頁時觸發。 | | EVT_SCROLL_THUMBRELEASE | 用戶使用鼠標拖動滾動條滾動不超過一頁的范圍,并釋放鼠標后,觸發該事件。 | | EVT_SCROLL_THUMBTRACK | 滾動條在一頁內被拖動時不斷的觸發。 | | EVT_SCROLL_TOP | 當用戶移動滾動條到它的范圍的最始端時觸發,可能是頂端或左邊,依賴于方向而定。 | 行和頁的準確定義依賴于你所設定的滾動單位,一行是一個滾動單位,一頁是滾動窗口中可見部分的全部滾動單位的數量。對于表中所列出的每個EVT_SCROLL*事件,都有一個相應的EVT_SCROLLWIN*事件(它們由wx.[ScrolledWindow](http://wiki.woodpecker.org.cn/moin/ScrolledWindow)產生)來回應。 還有一個wxPython的特殊的滾動窗口子類:wx.lib.scrolledpanel.[ScrolledPanel](http://wiki.woodpecker.org.cn/moin/ScrolledPanel),它使得你能夠在面板上自動地設置滾動,該面板使用一個sizer來管理子窗口部件的布局。wx.lib.scrolledpanel.[ScrolledPanel](http://wiki.woodpecker.org.cn/moin/ScrolledPanel)增加的好處是,它讓用戶能夠使用tab鍵來在子窗口部件間切換。面板自動滾動,使新獲得焦點的窗口部件進入視野。要使用wx.lib.scrolledpanel.[ScrolledPanel](http://wiki.woodpecker.org.cn/moin/ScrolledPanel),就要像一個滾動窗口一樣聲明它,然后,在所有的子窗口被添加后,調用下面的方法: ``` SetupScrolling(self, scroll_x=True, scroll_y=True, rate_x=20, rate_y=20) ``` rate_x和rate_y是窗口的滾動單位,該類自動根據sizer所計算的子窗口部件的尺寸設定虛擬尺寸(virtual size)。 記住,當確定滾動窗口中的窗口部件的位置的時候,該位置總是窗口部件的物理位置,它相對于顯示器中的滾動窗口的實際原點,而非窗口部件相對于顯示器虛擬尺寸(virtual size)的邏輯位置。這始終是成立的,即使窗口部件不再可見。例如,在敲擊了圖8.5中的Scroll Me按鈕后,該按鈕所報告的它的位置是(-277,-237)。如果這不的你所想要的,那么使用[CalcScrolledPosition](http://wiki.woodpecker.org.cn/moin/CalcScrolledPosition)(x,y)和。[CalcUnscrolledPosition](http://wiki.woodpecker.org.cn/moin/CalcUnscrolledPosition)(x, y)方法在顯示器坐標和邏輯坐標之間切換。在這兩種情況中,在按鈕敲擊并使滾動條移動到底部后,你傳遞指針的坐標,并且滾動窗口返回一個(x,y)元組,如下所示: ``` CalcUnscrolledPostion(-277, -237) # ``` ## 可選的框架類型 框架不限于其中帶有窗口部件的普通的矩形,它可以呈現其它的形狀。你也可以創建MDI(多文檔界面)框架,它其中包含別的框架。或者你也可以去掉框架的標題欄,并且仍然可以使用戶能拖動框架。 ### 如何創建一個MDI框架? 還記得MDI嗎?許多人都不記得了。MDI是微軟90年代初的創新,它使得一個應用程序中的多個子窗口能被一個單一的父窗口控制,本質上為每個應用程序提供了一個獨立的桌面。在大多數應用程序中,MDI要求應用程序中的所有窗口同時最小化,并保持相同的z軸次序(相對系統中的其它部分)。我們建議僅當用戶期望同時看到所有的應用程序窗口的情況下使用MDI,例如一個游戲。圖8.7顯示了一個典型的MDI環境。 在wxPython中MDI是被支持的,在Windows操作系統下通過使用本地窗口部件來實現MDI,在其它的操作系統中通過模擬子窗口實現MDI。例8.8提供了一簡單的MDI的例子。 **圖8.7** ![](https://box.kancloud.cn/2016-08-21_57b9960ce4384.gif) **例8.8** **如何創建一個MDI窗口** ``` import wx class MDIFrame(wx.MDIParentFrame): def __init__(self): wx.MDIParentFrame.__init__(self, None, -1, "MDI Parent", size=(600,400)) menu = wx.Menu() menu.Append(5000, " Window") menu.Append(5001, "E ") menubar = wx.MenuBar() menubar.Append(menu, " ") self.SetMenuBar(menubar) self.Bind(wx.EVT_MENU, self.OnNewWindow, id=5000) self.Bind(wx.EVT_MENU, self.OnExit, id=5001) def OnExit(self, evt): self.Close(True) def OnNewWindow(self, evt): win = wx.MDIChildFrame(self, -1, "Child Window") win.Show(True) if __name__ == '__main__': app = wx.PySimpleApp() frame = MDIFrame() frame.Show() app.MainLoop() ``` MDI的基本概念是十分簡單的。父窗口是wx.MDIParentFrame的一個子類,子窗口如同任何其它的wxPython窗口部件一樣被添加,除了它們是wx.MDIChildFrame的子類。wx.MDIParentFrame的構造函數與wx.Frame的基本相同,如下所示: ``` wx.MDIParentFrame(parent, id, title, pos = wx.DefaultPosition, size=wxDefaultSize, style=wx.DEFAULT_FRAME_STYLE | wx.VSCROLL | wx.HSCROLL, name="frame") ``` 不同的一點是wx.MDIParentFrame在默認情況下有滾動條。wx.MDIChildFrame的構造函數是相同的,除了它沒有滾動條。如例8.8所示,添加一個子框架是通過創建一個以父框架為父親的框架來實現的。 你可以通過使用父框架的Cascade()或Tile()方法來同時改變所有子框架的位置和尺寸,它們模擬相同名字的菜單項。調用Cascade(),導致一個窗口顯示在其它的上面,如圖8.7的所示,而Tile()使每個窗口有相同的尺寸并移動它們以使它們不重疊。要以編程的方式在子窗口中移動焦點,要使用父親的方法[ActivateNext](http://wiki.woodpecker.org.cn/moin/ActivateNext)()和[ActivatePrevious](http://wiki.woodpecker.org.cn/moin/ActivatePrevious)() ### 什么是小型框架,我們為何要用它? 小型框架是一個有兩個例外的矩形框架:它有一個較小的標題區域,并且在微軟的Windows下或GTK下,它不在任務欄中顯示。圖8.8顯示了一個較小標題域的一個例子。 **圖8.8** **一個小型框架** ![](https://box.kancloud.cn/2016-08-21_57b9960d36932.gif) 創建小型框架的代碼基本上等同于創建一個矩形框架,唯一的不同是父類是wx.[MiniFrame](http://wiki.woodpecker.org.cn/moin/MiniFrame)。例8.9顯示了這個代碼。 **例8.9** **創建一個小型框架** ``` import wx class MiniFrame(wx.MiniFrame): def __init__(self): wx.MiniFrame.__init__(self, None, -1, 'Mini Frame', size=(300, 100)) panel = wx.Panel(self, -1, size=(300, 100)) button = wx.Button(panel, -1, "Close Me", pos=(15, 15)) self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button) self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) def OnCloseMe(self, event): self.Close(True) def OnCloseWindow(self, event): self.Destroy() if __name__ == '__main__': app = wx.PySimpleApp() MiniFrame().Show() app.MainLoop() ``` wx.[MiniFrame](http://wiki.woodpecker.org.cn/moin/MiniFrame)的構造函數等同于wx.Frame的,然而,wx.[MiniFrame](http://wiki.woodpecker.org.cn/moin/MiniFrame)支持額外的樣式標記。如表8.8所示。 **表8.8** **wx.[MiniFrame](http://wiki.woodpecker.org.cn/moin/MiniFrame)的樣式標記** | | | | --- | --- | | wx.THICK_FRAME | 在Windows或Motif下,使用粗邊框繪制框架。 | | wx.TINY_CAPTION_HORIZONTAL | 代替wx.CAPTION而顯示一個較小的水平標題。 | | wx.TINY_CAPTION_VERTICAL | 代替wx.CAPTION而顯示一個較小的垂直標題。 | 典型的,小型框架被用于工具框窗口中,在工具框窗口中始終是有效的,它們不影響任務欄。較小的標題使得它們更有效的利用空間,并且明顯地區別于標準的框架。 ### 如何創建一個非矩形的框架? 在大多數應用程序中,框架都是矩形,因為矩形有一個不錯的規則的形狀,并且繪制和維護相對簡單。可是,有時候你需要打破直線的制約。在wxPython中,你可以給框架一個任一的形狀。如果一個備用的形狀被定義了,那么框架超出該形狀的部分不將被繪制,并且不響應鼠標事件;對于用戶而言,它們不是框架的一部分。圖8.9顯示了一個非矩形的窗口,顯示的背景是文本編輯器中的代碼。 事件被設置來以便雙擊時開關這個非標準形狀,鼠標右鍵單擊時關閉這個窗口。這個例子使用了來自wxPython demo的images模塊作為vippi的圖像的資源,wxPython的吉祥物。 **圖8.9** ![](https://box.kancloud.cn/2016-08-21_57b9960d4b377.gif) 例8.10顯示了在這個非矩形框架后面的代碼。這個例子比我們見過的其它一些稍微精細點,以顯示如何在缺少典型的窗口界面裝飾的情況下管理像窗口關閉之類的事情。 **例8.10** **繪制符合形狀的窗口** ``` import wx import images class ShapedFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, "Shaped Window", style = wx.FRAME_SHAPED | wx.SIMPLE_BORDER | wx.FRAME_NO_TASKBAR) self.hasShape = False #1 獲取圖像 self.bmp = images.getVippiBitmap() self.SetClientSize((self.bmp.GetWidth(), self.bmp.GetHeight())) #2 繪制圖像 dc = wx.ClientDC(self) dc.DrawBitmap(self.bmp, 0,0, True) self.SetWindowShape() self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) self.Bind(wx.EVT_RIGHT_UP, self.OnExit) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_WINDOW_Create, self.SetWindowShape)#3 綁定窗口創建事件 def SetWindowShape(self, evt=None):#4 設置形狀 r = wx.RegionFromBitmap(self.bmp) self.hasShape = self.SetShape(r) def OnDoubleClick(self, evt): if self.hasShape: self.SetShape(wx.Region())#5 重置形狀 self.hasShape = False else: self.SetWindowShape() def OnPaint(self, evt): dc = wx.PaintDC(self) dc.DrawBitmap(self.bmp, 0,0, True) def OnExit(self, evt): self.Close() if __name__ == '__main__': app = wx.PySimpleApp() ShapedFrame().Show() app.MainLoop() ``` **#1** 在從images模塊得到圖像后,我們將窗口內部的尺寸設置為位圖的尺寸。你也可以根據一個標準的圖像文件來創建這個wxPython位圖,這將在第16章中作更詳細的討論。 **#2** 這里,我們在窗口中繪制這個圖像。這決不是一個必然的選擇。你可以像其它窗口一樣在該形狀窗口中放置窗口部件和文本(盡管它們必須在該形狀的區域內)。 **#3** 這個事件在大多數平臺上是多余的,它強制性地在窗口被創建后調用[SetWindowShape](http://wiki.woodpecker.org.cn/moin/SetWindowShape)()。但是,GTK的實現要求在該形狀被設置以前,窗口的本地UI對象被創建和確定,因此當窗口創建發生時我們使用窗口創建事件去通知并在它的處理器中設置形狀。 **#4** 我們使用全局方法wx.[RegionFromBitmap](http://wiki.woodpecker.org.cn/moin/RegionFromBitmap)去創建設置形狀所需的wx.Region對象。這是創建不規則形狀的最容易的方法。你也可以根據一個定義多邊形的點的列表來創建一個wx.Region。圖像的透明部分的用途是定義區域的邊界。 **#5** 雙擊事件開關窗口的形狀。要回到標準的矩形,要使用一個空的wx.Region作為參數來調用[SetShape](http://wiki.woodpecker.org.cn/moin/SetShape)()。 除了沒有標準的關閉框或標題欄等外,不規則形狀框架的行為像一個普通的框架一樣。任何框架都可以改變它的形狀,因為[SetShape](http://wiki.woodpecker.org.cn/moin/SetShape)()方法是wx.Frame類的一部分,它可以被任何子類繼承。在wx.[SplashScreen](http://wiki.woodpecker.org.cn/moin/SplashScreen)中,符合形狀的框架是特別的有用。 ### 如何拖動一個沒有標題欄的框架? 前一個例子的明顯結果是這個沒有標題欄的框架不能被拖動的,這兒沒有拖動窗口的標準方法。要解決這個問題,我們需要去添加事件處理器來在當拖動發生時移動該窗口。例8.11顯示與前一例子相同形狀的窗口,但增加了對于處理鼠標左鍵敲擊和鼠標移動的一些事件。這個技術可以適用于任何其它的框架,甚至是框架內你想要移動的窗口(例如繪畫程序中的元素)。 **例8.11** **使用戶能夠從框架來拖動框架的事件** ``` import wx import images class ShapedFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, "Shaped Window", style = wx.FRAME_SHAPED | wx.SIMPLE_BORDER ) self.hasShape = False self.delta = wx.Point(0,0) self.bmp = images.getVippiBitmap() self.SetClientSize((self.bmp.GetWidth(), self.bmp.GetHeight())) dc = wx.ClientDC(self) dc.DrawBitmap(self.bmp, 0,0, True) self.SetWindowShape() self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) #1 新事件 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) self.Bind(wx.EVT_MOTION, self.OnMouseMove) self.Bind(wx.EVT_RIGHT_UP, self.OnExit) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_WINDOW_Create, self.SetWindowShape) def SetWindowShape(self, evt=None): r = wx.RegionFromBitmap(self.bmp) self.hasShape = self.SetShape(r) def OnDoubleClick(self, evt): if self.hasShape: self.SetShape(wx.Region()) self.hasShape = False else: self.SetWindowShape() def OnPaint(self, evt): dc = wx.PaintDC(self) dc.DrawBitmap(self.bmp, 0,0, True) def OnExit(self, evt): self.Close() def OnLeftDown(self, evt):#2 鼠標按下 self.CaptureMouse() pos = self.ClientToScreen(evt.GetPosition()) oigin = self.GetPosition() self.delta = wx.Point(pos.x - oigin.x, pos.y - oigin.y) def OnMouseMove(self, evt):#3 鼠標移動 if evt.Dragging() and evt.LeftIsDown(): pos = self.ClientToScreen(evt.GetPosition()) newPos = (pos.x - self.delta.x, pos.y - self.delta.y) self.Move(newPos) def OnLeftUp(self, evt):#4 鼠標釋放 if self.HasCapture(): self.ReleaseMouse() if __name__ == '__main__': app = wx.PySimpleApp() ShapedFrame().Show() app.MainLoop() ``` **#1** 我們為三個事件增加了相應的處理器,以作相應的工作。這三個事件是鼠標左鍵按下,鼠標左鍵釋放和鼠標移動。 **#2** 拖動事件從鼠標左鍵按下開始。這個事件處理器做兩件事。首先它捕獲這個鼠標,直到鼠標被釋放,以防止鼠標事件被改善到其它窗口部件。第二,它計算事件發生的位置和窗口左上角之間的偏移量,這個偏移量將被用來計算窗口的新位置。 **#3** 這個處理器當鼠標移動時被調用,它首先檢查看該事件是否是一個鼠標左鍵按下,如果是,它使用這個新的位置和前面計算的偏移量來確定窗口的新位置,并移動窗口。 **#4** 當鼠標左鍵被釋放時,[ReleaseMouse](http://wiki.woodpecker.org.cn/moin/ReleaseMouse)()被調用,這使得鼠標事件又可以被發送到其它的窗口部件。 這個拖動技術可以被完善以適合其它的需要。例如,僅在一個定義的區域內鼠標敲擊才開始一個拖動,你可以對鼠標按下事件的位置做一個測試,使敲擊發生在右邊的位置時,才能拖動。 ## 使用分割窗 分割窗是一種特殊的容器窗口部件,它管理兩個子窗口。這兩個子窗口可以被水平的堆放或彼此左右相鄰。在兩個子窗口之間的是一個窗框,它是一個可移動的邊框,移動它就改變了兩個子窗口的尺寸。分割窗經常被用于主窗口的側邊欄。圖8.10顯示了一個分割窗的樣板。 當你有兩個信息面板并且想讓用戶自主決定每個面板的尺寸時,可以使用分割窗。Mac OS X Finder窗口就是一個分割窗的例子,并且許多的文本編輯器或制圖軟件都用它來維護一個打開的文件的列表。 ### 創建一個分割窗 在wxPython中,分割窗是類wx.[SplitterWindow](http://wiki.woodpecker.org.cn/moin/SplitterWindow)的實例。和大多數其它的wxPython窗口部件不一樣,分隔窗口在被創建后,可使用前要求進一步的初始化。它的構造函數是十分簡單的。 **圖8.10** ![](https://box.kancloud.cn/2016-08-21_57b9960d61846.gif) ``` wx.SplitterWindow(parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.SP_3D, name="splitterWindow") ``` 它的這些參數都有標準的含義——parent是窗口部件的容器,pos是窗口部件在它的父容器中位置,size是它的尺寸。 在創建了這個分割窗后,在它可以被使用前,你必須對這個窗口調用三個方法中的一處。如果你想初始時只顯示一個子窗口,那么調用Initialize(window),參數window是這個單一的子窗口(通常是一種wx.Panel)。在這種情況下,窗口將在以后響應用戶的動作時再分割。 要顯示兩個子窗口,使用[SplitHorizontally](http://wiki.woodpecker.org.cn/moin/SplitHorizontally) (window1,window2,sashPosition=0)或[SplitVertically](http://wiki.woodpecker.org.cn/moin/SplitVertically)(window1, window2, sashPosition=0)。兩個方法的工作都是相似的,參數window1和window2包含兩個子窗口,參數sashPosition包含分割條的初始位置。對于水平分割(水平分割條)來說,window1被放置在window2的頂部。如果sashPosition是一個正數,它代表頂部窗口的初始高度(也就是分割條距頂部的像素值)。如果sashPosition是一個負數,它定義了底部窗口的尺寸,或分割條距底部的像素值。如果sashPosition是0,那么這個分割條位于正中。對于垂直分割(垂直分割條),window1位于左邊,window2位于右邊。正值的sashPosition設置window1的尺寸,也就是分割條距左邊框的像素值。類似的,負值sashPosition設置右邊子窗口的尺寸,0值將分割條放置在正中。如果你的子窗口復雜的話,我們建議你在布局中使用sizer,以便于當分割條被移動時很好地調整窗口的大小。 ### 一個分割窗的例子 例8.12顯示了如何創建有一個子窗口的分割窗并且在以后響應菜單項的分割。這個例子也使用了一些事件,這些事件我們以后討論。注意,我們不計劃在開始可見的子面板使用Hide()方法來隱藏。我們這樣做是因為我們開始時不告訴分割窗去管理那個子面板的尺寸和位置,所以我們使用這種方法來隱藏它。如果我們在開始就要分割和顯示這兩個子面板,那么我們就不必考慮這些。 **例8.12** **如何創建你自己的分割窗** ``` import wx class SplitterExampleFrame(wx.Frame): def __init__(self, parent, title): wx.Frame.__init__(self, parent, title=title) self.MakeMenuBar() self.minpane = 0 self.initpos = 0 self.sp = wx.SplitterWindow(self)# 創建一個分割窗 self.p1 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER)# 創建子面板 self.p2 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER) self.p1.SetBackgroundColour("pink") self.p2.SetBackgroundColour("sky blue") self.p1.Hide()# 確保備用的子面板被隱藏 self.p2.Hide() self.sp.Initialize(self.p1)# 初始化分割窗 self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging, self.sp) self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged, self.sp) def MakeMenuBar(self): menu = wx.Menu() item = menu.Append(-1, "Split horizontally") self.Bind(wx.EVT_MENU, self.OnSplitH, item) self.Bind(wx.EVT_Update_UI, self.OnCheckCanSplit, item) item = menu.Append(-1, "Split vertically") self.Bind(wx.EVT_MENU, self.OnSplitV, item) self.Bind(wx.EVT_Update_UI, self.OnCheckCanSplit, item) item = menu.Append(-1, "Unsplit") self.Bind(wx.EVT_MENU, self.OnUnsplit, item) self.Bind(wx.EVT_Update_UI, self.OnCheckCanUnsplit, item) menu.AppendSeparator() item = menu.Append(-1, "Set initial sash position") self.Bind(wx.EVT_MENU, self.OnSetPos, item) item = menu.Append(-1, "Set minimum pane size") self.Bind(wx.EVT_MENU, self.OnSetMin, item) menu.AppendSeparator() item = menu.Append(wx.ID_EXIT, "E ") self.Bind(wx.EVT_MENU, self.OnExit, item) mbar = wx.MenuBar() mbar.Append(menu, "Splitter") self.SetMenuBar(mbar) def OnSashChanging(self, evt): print "OnSashChanging:", evt.GetSashPosition() def OnSashChanged(self, evt): print "OnSashChanged:", evt.GetSashPosition() def OnSplitH(self, evt):# 響應水平分割請求 self.sp.SplitHorizontally(self.p1, self.p2, self.initpos) def OnSplitV(self, evt):# 響應垂直分割請求 self.sp.SplitVertically(self.p1, self.p2, self.initpos) def OnCheckCanSplit(self, evt): evt.Enable(not self.sp.IsSplit()) def OnCheckCanUnsplit(self, evt): evt.Enable(self.sp.IsSplit()) def OnUnsplit(self, evt): self.sp.Unsplit() def OnSetMin(self, evt): minpane = wx.GetNumberFromUser( "Enter the minimum pane size", "", "Minimum Pane Size", self.minpane, 0, 1000, self) if minpane != -1: self.minpane = minpane self.sp.SetMinimumPaneSize(self.minpane) def OnSetPos(self, evt): initpos = wx.GetNumberFromUser( "Enter the initial sash position (to be used in the Split call)", "", "Initial Sash Position", self.initpos, -1000, 1000, self) if initpos != -1: self.initpos = initpos def OnExit(self, evt): self.Close() app = wx.PySimpleApp(redirect=True) frm = SplitterExampleFrame(None, "Splitter Example") frm.SetSize((600,500)) frm.Show() app.SetTopWindow(frm) app.MainLoop() ``` 分割窗只能分割一次,對已分割的窗口再分割將會失敗,從而導致分割方法返回False(成功時返回True)。要確定窗口當前是否被分割了,調用方法[IsSplit](http://wiki.woodpecker.org.cn/moin/IsSplit)()。在例8.12中,為了確保相應的菜單項有效,就采用這個方法。 如果你想不分割窗口,那么使用Unsplit(toRemove=None)。參數toRemove是實際要移除的wx.Window對象,并且必須是這兩個子窗口中的一個。如果toRemove是None,那么底部或右部的窗口將被移除,這根據分割的方向而定。默認情況下,被移除的窗口是沒有被wxPython刪除的,所以以后你可以再把它添加回來。unsplit方法在取消分割成功時返回True。如果分割窗當前沒有被分割,或toRemove參數不是兩個子窗口中的一個,那么該方法返回False。 要確保你對想要的子窗口有一個正確的引用,那么使用[GetWindow1](http://wiki.woodpecker.org.cn/moin/GetWindow1)()和[GetWindow2](http://wiki.woodpecker.org.cn/moin/GetWindow2)()方法。[GetWindow1](http://wiki.woodpecker.org.cn/moin/GetWindow1)()方法返回頂部或左邊的子窗口,而[GetWindow2](http://wiki.woodpecker.org.cn/moin/GetWindow2)()方法返回底部或右邊的窗口。由于沒有一個直接的設置方法來改變一個子窗口,所以使用方法[ReplaceWindow](http://wiki.woodpecker.org.cn/moin/ReplaceWindow)(winOld, winNew),winOld是你要替換的wx.Window對象,winNew是要顯示的新窗口。 ### 改變分割的外觀 有許多樣式標記用來控制顯示在屏幕上的分割窗的外觀。注意,由于分割與平臺有關,所以不是所有列出的標記都將對任何平臺起作用。表8.9說明了這些有效的標記。 我們將在接下來的部分看到,你也可以用你的程序來改變分割的顯示,以響應用戶的動作或你自己的要求。 **表8.9** **分割窗的樣式** | | | | --- | --- | | wx.SP_3D | 繪制三維的邊框和分割條。這是一個默認樣式。 | | wx.SP_3DBORDER | 繪制三維樣式的邊框,不包括分割條。 | | wx.SP_3DSASH | 繪制三維樣式的分割條,不包括邊框。 | | wx.SP_BORDER | 繪制窗口的邊框,非三維的樣式。 | | wx.SP_LIVE_Update | 改變響應分割條移動的默認行為。如果沒有設置這個標記,那么當用戶拖動分割條時,將繪制一條線來標明分割條的新位置。子窗口的尺寸沒有被實際地更新,直到完成分割條拖放。如果設置了這個標記,那么當分割條在被拖動時,子窗口的尺寸將不斷地變化。 | | wx.SP_NOBORDER | 不繪制任何邊框。 | | wx.SP_NO_XP_THEME | 在Windows XP系統下,分割條不使用XP的主題樣式,它給窗口一個更經典的外觀。 | | wx.SP_PERMIT_UNSPLIT | 如果設置了這個樣式,那么窗口始終不被分割。如果不設置,你可以通過設置大于0的最小化的窗格尺寸來防止窗口被分割。 | ### 以程序的方式處理分割 一旦分割窗被創建,你就可以使用窗口的方法來處理分割條的位置。特別是,你可以使用方法[SetSashPosition](http://wiki.woodpecker.org.cn/moin/SetSashPosition)(position,redraw=True)來移動分割條。position是以像素單位的新的位置,它是分割條距窗口頂部或左邊的距離。用在分割方法中的負值,表示位置從底部或右邊算起。如果redraw為True,則窗口立即更新。否則它等待常規窗口的刷新。如果你的像素值在范圍外的話,設置方法的行為將不被定義。要得到當前分割條的位置,使用[GetSashPosition](http://wiki.woodpecker.org.cn/moin/GetSashPosition)()方法。 在默認的分割行為下,用戶可以在兩個邊框間隨意移到分割條。移動分割條到一邊,使得別一子窗口的尺寸為0,這導致窗口此時成未分割狀態。要防止這種情況,你可以使用方法[SetMinimumPaneSize](http://wiki.woodpecker.org.cn/moin/SetMinimumPaneSize)(paneSize)來指定子窗口的最小尺寸。paneSize參數是子窗口的最小像素尺寸。這樣,用戶就不能通過拖放來使子窗口更小,程序同樣也不能使子窗口更小。如前所述,你可以使用wx.SP_PERMIT_UNSPLIT樣式來達到相同的效果。要得到當前最小子窗口尺寸,使用方法[GetMinimumPaneSize](http://wiki.woodpecker.org.cn/moin/GetMinimumPaneSize)()。 改變窗口的分割模式,使用方法[SetSplitMode](http://wiki.woodpecker.org.cn/moin/SetSplitMode)(mode),參數mode取下列常量值之一:wx.SPLIT_VERTICAL、wx.SPLIT_HORIZONTAL。如果模式改變了,那么頂部窗口變為左邊,而底部變為右邊(反之亦然)。該方法不引起窗口的重繪,你必須顯式地進行強制重繪。你可以使用[GetSplitMode](http://wiki.woodpecker.org.cn/moin/GetSplitMode)()來得到當前的分割模式,它返回上面兩個常量值之一。如果窗口當前是未分割狀態,那么[GetSplitMode](http://wiki.woodpecker.org.cn/moin/GetSplitMode)()方法返回最近的分割模式。 典型的,如果wx.SP_LIVE_Update樣式沒有被設置,那么子窗口僅在分割條拖動會話結束時改變尺寸。如果你想在其它時刻強制子窗口重繪,你可以使用方法[UpdateSize](http://wiki.woodpecker.org.cn/moin/UpdateSize)()。 ### 響應分割事件 分割窗觸發wx.[SplitterEvent](http://wiki.woodpecker.org.cn/moin/SplitterEvent)類事件。這兒有四個不同的分割窗的事件類型,如表8.10所示。 **表8.10 分割窗的事件類型** | | | | --- | --- | | EVT_SPLITTER_DCLICK | 當分割條被雙擊時觸發。捕捉這個事件不阻塞標準的不分割行為,除非你調用事件的Veto()方法。 | | EVT_SPLITTER_SASH_POS_CHANGED | 分割條的改變結束后觸發,但在此之前,改變將在屏幕上顯示(因此你可以再作用于它)。這個事件可以使用Veto()來中斷。 | | EVT_SPLITTER_SASH_POS_CHANGING | 當分割條在被拖動時,不斷觸發該事件。這個事件可以通過使用事件的Veto()方法來中斷,如果被中斷,那么分割條的位置不被改變。 | | EVT_SPLITTER_UNSPLIT | 變成未分割狀態時觸發。 | 這個分割事件類是wx.[CommandEvent](http://wiki.woodpecker.org.cn/moin/CommandEvent)的子類。從分割事件的實例,你可以訪問關于分割窗當前狀態的信息。對于涉及到分割條移動的兩個事件,調用[GetSashPosition](http://wiki.woodpecker.org.cn/moin/GetSashPosition)()得到分割條相對于左或頂部的位置,這依據分割條的方向而定。在位置正在變化事件中,調用[SetSashPosition](http://wiki.woodpecker.org.cn/moin/SetSashPosition)(pos),將用線條表示新的位置。在位置已改變事件中,[SetSashPosition](http://wiki.woodpecker.org.cn/moin/SetSashPosition)(pos)方法將移動分割條。對于雙擊事件,你可以使用事件的GetX() 和GetY()方法得到敲擊的確切位置。對于未分割事件,你可以使用[GetWindowBeingRemoved](http://wiki.woodpecker.org.cn/moin/GetWindowBeingRemoved)()方法來得到哪個窗口被移除了。 ## 本章小結 1、wxPython中的大部分用戶交互都發生在wx.Frame或wx.Dialog中。wx.Frame代表用戶調用的窗口。wx.Frame實例的創建就像其它的wxPython窗口部件一樣。wx.Frame的典型用法包括創建子類,子類通過定義子窗口部件,布局和行為來擴展基類。通常,一個框架包含只包含一個wx.Panel的頂級子窗口部件或別的容器窗口。 2、這兒還有各種特定于wx.Frame的樣式標記。其中的一些影響框架的尺寸和形狀,另一些影響在系統中相對于其它的框架,它將如何被繪制,還有一些定義了在框架邊框上有那些界面裝飾。在某種情況下,定義一個樣式標記需要“兩步”的創建過程。 3、通過調用Close()方法可以產生關閉框架的請求。這給了框架一個關閉它所占用的資源的機會。框架也能否決一個關閉請求。調用Destroy()方法將迫使框架立即消失而沒有任何延緩。 4、框架中的一個特定的子窗口部件可以使用它的wxPython ID、名字或它的文本標簽來發現。 5、通過包括wx.[ScrolledWindow](http://wiki.woodpecker.org.cn/moin/ScrolledWindow)類的容器部件可以實現滾動。這兒有幾個方法來設置滾動參數,最簡單的是在滾動窗口中使用sizer,在這種情況下,wxPython自動確定滾動面板的虛擬尺寸(virtual size)。如果想的話,虛擬尺寸可以被手動設置。 6、這兒有一對不同的框架子類,它們允許不同的外觀。類wx.MDIParentFrame可以被用來創建MDI,而wx.[MiniFrame](http://wiki.woodpecker.org.cn/moin/MiniFrame)可以創建一個帶有較小標題欄的工具框樣式的窗口。使用[SetShape](http://wiki.woodpecker.org.cn/moin/SetShape)()方法,框架可以呈現出非矩形的形狀。形狀的區域可以被任何位圖定義,并使用簡單的顏色掩碼來決定區域的邊緣。非矩形窗口通常沒有標準的標題欄,標題欄使得框架可以被拖動, 但這可以通過顯式地處理鼠標事件來管理。 7、位于兩個子窗口間的可拖動的分割條能夠使用wx.[SplitterWindow](http://wiki.woodpecker.org.cn/moin/SplitterWindow)來實現,分割條可以被用戶以交互的方式處理,或以編程的方式處理(如果需要的話)。 在下一章,我們將討論對話框,它的行為類似于框架。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看