2012-04-20 42 views
1

我在教自己(Wx)Python,並陷入困境。我想創建一個子窗口,其中包含我的TestFrame中包含大部分代碼的循環信息集。問題是,它只在我的代碼中顯示一個小部件。我試圖弄清楚以下幾點,對我來說很重要。WxPython:兒童窗口中的多個構件

**請注意,此代碼是一個擴展this頁。*

  1. 我怎麼能允許多個小部件在「AddBox」級正確顯示?
  2. 當我的窗口被調整大小時,它會損壞按鈕圖像,如同在所附的屏幕中。我怎麼能解決這個問題?
  3. 你如何調用/綁定每個這些動態創建的小部件?
  4. 獎勵:這裏需要的「OnSize」模塊?

謝謝你的幫助。如果允許/適當,我願意通過Paypal向獲獎者捐款5美元,如果你是我的話。

import wx 

class AddBox(wx.Window): 
    def __init__(self, parent): 
     wx.Window.__init__(self, parent)   

     pbox = wx.BoxSizer(wx.VERTICAL) 

     controlback = wx.Button(self, label="Back") 
     controlforward = wx.Button(self, label="Forward") 

     pbox.AddMany([(controlback, 1, wx.ALL), (controlforward, 1, wx.ALL)]) 

class TestFrame(wx.Frame): 
    def __init__(self): 
     wx.Frame.__init__(self, None, -1, size=(1000, 550)) 

     self.Bind(wx.EVT_SIZE, self.OnSize) 

     pbox0 = wx.BoxSizer(wx.VERTICAL) 
     controlback0 = wx.Button(self, label="Back0") 
     controlforward0 = wx.Button(self, label="Forward0") 
     pbox0.AddMany([(controlback0, 1, wx.ALL), (controlforward0, 1, wx.ALL)]) 
     pbox2 = wx.BoxSizer(wx.VERTICAL) 

     self.scrolling_window = wx.ScrolledWindow(self) 
     self.scrolling_window.SetScrollRate(1,6) 
     self.scrolling_window.EnableScrolling(True,True) 
     self.sizer_container = wx.BoxSizer(wx.VERTICAL) 
     self.sizer = wx.BoxSizer(wx.VERTICAL) 
     self.sizer_container.Add(self.sizer,1,wx.CENTER,wx.EXPAND) 
     self.child_windows = [] 
     for i in range(0,8): 
      wind = AddBox(self.scrolling_window) 
      self.sizer.Add(wind, 0, wx.CENTER|wx.ALL, 5) 
      self.child_windows.append(wind) 

     self.scrolling_window.SetSizer(self.sizer_container) 
     #self.Layout() #not needed? 


     pbox2.AddMany([(self.sizer_container, 1, wx.ALL)]) 

    def OnSize(self, event): 
     self.scrolling_window.SetSize(self.GetClientSize()) 

if __name__=='__main__': 
    app = wx.PySimpleApp() 
    f = TestFrame() 
    f.Show() 
    app.MainLoop() 

回答

1

這裏的代碼非常複雜,很難遵循。你幾乎不需要使用wx.Window。事實上,在使用wxPython近6年的時間裏,我從來沒有直接使用它。 PySimpleApp也被棄用。無論如何,我清理了一堆代碼,並在下面重新執行了代碼。我不確定這是不是你要找的或不是。另外請注意,我換出ScrolledWindow爲ScrolledPanel,因爲我認爲後者更容易使用:

import wx 
import wx.lib.scrolledpanel as scrolled 

class TestFrame(wx.Frame): 
    def __init__(self): 
     wx.Frame.__init__(self, None, size=(1000, 550)) 
     panel = wx.Panel(self) 

     mainSizer = wx.BoxSizer(wx.VERTICAL) 
     pbox0 = wx.BoxSizer(wx.VERTICAL) 
     controlback0 = wx.Button(panel, label="Back0") 
     controlforward0 = wx.Button(panel, label="Forward0") 
     pbox0.Add(controlback0, 0, wx.ALL) 
     pbox0.Add(controlforward0, 0, wx.ALL) 
     mainSizer.Add(pbox0) 

     self.scrolling_window = scrolled.ScrolledPanel(panel) 
     self.scrolling_window.SetAutoLayout(1) 
     self.scrolling_window.SetupScrolling() 
     self.sizer = wx.BoxSizer(wx.VERTICAL) 
     self.child_windows = [] 
     for i in range(0,8): 
      wind = self.addBox() 
      self.sizer.Add(wind, 0, wx.CENTER|wx.ALL, 5) 
     self.scrolling_window.SetSizer(self.sizer) 

     mainSizer.Add(self.scrolling_window, 1, wx.EXPAND) 
     panel.SetSizer(mainSizer) 

    def addBox(self): 
     pbox = wx.BoxSizer(wx.VERTICAL) 

     controlback = wx.Button(self.scrolling_window, label="Back") 
     controlforward = wx.Button(self.scrolling_window, label="Forward") 

     pbox.AddMany([(controlback, 0, wx.ALL), (controlforward, 0, wx.ALL)]) 
     return pbox 

    def OnSize(self, event): 
     self.scrolling_window.SetSize(self.GetClientSize()) 

if __name__=='__main__': 
    app = wx.App(False) 
    f = TestFrame() 
    f.Show() 
    app.MainLoop() 

你也應該看看Widget的檢測工具。這將幫助你找出這樣的佈局問題:http://wiki.wxpython.org/Widget%20Inspection%20Tool

編輯:我覺得上面的代碼需要將項目#1和2.對於#3,請參閱下面的文章中,我去年寫:http://www.blog.pythonlibrary.org/2011/09/20/wxpython-binding-multiple-widgets-to-the-same-handler/

基本上,你綁定在循環本身,然後在事件處理程序中,可以使用event.GetEventObject()來返回調用小部件並設置它的值或任何其他值。至於你的第四個問題,我會說不,你不需要OnSize方法。你幾乎從不需要在wxPython中重寫它,我當然也沒有在我的示例代碼中。

+0

右邊徑跡,這是有幫助的,但它並不顯示如何從外部編輯。例如,如果按下controlback或controlback0,如何編輯addBox模塊中的textctrl? – mh00h 2012-04-23 18:03:32

+0

我必須在這裏失去一些東西。你的例子中有一個TextCtrl在哪裏?沒有一個。爲什麼按一個隨機按鈕可以讓你編輯一個文本控件呢?如果你想按下一個按鈕來打開編輯,那麼你需要保留一些按鈕的數據結構(可能是一個字典)以及它們映射到哪些文本控件。然後當按下按鈕時,它將啓用文本控件並將焦點放在那裏。 – 2012-04-23 18:45:18

+0

謝謝。我在第一季度遇到了最困難的時刻,你優雅地修好了。感謝您向我展示如何處理wx。Window,我不知道該如何去追求它,並且你給了我我需要開始理解這裏發生了什麼的牽引力。至於Q3,你的回答也非常有幫助,並使我可以自動填充多個文本控件。有一天我可以像這樣的人出去......謝謝你! – mh00h 2012-04-23 19:51:41

0

我現在只有一個答案:爲每個動態創建的小部件分配一個ID,將此ID存儲在字典({id:widget})中,並將回調函數作爲lambda函數或使用functools。部分將ID傳遞給「真實」回調。 (當然你也可以通過插件直接在λ-功能,但我喜歡到創建的小部件實例的地方,如果我需要訪問這些某個時候)

def __init__(...): 
    self.event_dispatch = dict() 

    ... 

    for id in xrange(500, 508): 
     wind = AddBox(self.scrolling_window, id) 
     ... 
     self.event_dispatch[id] = wind 
     self.scrolling_window.Bind(wx.MY_EVENT, lambda evt: self.on_event(evt, id), id=id) 


def on_event(event, id): 
    widget = self.event_dispatch[id] 
    # do something with widget 
+0

到目前爲止這麼好......但是,當MikeDriscoll的代碼中存在事件時,這很有效,但它不是來自「外部」。 即,我不知道如何訪問位於controlback0的'for循環'內的textctrl。 (謝謝你的幫助) – mh00h 2012-04-20 18:59:24