bad wxGrid refresh after row count changes

I don't remember where this code came from, but I stuck it in my
GridTable and it seems to do the job...

    def ResetView(self):
        """Trim/extend the control's rows and update all values"""
        self.GetView().BeginBatch()
        for current, new, delmsg, addmsg in [
            (self.GetView().GetNumberRows(), self.GetNumberRows(),
wxGRIDTABLE_NOTIFY_ROWS_DELETED, wxGRIDTABLE_NOTIFY_ROWS_APPENDED),
            (self.GetView().GetNumberCols(), self.GetNumberCols(),
wxGRIDTABLE_NOTIFY_COLS_DELETED, wxGRIDTABLE_NOTIFY_COLS_APPENDED),
        ]:
            if new < current:
                msg = wxGridTableMessage(
                        self,
                        delmsg,
                        new, # position
                        current-new,
                )
                self.GetView().ProcessTableMessage(msg)
            elif new > current:
                msg = wxGridTableMessage(
                        self,
                        addmsg,
                        new-current
                )
                self.GetView().ProcessTableMessage(msg)
        self.UpdateValues()
        self.GetView().EndBatch()

        # The scroll bars aren't resized (at least on windows)
        # Jiggling the size of the window rescales the scrollbars
        grid = self.GetView()
        h,w = grid.GetSize()
        grid.SetSize((h+1, w))
        grid.SetSize((h, w))
        grid.ForceRefresh()

HTH

-Mark

···

On Mon, 2003-12-01 at 19:11, Jean Brouwers wrote:

We have been trying for several days now to get wxGrid to refresh
a table correctly after some rows have been added to a custom data
table using AppendRows().

Using ForceRefresh() simply does not fully refresh the grid. Nothing
seems to update the screen image completely, there are always blank
spots or even partial images of the grid on top of each other.

Mark,

Thank you for this reply. This is exactly the same code as
we have been using already.

Btw, this originates from one of the examples and is used when
rows or columns are moved.

The 'jiggle' trick at the end is important and it works, but
not always. As I mentioned, the scroll bar disappears and
that is one of the main symptoms.

/Jean Brouwers

Roach, Mark R. wrote:

···

On Mon, 2003-12-01 at 19:11, Jean Brouwers wrote:

We have been trying for several days now to get wxGrid to refresh
a table correctly after some rows have been added to a custom data
table using AppendRows().

Using ForceRefresh() simply does not fully refresh the grid. Nothing
seems to update the screen image completely, there are always blank
spots or even partial images of the grid on top of each other.

I don't remember where this code came from, but I stuck it in my GridTable and it seems to do the job...

    def ResetView(self): """Trim/extend the control's rows and update all values""" self.GetView().BeginBatch() for current, new, delmsg, addmsg in [ (self.GetView().GetNumberRows(), self.GetNumberRows(),
wxGRIDTABLE_NOTIFY_ROWS_DELETED, wxGRIDTABLE_NOTIFY_ROWS_APPENDED), (self.GetView().GetNumberCols(), self.GetNumberCols(),
wxGRIDTABLE_NOTIFY_COLS_DELETED, wxGRIDTABLE_NOTIFY_COLS_APPENDED), ]: if new < current: msg = wxGridTableMessage( self, delmsg, new, # position current-new, ) self.GetView().ProcessTableMessage(msg) elif new > current: msg = wxGridTableMessage( self, addmsg, new-current ) self.GetView().ProcessTableMessage(msg) self.UpdateValues() self.GetView().EndBatch()

        # The scroll bars aren't resized (at least on windows) # Jiggling the size of the window rescales the scrollbars
        grid = self.GetView()
        h,w = grid.GetSize() grid.SetSize((h+1, w)) grid.SetSize((h, w)) grid.ForceRefresh()

HTH

-Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

Jean,

I am using similar code to the one below and it works fine. BUT did you see/note the difference between Mark's code and the sample on the Wiki page.

Wiki page code snippet:

for current, new, delmsg, addmsg in [ (self.currentRows, self.GetNumberRows(), wxGRIDTABLE_NOTIFY_ROWS_DELETED, wxGRIDTABLE_NOTIFY_ROWS_APPENDED), (self.currentColumns, self.GetNumberCols(), wxGRIDTABLE_NOTIFY_COLS_DELETED, wxGRIDTABLE_NOTIFY_COLS_APPENDED),

Which means you have to ensure that self.currentRows and self.currentColumns are maintained correctly - maybe obvious to you but it wasn't to me for some time.

Where Mark's code seems to be a bit smarter (I haven't tried it but it looks neet!), as he is using

for current, new, delmsg, addmsg in [
  (self.GetView().GetNumberRows(), self.GetNumberRows().....

See you
Werner

Jean Brouwers wrote:

···

Mark,

Thank you for this reply. This is exactly the same code as
we have been using already.

Btw, this originates from one of the examples and is used when
rows or columns are moved.

The 'jiggle' trick at the end is important and it works, but
not always. As I mentioned, the scroll bar disappears and
that is one of the main symptoms.

/Jean Brouwers

Roach, Mark R. wrote:

On Mon, 2003-12-01 at 19:11, Jean Brouwers wrote:

We have been trying for several days now to get wxGrid to refresh
a table correctly after some rows have been added to a custom data
table using AppendRows().

Using ForceRefresh() simply does not fully refresh the grid. Nothing
seems to update the screen image completely, there are always blank
spots or even partial images of the grid on top of each other.

I don't remember where this code came from, but I stuck it in my GridTable and it seems to do the job...
    def ResetView(self): """Trim/extend the control's rows and update all values""" self.GetView().BeginBatch() for current, new, delmsg, addmsg in [ (self.GetView().GetNumberRows(), self.GetNumberRows(),
wxGRIDTABLE_NOTIFY_ROWS_DELETED, wxGRIDTABLE_NOTIFY_ROWS_APPENDED), (self.GetView().GetNumberCols(), self.GetNumberCols(),
wxGRIDTABLE_NOTIFY_COLS_DELETED, wxGRIDTABLE_NOTIFY_COLS_APPENDED), ]: if new < current: msg = wxGridTableMessage( self, delmsg, new, # position current-new, ) self.GetView().ProcessTableMessage(msg) elif new > current: msg = wxGridTableMessage( self, addmsg, new-current ) self.GetView().ProcessTableMessage(msg) self.UpdateValues() self.GetView().EndBatch()
        # The scroll bars aren't resized (at least on windows) # Jiggling the size of the window rescales the scrollbars
        grid = self.GetView()
        h,w = grid.GetSize() grid.SetSize((h+1, w)) grid.SetSize((h, w)) grid.ForceRefresh()

HTH

-Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

Roach, Mark R. wrote:

        # The scroll bars aren't resized (at least on windows) # Jiggling the size of the window rescales the scrollbars
        grid = self.GetView()
        h,w = grid.GetSize() grid.SetSize((h+1, w)) grid.SetSize((h, w)) grid.ForceRefresh()

Did you try calling grid.AdjustScrollbars instead of jiggling?

···

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

Robin,

What is the signature for AdjustScrollbars()? Also, from the
wxWindows doc, it seems that we'd have to write such a function.
Is that correct.

Let me reiterate, the problem is not just the vertical scollbar.
The grid itself if not or not entirely repainted.

Would you advise against calling grid.SetTable() more than once
for a grid? If that is possible, it may resolve the problem
since the grid is always correctly drawn, initially.

If not, the final option is to create and new grid and use the
existing data table. That requires adding and reorganizing the
code to restore the sizes, position, etc. of the grid to avoid
flashes and sudden visual changes.

/Jean Brouwers

Robin Dunn wrote:

···

Roach, Mark R. wrote:

        # The scroll bars aren't resized (at least on windows) # Jiggling the size of the window rescales the scrollbars
        grid = self.GetView()
        h,w = grid.GetSize() grid.SetSize((h+1, w)) grid.SetSize((h, w)) grid.ForceRefresh()

Did you try calling grid.AdjustScrollbars instead of jiggling?

Jean Brouwers writes:

Would you advise against calling grid.SetTable() more than
once for a grid?

I'd like to know if this is possible as well. I've tried
destroying the table, but I still get errors when calling
SetTable() a second time.

···

--
Paul

Jean and Paul,

Paul McNett wrote:

Jean Brouwers writes:

Would you advise against calling grid.SetTable() more than
once for a grid?
   
I'd like to know if this is possible as well. I've tried destroying the table, but I still get errors when calling SetTable() a second time.

I don't think so, see the wiki page at http://wiki.wxpython.org/index.cgi/wxGrid it states:

Note: you can only call Set*Table* once for any given wxGrid. Because of this, it is generally necessary to have your wxPyGrid*Table*Base <http://wiki.wxpython.org/index.cgi/wxPyGridTableBase&gt; class alter the grid's size and shape to reflect any changes in your *table*'s dimensions. See *wxGrid Size/Shape Management* below for details.

I only used the wxGrid once so far, so I am by no means an expert with wxGrid, for that matter nor with wxPython. As my data is coming from a DB, I actually add/delete rows in the approriate table, and then update the wxPyGridTableBase by reading the database table, then table.ResetView and grid.ForceRefresh. I just checked again but don't seem to have any problems with the scrollbars (note that my grid's number of columns is constant), and I don't even need to jiggle them.

I am on Windows XP Prof with Python 2.3 and wxPython 2.4.2.4.

See you
Werner

Jean Brouwers wrote:

Robin,

What is the signature for AdjustScrollbars()?

  void AdjustScrollbars();

> Also, from the

wxWindows doc, it seems that we'd have to write such a function.
Is that correct.

No, it's there. It's part of a set of deprecated wxScrolledWindow methods that have been removed from the docs because there are new ways to do things now, (SetVirtualSize, etc.) But the wxGrid is still doing scrolling internally the old way and the bug you described can usually be solved by calling AdjustScrollbars.

Let me reiterate, the problem is not just the vertical scollbar.
The grid itself if not or not entirely repainted.

Try grid.ForceRefresh() or grid.GetGridWindow().Refresh(False)

Would you advise against calling grid.SetTable() more than once
for a grid?

It can't be done. (Although with a bit of work on wxGrid it could be.)

···

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

Robin,

This issue is the single, most important problem for the system
we built with a GUI based on wxPython. The grid *must* work
correctly since it is at the center of the entire system.

We will try all three suggestions you and others made. Hopefully,
one or several will fix the problem. We'll keep you posted.

/Jean Brouwers

Robin Dunn wrote:

···

Jean Brouwers wrote:

Robin,

What is the signature for AdjustScrollbars()?

    void AdjustScrollbars();

> Also, from the

wxWindows doc, it seems that we'd have to write such a function.
Is that correct.

No, it's there. It's part of a set of deprecated wxScrolledWindow methods that have been removed from the docs because there are new ways to do things now, (SetVirtualSize, etc.) But the wxGrid is still doing scrolling internally the old way and the bug you described can usually be solved by calling AdjustScrollbars.

Let me reiterate, the problem is not just the vertical scollbar.
The grid itself if not or not entirely repainted.

Try grid.ForceRefresh() or grid.GetGridWindow().Refresh(False)

Would you advise against calling grid.SetTable() more than once
for a grid?

It can't be done. (Although with a bit of work on wxGrid it could be.)

The answer is no, it is not possible to call SetTable()
more than once for a grid. As soon as SetTable() is
called more than once, a message is printed and the
call is ignored.

That leaves only one option open*, recreate the grid with
an existing data table. But when a data table is used or
reused in several grids, make sure that the second argument
in the SetTable() call to False to prevent the grid from
destroying the data table.

/Jean Brouwers

*) We have made some progress with updating the grid
after the number or rows and/or colums of the data table
changed. However, the testing is not yet complete and
there is another, new, grid cell attr issue. Both will
be reported in seperate emails.

Werner F. Bruhin wrote:

···

Jean and Paul,

Paul McNett wrote:

Jean Brouwers writes:

Would you advise against calling grid.SetTable() more than
once for a grid?
  
I'd like to know if this is possible as well. I've tried destroying the table, but I still get errors when calling SetTable() a second time.

I don't think so, see the wiki page at http://wiki.wxpython.org/index.cgi/wxGrid it states:

Note: you can only call Set*Table* once for any given wxGrid. Because of this, it is generally necessary to have your wxPyGrid*Table*Base <http://wiki.wxpython.org/index.cgi/wxPyGridTableBase&gt; class alter the grid's size and shape to reflect any changes in your *table*'s dimensions. See *wxGrid Size/Shape Management* below for details.

I only used the wxGrid once so far, so I am by no means an expert with wxGrid, for that matter nor with wxPython. As my data is coming from a DB, I actually add/delete rows in the approriate table, and then update the wxPyGridTableBase by reading the database table, then table.ResetView and grid.ForceRefresh. I just checked again but don't seem to have any problems with the scrollbars (note that my grid's number of columns is constant), and I don't even need to jiggle them.

I am on Windows XP Prof with Python 2.3 and wxPython 2.4.2.4.

See you
Werner

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

Finally, some good news! Grid updates are now working correctly
after incorporating the suggestions from the past several days.

Our special thanks to Werner Bruhin, Robin Dunn, Mike Fletcher,
Cristina Jocob and Paul McNett for your time and effort with
this issue.

/Jean Brouwers
  ProphICy Semiconductor

PS) Here is what the ciritical code for grid update now looks
like. It can be part of a grid or table method, but make sure
to use the correct object in various calls.

     ....
     # don't call SetTable() more than once;
     # use False to prevent table from being
     # destroyed when the grid is deleted
    grid.SetTable(table, False)
     ....
     # update the number of rows
    grid.BeginBatch()
    if new_num_rows > old_num_rows:
        m = wxGridTableMessage(table, # the table
                               wxGRIDTABLE_NOTIFY_ROWS_APPENDED, # what
                               new_num_rows - old_num_rows) # how many
        grid.ProcessTableMessage(m)
    elif new_num_rows < old_num_rows:
        m = wxGridTableMessage(table, # the table
                               wxGRIDTABLE_NOTIFY_ROWS_DELETED, # what
                               new_num_rows, # from here
                               old_num_rows - new_num_rows) # how many
        grid.ProcessTableMessage(m)
     # update number of columns (similarly)
     ....
    grid.EndBatch()
     # not sure about this ...
    m = wxGridTableMessage(table, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES)
    grid.ProcessTableMessage(m)
     ....
     # force row heights to default (superfluous?)
    h = grid.GetDefaultRowSize()
    grid.SetDefaultRowSize(h, True)
     ....
     # update the scroll bars
    try: # may be depricated
        grid.AdjustScrollbars()
    except: # jiggle the grid
        w, h = grid.GetSize() #
        grid.SetSize((w+1, h+1))
        grid.SetSize((w, h))
     # finally, update screen
    grid.ForceRefresh()
     ....

Jean Brouwers wrote:

···

Robin,

This issue is the single, most important problem for the system
we built with a GUI based on wxPython. The grid *must* work
correctly since it is at the center of the entire system.

We will try all three suggestions you and others made. Hopefully,
one or several will fix the problem. We'll keep you posted.

/Jean Brouwers

Robin Dunn wrote:

Jean Brouwers wrote:

Robin,

What is the signature for AdjustScrollbars()?

    void AdjustScrollbars();

> Also, from the

wxWindows doc, it seems that we'd have to write such a function.
Is that correct.

No, it's there. It's part of a set of deprecated wxScrolledWindow methods that have been removed from the docs because there are new ways to do things now, (SetVirtualSize, etc.) But the wxGrid is still doing scrolling internally the old way and the bug you described can usually be solved by calling AdjustScrollbars.

Let me reiterate, the problem is not just the vertical scollbar.
The grid itself if not or not entirely repainted.

Try grid.ForceRefresh() or grid.GetGridWindow().Refresh(False)

Would you advise against calling grid.SetTable() more than once
for a grid?

It can't be done. (Although with a bit of work on wxGrid it could be.)

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

Our appologies, we failed to mention and thank Mark Roach also.

/Jean Brouwers
  ProphICy Semiconductor

Jean Brouwers wrote:

···

Finally, some good news! Grid updates are now working correctly
after incorporating the suggestions from the past several days.

Our special thanks to Werner Bruhin, Robin Dunn, Mike Fletcher,
Cristina Jocob and Paul McNett for your time and effort with
this issue.

/Jean Brouwers
ProphICy Semiconductor

PS) Here is what the ciritical code for grid update now looks
like. It can be part of a grid or table method, but make sure
to use the correct object in various calls.

    ....
    # don't call SetTable() more than once;
    # use False to prevent table from being
    # destroyed when the grid is deleted
   grid.SetTable(table, False)
    ....
    # update the number of rows
   grid.BeginBatch()
   if new_num_rows > old_num_rows:
       m = wxGridTableMessage(table, # the table
                              wxGRIDTABLE_NOTIFY_ROWS_APPENDED, # what
                              new_num_rows - old_num_rows) # how many
       grid.ProcessTableMessage(m)
   elif new_num_rows < old_num_rows:
       m = wxGridTableMessage(table, # the table
                              wxGRIDTABLE_NOTIFY_ROWS_DELETED, # what
                              new_num_rows, # from here
                              old_num_rows - new_num_rows) # how many
       grid.ProcessTableMessage(m)
    # update number of columns (similarly)
    ....
   grid.EndBatch()
    # not sure about this ...
   m = wxGridTableMessage(table, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES)
   grid.ProcessTableMessage(m)
    ....
    # force row heights to default (superfluous?)
   h = grid.GetDefaultRowSize()
   grid.SetDefaultRowSize(h, True)
    ....
    # update the scroll bars
   try: # may be depricated
       grid.AdjustScrollbars()
   except: # jiggle the grid
       w, h = grid.GetSize() #
       grid.SetSize((w+1, h+1))
       grid.SetSize((w, h))
    # finally, update screen
   grid.ForceRefresh()
    ....

Jean Brouwers wrote:

Robin,

This issue is the single, most important problem for the system
we built with a GUI based on wxPython. The grid *must* work
correctly since it is at the center of the entire system.

We will try all three suggestions you and others made. Hopefully,
one or several will fix the problem. We'll keep you posted.

/Jean Brouwers

Robin Dunn wrote:

Jean Brouwers wrote:

Robin,

What is the signature for AdjustScrollbars()?

    void AdjustScrollbars();

> Also, from the

wxWindows doc, it seems that we'd have to write such a function.
Is that correct.

No, it's there. It's part of a set of deprecated wxScrolledWindow methods that have been removed from the docs because there are new ways to do things now, (SetVirtualSize, etc.) But the wxGrid is still doing scrolling internally the old way and the bug you described can usually be solved by calling AdjustScrollbars.

Let me reiterate, the problem is not just the vertical scollbar.
The grid itself if not or not entirely repainted.

Try grid.ForceRefresh() or grid.GetGridWindow().Refresh(False)

Would you advise against calling grid.SetTable() more than once
for a grid?

It can't be done. (Although with a bit of work on wxGrid it could be.)

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

We overload the GetAttr(self, row, col) method in a
wxPyGridTableBase subclass and return one of several,
statically created instances of wxGridCellAttr.

However, the caller of wxGetAttr() seems to be destroying
the returned attribute instance and that results in a crash*.
To avoid that, we are now returning a clone of the attribute.

The question is this the proper and best way to handle this?
The overhead of creating a clone which then is deleted, on
every single call seems very high. Isn't there a a more
efficient way to protect wxGridCellAttr instances?

/Jean Brouwers

*) This is wxPython 2.4.1.2 and Python 2.3.1 on Linux
RedHat 8 with GTK2.

Jean Brouwers wrote:

We overload the GetAttr(self, row, col) method in a
wxPyGridTableBase subclass and return one of several,
statically created instances of wxGridCellAttr.

However, the caller of wxGetAttr() seems to be destroying
the returned attribute instance and that results in a crash*.
To avoid that, we are now returning a clone of the attribute.

I had the same issue a few weeks ago. The response from Robin
which fixed it was to call IncRef on the attr you return.

Roger

That has a similar, unnecessary overhead, probably less than
Clone. The question is, can attributes not be configured
at creation time, such that they will never be deleted.

This points to a flaw in the Phython wxWindows interface,
since this is an object created and owned by Python but
wxWindows just wipes it out. Then, the Python level has
to jumps through hoops to fix that.

/Jean

Roger Binns wrote:

···

Jean Brouwers wrote:

We overload the GetAttr(self, row, col) method in a
wxPyGridTableBase subclass and return one of several,
statically created instances of wxGridCellAttr.

However, the caller of wxGetAttr() seems to be destroying
the returned attribute instance and that results in a crash*.
To avoid that, we are now returning a clone of the attribute.

I had the same issue a few weeks ago. The response from Robin
which fixed it was to call IncRef on the attr you return.

Roger

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

Jean Brouwers wrote:

That has a similar, unnecessary overhead, probably less than
Clone. The question is, can attributes not be configured
at creation time, such that they will never be deleted.

IncRef increments a reference count in the existing object.
That also happens to be exactly how Python internals also
work. There is no way of being any more efficient. (Clone
on the other hand allocates a new copy of the object).

Roger

Roger,

Well there is a better, more efficient and consistent way.
The caller of GetAttr() should not destroy the returned
attribute object. Why is that happening?

To illustrate the point, assume the following Python code:

     _version = 1.2.3

     def version():
         global _version
         return _version

What happens to the _version object after function version()
has called? Is it deleted?

If not, why would an wxGridCellAttr object be deleted by a
GetAttr() call?

/Jean Brouwers

Roger Binns wrote:

···

Jean Brouwers wrote:

That has a similar, unnecessary overhead, probably less than
Clone. The question is, can attributes not be configured
at creation time, such that they will never be deleted.

IncRef increments a reference count in the existing object. That also happens to be exactly how Python internals also
work. There is no way of being any more efficient. (Clone
on the other hand allocates a new copy of the object).

Roger

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

If not, why would an wxGridCellAttr object be deleted by a
GetAttr() call?

GridCellAttr objects *ARE* reference counted. They are *only*
deleted when the reference count hits zero indicating that
noone is using them.

Due to an artifact of the wxPython wrapping, the reference
count isn't increased and wx thinks it is no longer in
use when it is. Calling IncRef manually solves the problem.

Roger

We overload the GetAttr() method in a subclassed wxPyGridTableBase
and return a specific instance of wxGridCellAttr for each call
based on the value row and col arguments.

There are only five different attributes for the entire grid. Three
of those to align columns left, center or right. One for a different
background color in certain rows and a default attribute.

There are two issues:

(1) While the correct attribute object is returned by each call to
GetAttr(), the alignment, color, etc. is not applied in any of the
grid cells or columns. Other than returning the attribute is there
anything else we need to do?

(2) The GetAttr() methods has 4 args, incl. self. What is the purpose
of the last arg? Right now it is just ignored.

/Jean Brouwers

Jean Brouwers wrote:

Roger,

Well there is a better, more efficient and consistent way.
The caller of GetAttr() should not destroy the returned
attribute object. Why is that happening?

Because when the caller is finished with the attr it calls DecRef. It does not store an attr reference for every cell, that is what the the wxGridCellAttrProvider and/or the wxGridTableBase is for.

To illustrate the point, assume the following Python code:

    _version = 1.2.3

    def version():
        global _version
        return _version

What happens to the _version object after function version()
has called? Is it deleted?

No, because there is an implicit IncRef as part of the return statement. C++ based ref counting doesn't do that so we have to help it a little. The Python part of the attr object *is* reference counted properly by Python, but it just holds a pointer to the C++ object that has no clue about the Python reference count.

If it makes you feel any better, C++ code using grid attr objects has to do exactly the same thing.

If not, why would an wxGridCellAttr object be deleted by a
GetAttr() call?

If you don't IncRef the C++ object then when the caller DefRef's it then it will be deleted when the reference count drops to zero.

···

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