wxpython:向 wxgrid 动态添加行不适合面板

wxpython: adding rows to wxgrid dynamically does not fit to panel

我在可调整大小的可滚动面板中有一个 wxgrid。我在 wxgrid 中动态 add/hide/show 行。当我尝试在 wxgrid 中 add/show 更多行时,它不适合面板中可用的 space 而是占据了一个小区域,它以前用 wxgrid 的滚动条占据了。

像这样:

但在我调整面板或框架的大小后,它就完全适合了。像这样:

如何在不调整面板大小的情况下使其适合?

我在将网格添加到 sizer 时尝试了 wx.EXPAND、wx.GROW、wx.ALL 的所有组合,并且还尝试了 gridobj.Layout() 没有任何效果。有什么想法吗?

我在 windows 7

上使用 wx 3.0 和 python 2.7

编辑: 这是我的代码

controls.py

import wx
import wx.grid
import wx.combo
class SimpleGrid(wx.grid.Grid):
    def __init__(self, parent):
        wx.grid.Grid.__init__(self, parent, -1)
        self.CreateGrid(10, 5)
        for i in range(10):
            self.SetRowLabelValue(i,str(i))

class ListCtrlComboPopup(wx.ListCtrl, wx.combo.ComboPopup):

    def __init__(self,parent):
        self.gfobj = parent
        self.PostCreate(wx.PreListCtrl())
        self.parent = parent
        wx.combo.ComboPopup.__init__(self)

    def AddItem(self, txt):
        self.InsertStringItem(self.GetItemCount(), txt)
        self.Select(0)

    def GetSelectedItems(self):
      del self.gfobj.selection[:]
      current = -1
      while True:
            next = self.GetNextSelected(current)
            if next == -1:
                return
            self.gfobj.selection.append(next)
            current = next

    def onItemSelected(self, event):
        item = event.GetItem()
        self.GetSelectedItems()
        self.parent.draw_plot()

    def onItemDeSelected(self, event):
        self.GetSelectedItems()
        self.parent.draw_plot()


    def Init(self):
        """ This is called immediately after construction finishes.  You can
        use self.GetCombo if needed to get to the ComboCtrl instance. """
        self.value = -1
        self.curitem = -1


    def Create(self, parent):
        """ Create the popup child control. Return True for success. """
        wx.ListCtrl.Create(self, parent,
                           style=wx.LC_LIST|wx.SIMPLE_BORDER)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onItemSelected)
        self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.onItemDeSelected)
        return True


    def GetControl(self):
        """ Return the widget that is to be used for the popup. """
        return self

    def SetStringValue(self, val):
        """ Called just prior to displaying the popup, you can use it to
        'select' the current item. """
        idx = self.FindItem(-1, val)
        if idx != wx.NOT_FOUND:
            self.Select(idx)


    def GetStringValue(self):
        """ Return a string representation of the current item. """
        a = self.GetItemText(self.value)
        if self.value >= 0:
            return a
        return ""

    def OnPopup(self):
        """ Called immediately after the popup is shown. """
        self.state = []
        for i in range(self.GetItemCount()):
            item = self.GetItem(itemId=i)
            self.state.append(item.GetState())
            #print self.state
        wx.combo.ComboPopup.OnPopup(self)

    def OnDismiss(self):
        " Called when popup is dismissed. """
        wx.combo.ComboPopup.OnDismiss(self)

main.py

import wx
import wx.lib.scrolledpanel
from controls import SimpleGrid
from controls import ListCtrlComboPopup


class GraphFrame(wx.Frame):
    title = 'Demo: Data Trending Tool'

    def __init__(self):
        self.selection = []
        self.displaySize = wx.DisplaySize() 
        wx.Frame.__init__(self, None, -1, self.title,
                 style = wx.DEFAULT_FRAME_STYLE,
                 size = (self.displaySize[0]/2, self.displaySize[1]/2))        
        self.containingpanel = wx.Panel(self, -1)
        self.toppanel = wx.Panel(self, -1)
        self.splittedwin = wx.SplitterWindow(self.containingpanel, wx.ID_ANY, style=wx.SP_3D | wx.SP_BORDER)
        self.splittedwin.SetMinimumPaneSize(20)
        self.gridpanel = wx.lib.scrolledpanel.ScrolledPanel(self.splittedwin,-1, style = wx.SUNKEN_BORDER)        
        self.panel = wx.lib.scrolledpanel.ScrolledPanel(self.splittedwin,-1, style = wx.SUNKEN_BORDER)

        #### GRID
        self.grid = SimpleGrid(self.gridpanel)
        self.gridpanelsizer= wx.BoxSizer(wx.HORIZONTAL)
        self.gridpanelsizer.Add(self.grid, wx.GROW)
        self.gridpanel.SetSizer(self.gridpanelsizer)
        self.gridpanelsizer.Fit(self)             
        #### COMBOBOX
        self.cc = wx.combo.ComboCtrl(self.toppanel, style=wx.CB_READONLY, size=(200,-1), )
        self.cc.SetPopupMaxHeight(140)
        popup = ListCtrlComboPopup(self)
        self.cc.SetPopupControl(popup)
        self.cc.SetText("--select--")
        # Add some items to the listctrl
        for i in range(10):
            popup.AddItem(str(i))

        #### SIZER FOR COMBOBOX 
        self.cbpanelsizer= wx.BoxSizer(wx.HORIZONTAL)
        self.cbpanelsizer.Add(self.cc, border = 5,flag = wx.LEFT)
        self.toppanel.SetSizer(self.cbpanelsizer)


        self.splittedwin.SplitHorizontally(self.gridpanel,self.panel,100)

        ##### SIZER FOR CONTAININGPANEL
        self.cpsizer = wx.BoxSizer(wx.VERTICAL) 
        self.cpsizer.Add(self.splittedwin, 1, wx.EXPAND, 0)
        self.containingpanel.SetSizer(self.cpsizer)
        self.cpsizer.Fit(self.containingpanel)

        mainsizer = wx.BoxSizer(wx.VERTICAL)
        mainsizer.Add(self.toppanel, 0, wx.EXPAND)
        mainsizer.Add(self.containingpanel, 1, wx.EXPAND)
        self.SetSizerAndFit(mainsizer)

        self.panel.SetAutoLayout(1)
        self.panel.SetupScrolling()
        self.gridpanel.SetAutoLayout(1)
        self.gridpanel.SetupScrolling()
        self.draw_plot()

    def draw_plot(self):
        for i in range(10):  
          if i in self.selection:
             self.grid.ShowRow(i)
          else:
             self.grid.HideRow(i) 
        self.Layout()
        #self.gridpanel.Layout()

if __name__ == "__main__":

  app = wx.PySimpleApp()
  app.frame = GraphFrame()
  app.frame.Show()

  app.MainLoop()

模拟: 1. 运行 main.py 它在一个面板中显示带有单行网格的拆分 window。

  1. 使用下拉菜单 select 多个项目(按住 ctrl 和 select)
  2. wxgrid 被限制在一行space 带有 wxgrid 滚动条
  3. 使用拆分器调整面板大小或调整 window。现在所有 selected 行都按要求显示。

WIT 是一个很好的调试工具 (http://wiki.wxpython.org/Widget%20Inspection%20Tool)

使用您更正后的代码,我可以通过强制窗扇位置使其变大,这并不理想,但它表明 'problem' 与分离器一起使用。

import wx
import wx.lib.scrolledpanel
from controls import SimpleGrid
from controls import ListCtrlComboPopup


class GraphFrame(wx.Frame):
    title = 'Demo: Data Trending Tool'

    def __init__(self):
        self.selection = []
        self.displaySize = wx.DisplaySize() 
        wx.Frame.__init__(self, None, -1, self.title,
                          style = wx.DEFAULT_FRAME_STYLE,
                          size = (self.displaySize[0]/2, self.displaySize[1]/2))        
        self.containingpanel = wx.Panel(self, -1)
        self.toppanel = wx.Panel(self, -1)
        self.splittedwin = wx.SplitterWindow(self.containingpanel, wx.ID_ANY, style=wx.SP_3D | wx.SP_BORDER)
        self.splittedwin.SetMinimumPaneSize(20)
        self.gridpanel = wx.lib.scrolledpanel.ScrolledPanel(self.splittedwin,-1, style = wx.SUNKEN_BORDER)        
        self.panel = wx.lib.scrolledpanel.ScrolledPanel(self.splittedwin,-1, style = wx.SUNKEN_BORDER)

        #### GRID
        self.grid = SimpleGrid(self.gridpanel)
        self.gridpanelsizer= wx.BoxSizer(wx.HORIZONTAL)
        self.gridpanelsizer.Add(self.grid, wx.GROW)
        self.gridpanel.SetSizer(self.gridpanelsizer)
        self.gridpanelsizer.Fit(self)             
        #### COMBOBOX
        self.cc = wx.combo.ComboCtrl(self.toppanel, style=wx.CB_READONLY, size=(200,-1), )
        self.cc.SetPopupMaxHeight(140)
        popup = ListCtrlComboPopup(self)
        self.cc.SetPopupControl(popup)
        self.cc.SetText("--select--")
        # Add some items to the listctrl
        for i in range(10):
            popup.AddItem(str(i))

        #### SIZER FOR COMBOBOX 
        self.cbpanelsizer= wx.BoxSizer(wx.HORIZONTAL)
        self.cbpanelsizer.Add(self.cc, border = 5,flag = wx.LEFT)
        self.toppanel.SetSizer(self.cbpanelsizer)


        self.splittedwin.SplitHorizontally(self.gridpanel, self.panel, 50)

        ##### SIZER FOR CONTAININGPANEL
        self.cpsizer = wx.BoxSizer(wx.VERTICAL) 
        self.cpsizer.Add(self.splittedwin, 1, wx.EXPAND, 0)
        self.containingpanel.SetSizer(self.cpsizer)

        mainsizer = wx.BoxSizer(wx.VERTICAL)
        mainsizer.Add(self.toppanel, 0, wx.EXPAND)
        mainsizer.Add(self.containingpanel, 1, wx.EXPAND)
        self.SetSizer(mainsizer)

        self.panel.SetupScrolling()
        self.gridpanel.SetupScrolling()
        self.draw_plot()

    def draw_plot(self):
        for i in range(10):  
            if i in self.selection:
                self.grid.ShowRow(i)
            else:
                self.grid.HideRow(i)

        s = self.grid.GetBestSize()
        print(s)
        self.splittedwin.SetSashPosition(s[1])


if __name__ == "__main__":

    from wx.lib.mixins.inspection import InspectableApp
    app = InspectableApp()
    app.frame = GraphFrame()
    app.frame.Show()

    app.MainLoop()

终于找到了!!!

This Answer 的帮助下,发现问题是尝试使用 gridpanel.Layout() 重绘 gridpanel。而是使用 gridpanelsizer.Layout() 重新绘制 gridpanelsizer 成功了!!

已更新 main.py

import wx
import wx.lib.scrolledpanel
from controls import SimpleGrid
from controls import ListCtrlComboPopup


class GraphFrame(wx.Frame):
    title = 'Demo: Data Trending Tool'

    def __init__(self):
        self.selection = []
        self.displaySize = wx.DisplaySize() 
        wx.Frame.__init__(self, None, -1, self.title,
                 style = wx.DEFAULT_FRAME_STYLE,
                 size = (self.displaySize[0]/2, self.displaySize[1]/2))        
        self.containingpanel = wx.Panel(self, -1)
        self.toppanel = wx.Panel(self, -1)
        self.splittedwin = wx.SplitterWindow(self.containingpanel, wx.ID_ANY, style=wx.SP_3D | wx.SP_BORDER)
        self.splittedwin.SetMinimumPaneSize(20)
        self.gridpanel = wx.lib.scrolledpanel.ScrolledPanel(self.splittedwin,-1, style = wx.SUNKEN_BORDER)        
        self.panel = wx.lib.scrolledpanel.ScrolledPanel(self.splittedwin,-1, style = wx.SUNKEN_BORDER)

        #### GRID
        self.grid = SimpleGrid(self.gridpanel)
        self.gridpanelsizer= wx.BoxSizer(wx.HORIZONTAL)
        self.gridpanelsizer.Add(self.grid, wx.GROW)
        self.gridpanel.SetSizer(self.gridpanelsizer)
        self.gridpanelsizer.Fit(self)             
        #### COMBOBOX
        self.cc = wx.combo.ComboCtrl(self.toppanel, style=wx.CB_READONLY, size=(200,-1), )
        self.cc.SetPopupMaxHeight(140)
        popup = ListCtrlComboPopup(self)
        self.cc.SetPopupControl(popup)
        self.cc.SetText("--select--")
        # Add some items to the listctrl
        for i in range(10):
            popup.AddItem(str(i))

        #### SIZER FOR COMBOBOX 
        self.cbpanelsizer= wx.BoxSizer(wx.HORIZONTAL)
        self.cbpanelsizer.Add(self.cc, border = 5,flag = wx.LEFT)
        self.toppanel.SetSizer(self.cbpanelsizer)


        self.splittedwin.SplitHorizontally(self.gridpanel,self.panel,100)

        ##### SIZER FOR CONTAININGPANEL
        self.cpsizer = wx.BoxSizer(wx.VERTICAL) 
        self.cpsizer.Add(self.splittedwin, 1, wx.EXPAND, 0)
        self.containingpanel.SetSizer(self.cpsizer)
        self.cpsizer.Fit(self.containingpanel)

        mainsizer = wx.BoxSizer(wx.VERTICAL)
        mainsizer.Add(self.toppanel, 0, wx.EXPAND)
        mainsizer.Add(self.containingpanel, 1, wx.EXPAND)
        self.SetSizerAndFit(mainsizer)

        self.panel.SetAutoLayout(1)
        self.panel.SetupScrolling()
        self.gridpanel.SetAutoLayout(1)
        self.gridpanel.SetupScrolling()
        self.draw_plot()

    def draw_plot(self):
        for i in range(10):  
          if i in self.selection:
             self.grid.ShowRow(i)
          else:
             self.grid.HideRow(i) 
        #self.Layout()
        self.gridpanelsizer.Layout()

if __name__ == "__main__":

  app = wx.PySimpleApp()
  app.frame = GraphFrame()
  app.frame.Show()

  app.MainLoop()