【问题标题】:wxpython: adding rows to wxgrid dynamically does not fit to panelwxpython:动态添加行到 wxgrid 不适合面板
【发布时间】:2015-04-21 06:59:09
【问题描述】:

我在可调整大小的可滚动面板中有一个 wxgrid。我在 wxgrid 中动态添加/隐藏/显示行。当我尝试在 wxgrid 中添加/显示更多行时,它不适合面板中的可用空间,而是占据了它之前使用 wxgrid 滚动条占用的一小块区域。

像这样:

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

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

我尝试了 wx.EXPAND、wx.GROW、wx.ALL 的所有组合,同时将网格添加到 sizer 并尝试了 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,它会在一个面板中显示一个带有单行网格的分割窗口。

  1. 使用下拉菜单选择多个项目(按住 ctrl 并选择)
  2. wxgrid 被 wxgrid 滚动条限制在一个行空间中
  3. 使用拆分器调整面板大小或调整窗口大小。现在所有选定的行都按要求显示。

【问题讨论】:

  • 添加新数据/行后是否尝试在窗口上使用 self.Fit()?
  • 是的,但这也没用
  • @Lokla 或者可能遗漏了什么。我已经编辑了我的问题以包含一个简化的代码。

标签: python-2.7 wxpython wxwidgets


【解决方案1】:

终于知道了!!!

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()

【讨论】:

    【解决方案2】:

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

    使用您更正的代码,我可以通过强制窗扇位置使其增长,这并不理想,但它表明“问题”出在拆分器上。

    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()
    

    【讨论】:

    • 抱歉,我已更正代码中的异常。将其更正为 flag=wx.GROW,问题仍然存在。
    • 谢谢维尔纳。实际的问题原来是重绘网格的尺寸器。但是,与您的解决方案相比,您的解决方案提供了更简洁的 UI。我将把它包含在我的代码中:):)
    猜你喜欢
    • 2012-12-06
    • 2016-12-04
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多