[wxpython-users] wx.Grid, Hiding columns

822 views
Skip to first unread message

Massi

unread,
Oct 20, 2008, 8:00:49 AM10/20/08
to wxpytho...@lists.wxwidgets.org
Hi everyone,
 
I'm getting in trouble under windows trying to hide columns in a very huge grid (PyGridTableBase), say 100 rows and 20000 columns. The user can decide to hide some or all columns by using a checklistbox in which each checkbox is associated to a column. To hide a column I use SetColSize(col, 0). My problem is that when the number of hidden rows become large, the updating of the grid become extremely slow. In case only one or few columns are not hidden, the grid hangs and program must be killed. Any help?
 
Thanks in advance.
 
 

Massi

unread,
Oct 20, 2008, 9:44:38 AM10/20/08
to wxpytho...@lists.wxwidgets.org
I post a little example code to show what I mean (I simply modified one of the example of the demo), just run the code, press button 1 and then button 2 and, for example, try to use the scrollbar. That simulates exactly what happens in my program.
 
import  wx
import  wx.grid as  gridlib
 
class HugeTable(gridlib.PyGridTableBase):
 
    def __init__(self, log):
        gridlib.PyGridTableBase.__init__(self)
        self.log = log
        self._rows = self.GetNumberRows()
        self._cols = self.GetNumberCols()
   
    def ResetView(self, grid):
        grid.BeginBatch()
        for current, new, delmsg, addmsg in [(self._rows, self.GetNumberRows(), gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED),
            (self._cols, self.GetNumberCols(), gridlib.GRIDTABLE_NOTIFY_COLS_DELETED, gridlib.GRIDTABLE_NOTIFY_COLS_APPENDED),]:
            if new < current:
                msg = gridlib.GridTableMessage(self,delmsg,new,current-new)
                grid.ProcessTableMessage(msg)
            elif new > current:
                msg = gridlib.GridTableMessage(self,addmsg,new-current)
                grid.ProcessTableMessage(msg)
                self.UpdateValues(grid)
        grid.EndBatch()
        self._rows = self.GetNumberRows()
        self._cols = self.GetNumberCols()
        grid.AdjustScrollbars()
        grid.ForceRefresh()
 
    def UpdateValues(self, grid):
        msg = gridlib.GridTableMessage(self, gridlib.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
        grid.ProcessTableMessage(msg)
   
    def GetNumberRows(self):
        return 100
 
    def GetNumberCols(self):
        return 20000
 
    def GetValue(self, row, col):
        return str( (row, col) )
 
class HugeTableGrid(gridlib.Grid):
    def __init__(self, parent, log):
        gridlib.Grid.__init__(self, parent, -1)
        self.table = HugeTable(log)
        self.SetTable(self.table, True)
 

#---------------------------------------------------------------------------
 
class TestFrame(wx.Frame):
    def __init__(self, parent, log):
        wx.Frame.__init__(self, parent, -1, "", size=(840, 680))
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.grid = HugeTableGrid(self, log)
        self.grid.SetColMinimalAcceptableWidth(0)
        b1 = wx.Button(self, -1, "1")
        b2 = wx.Button(self, -1, "2")
        sizer.Add(self.grid, 1, wx.ALL|wx.EXPAND, 5)
        sizer.Add(b1, 0, wx.ALL, 5)
        sizer.Add(b2, 0, wx.ALL, 5)
        self.SetSizer(sizer)
 
        self.Bind(wx.EVT_BUTTON, self.OnButton1, b1)
        self.Bind(wx.EVT_BUTTON, self.OnButton2, b2)
 
    def OnButton1(self, event) :
        for i in range(0, 20000) :
            self.grid.SetColSize(i, 0)
        self.grid.table.ResetView(self.grid)
 
    def OnButton2(self, event) :
        self.grid.SetColSize(10, 100)
        self.grid.table.ResetView(self.grid)
 
if __name__ == '__main__':
    import sys
    app = wx.PySimpleApp()
    frame = TestFrame(None, sys.stdout)
    frame.Show(True)
    app.MainLoop()
 
 

Robin Dunn

unread,
Oct 20, 2008, 7:15:07 PM10/20/08
to wxpytho...@lists.wxwidgets.org

The problem is that although setting the column sizes to zero may hide
them visually, but they still must be traversed when the grid is
figuring out what to display, and fetching values for those items, etc.
Also compounding the problem is that the grid maintains a sparse array
of column widths. When the column width is the default width then it
doesn't need to do anything, but when a non default width is set for a
col then it needs to look at that array to get the width, and it's not
real efficient when there are lots of them.


The approach that I prefer to take in things like this is to fool the
grid and do some magic in the table. For example, if you've got N
columns and 5 of them are to be hidden, then tell the grid that you've
got N-5 columns and just map the values in the real column to the
adjusted column that the grid is asking for. This way, the grid won't
be doing any useless work for the 5 (or 50, or 5000, or whatever)
columns that are hidden, and you have more control in the table over
what is displayed and how it is displayed.

Of course an even better answer is to only deal with the data that is
necessary to provide what is supposed to be visible to the user, and
leave the rest of it in the database or wherever it is coming from.

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Massi

unread,
Oct 21, 2008, 5:11:54 AM10/21/08
to wxpytho...@lists.wxwidgets.org
Hmmmm, there's still something I can't understand. If I simply modify the
code of the function OnButton1 as follows, everything works fine:

def OnButton1(self, event) :
for i in range(0, 19999) :
self.grid.SetColSize(i, 0)
self.grid.table.ResetView(self.grid)

I mean, 19999 columns are hidden and only one is displayed.
But then if I press button 2, again the gui becomes very slow. It seems a
pretty strange behavior to me...


> Date: Mon, 20 Oct 2008 21:17:50 +0200
> From: raffaello <barbaros...@gmail.com>
> Subject: Re: [wxpython-users] wx.Grid, Hiding columns
> To: wxpytho...@lists.wxwidgets.org
> Message-ID:
> <5caf8fc00810201217rfe...@mail.gmail.com>
> Content-Type: text/plain; charset="iso-8859-1"
>
> I am afraid you want too much from your RAM: I tried your code, only
> reducing the number of columns to 200, and it runs smoothly.
> Unless there's a compelling necessity to have all data included at the
> same
> time in one grid (that nobody could swallow it in one gulp), I suggest
> that
> you put the data into a database, and trust the selection of the ones the
> user wants to see at any given moment to a SELECT query: the resulting
> output should arrive much faster.
>
> BTW in databases the number of columns is usually fixed, because they
> describe the categories of data, while the rows -containing the actual
> data-
> vary: so rows tend to become more numerous than columns.
>
> 2008/10/20 Massi <mass...@msn.com>


>
>> I post a little example code to show what I mean (I simply modified one
>> of the example of the demo), just run the code, press button 1 and then
>> button 2 and, for example, try to use the scrollbar. That simulates

>> exact=
> ly


>> what happens in my program.
>>
>> import wx
>> import wx.grid as gridlib
>>
>> class HugeTable(gridlib.PyGridTableBase):
>>
>> def __init__(self, log):
>> gridlib.PyGridTableBase.__init__(self)

>> self.log =3D log
>> self._rows =3D self.GetNumberRows()
>> self._cols =3D self.GetNumberCols()


>>
>> def ResetView(self, grid):
>> grid.BeginBatch()
>> for current, new, delmsg, addmsg in [(self._rows,
>> self.GetNumberRows(), gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED,
>> gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED),
>> (self._cols, self.GetNumberCols(),
>> gridlib.GRIDTABLE_NOTIFY_COLS_DELETED,
>> gridlib.GRIDTABLE_NOTIFY_COLS_APPENDED),]:
>> if new < current:

>> msg =3D
>> gridlib.GridTableMessage(self,delmsg,new,current-=


> new)
>> grid.ProcessTableMessage(msg)
>> elif new > current:

>> msg =3D gridlib.GridTableMessage(self,addmsg,new-current)
>> grid.ProcessTableMessage(msg)
>> self.UpdateValues(grid)
>> grid.EndBatch()
>> self._rows =3D self.GetNumberRows()
>> self._cols =3D self.GetNumberCols()


>> grid.AdjustScrollbars()
>> grid.ForceRefresh()
>>
>> def UpdateValues(self, grid):

>> msg =3D gridlib.GridTableMessage(self,


>> gridlib.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
>> grid.ProcessTableMessage(msg)
>>
>> def GetNumberRows(self):
>> return 100
>>
>> def GetNumberCols(self):
>> return 20000
>>
>> def GetValue(self, row, col):
>> return str( (row, col) )
>>
>> class HugeTableGrid(gridlib.Grid):
>> def __init__(self, parent, log):
>> gridlib.Grid.__init__(self, parent, -1)

>> self.table =3D HugeTable(log)
>> self.SetTable(self.table, True)
>>
>>
>>
>> #------------------------------------------------------------------------=


> ---
>>
>> class TestFrame(wx.Frame):
>> def __init__(self, parent, log):

>> wx.Frame.__init__(self, parent, -1, "", size=3D(840, 680))
>> sizer =3D wx.BoxSizer(wx.VERTICAL)
>> self.grid =3D HugeTableGrid(self, log)
>> self.grid.SetColMinimalAcceptableWidth(0)
>> b1 =3D wx.Button(self, -1, "1")
>> b2 =3D wx.Button(self, -1, "2")


>> sizer.Add(self.grid, 1, wx.ALL|wx.EXPAND, 5)
>> sizer.Add(b1, 0, wx.ALL, 5)
>> sizer.Add(b2, 0, wx.ALL, 5)
>> self.SetSizer(sizer)
>>
>> self.Bind(wx.EVT_BUTTON, self.OnButton1, b1)
>> self.Bind(wx.EVT_BUTTON, self.OnButton2, b2)
>>
>> def OnButton1(self, event) :
>> for i in range(0, 20000) :
>> self.grid.SetColSize(i, 0)
>> self.grid.table.ResetView(self.grid)
>>
>> def OnButton2(self, event) :
>> self.grid.SetColSize(10, 100)
>> self.grid.table.ResetView(self.grid)
>>

>> if __name__ =3D=3D '__main__':
>> import sys
>> app =3D wx.PySimpleApp()
>> frame =3D TestFrame(None, sys.stdout)
>> frame.Show(True)
>> app.MainLoop()

raffaello

unread,
Oct 20, 2008, 3:17:50 PM10/20/08
to wxpytho...@lists.wxwidgets.org
I am afraid you want too much from your RAM: I tried your code, only reducing the number of columns to 200, and it runs smoothly.
Unless there's a compelling necessity to have all data included at the same time in one grid (that nobody could swallow it in one gulp), I suggest that you put the data into a database, and trust the selection of the ones the user wants to see at any given moment to a SELECT query: the resulting output should arrive much faster.

BTW in databases the number of columns is usually fixed, because they describe the categories of data, while the rows -containing the actual data- vary: so rows tend to become more numerous than columns.

2008/10/20 Massi <mass...@msn.com>
I post a little example code to show what I mean (I simply modified one of the example of the demo), just run the code, press button 1 and then button 2 and, for example, try to use the scrollbar. That simulates exactly what happens in my program.

_______________________________________________
wxpython-users mailing list
wxpytho...@lists.wxwidgets.org
http://lists.wxwidgets.org/mailman/listinfo/wxpython-users


Reply all
Reply to author
Forward
0 new messages