in derived wxGridTableBase SetValue() is never called Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
smf
Knows some wx things
Knows some wx things
Posts: 32
Joined: Wed Nov 12, 2008 7:04 pm

in derived wxGridTableBase SetValue() is never called

Post by smf » Sat May 17, 2014 9:28 am

Hi,

I would like to use a virtual wxGrid. While the display of values works fine so far, I have some problems with editing cells. More specifically: Editing itself seems to work (I can enter a string into the cell for instance), but wxGridTableBase::SetValue is never called. Maybe someone has a hint of what to check? I guess it's something really stupid...

MTIA,
smf

Code: Select all

class GridTable : public wxGridTableBase
{
    public:

    // ... some setup-stuff removed, to keep this shorter...

    wxString GetValue(int row, int col)
    {
        wxString returnText(_("--"));

        if( (int)m_Data.size()    > col &&
            (int)m_Data[0].size() > row )
        {
            enum GridData::TYPE type;
            type = m_Data[col][row].getType();

            bool isValid;
            isValid = m_Data[col][row].isValid();

            if( isValid )
            {
                switch( type )
                {
                    case( GridData::TYPE_FLOAT ):
                    {
                        returnText.Printf( _("%3.2f %s"),
                                           m_Data[col][row].getFloatValue(),
                                           m_Data[col][row].getUnit() );
                    }
                    default:
                    {
                        returnText.Printf( _("--- %s"),
                                           m_Data[col][row].getUnit() );
                    }
                }
            }
        }
        return( returnText );
    };

    wxString GetTypeName( int row, int col )
    {
        return( wxGRID_VALUE_STRING );
    }

    bool CanSetValueAs( int row, int col, const wxString& typeName )
    {
        if( typeName == wxGRID_VALUE_STRING )
        {
            return( true );
        }
        return( false );
    }

    void SetValue(int row, int col, wxString const& value )
    {
        if( (int)m_Data.size()    > col &&
            (int)m_Data[0].size() > row )
        {
            enum GridData::TYPE type;
            type = m_Data[col][row].getType();

            switch( type )
            {
                case( GridData::TYPE_FLOAT ):
                {
                    double number;
                    if( value.ToDouble(&number) )
                    {
                        m_Data[col][row].setFloatValue( number );
                    }
                    m_Data[col][row].setFloatValue( 3.1415926 );
                }
                default:
                {
                    m_Data[col][row].invalidate();
                }
            }
        }
    };

    int GetNumberRows()
    {
        if( m_Data.size() > 0)
        {
            return( m_Data[0].size() );
        }
        return( 0 );
    }

    int GetNumberCols()
    {
        return( m_Data.size() );
    }

    wxString GetRowLabelValue( int row )
    {
        if( m_Data.size() > 0 &&
            row < m_Data[0].size() )
        {
            return( m_Data[0][row].getName() );
        }
        return( _("") );
    }

    private:
    std::vector<std::vector<GridData>>& m_Data;
};

User avatar
doublemax
Moderator
Moderator
Posts: 15860
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: in derived wxGridTableBase SetValue() is never called

Post by doublemax » Sat May 17, 2014 9:34 am

Code: Select all

void SetValue(int row, int col, wxString const& value )
I think this method is only called for wxString values.

Also check:

Code: Select all

virtual void SetValueAsLong (int row, int col, long value)
virtual void SetValueAsDouble (int row, int col, double value)
virtual void SetValueAsBool (int row, int col, bool value)
Use the source, Luke!

smf
Knows some wx things
Knows some wx things
Posts: 32
Joined: Wed Nov 12, 2008 7:04 pm

Re: in derived wxGridTableBase SetValue() is never called

Post by smf » Mon May 19, 2014 9:32 am

Code: Select all

void SetValue(int row, int col, wxString const& value )
I think this method is only called for wxString values.
... yes, but that shouldn't be a problem for a table pretending to only have string-capable cells... The real problem with the above line is, that it doesn't match the prototype. So it's not replacing the original function and therefor is never called. So, yes,... it was a really stupid error... :oops:

Despite setting this topic to "resolved", could you please give me a hint or two of how to achieve the following with wxGrid:

1. Content dependent colouring/editable-status (the datastructure wrapped into the wxGridTableBase I use, knows by itself if a cell is editable or not or if it's an intermediate result and I'd like to color code the cells with that information. My attempt in using wxCellAttr* wxTableBase::GetCellAttr(...); for this was not quite successful in that regard as trying to change anything in the wxCellAttr lead to a crash... *whoops*? Only reading seems to be allowed...)

2. If a cell has it's content changed, eg. by data-entry, then many other cells do change their content, too, due to internal recalculation of the table (like in a spreadsheet). While I could intercept WXK_RETURN like described here: http://wiki.wxwidgets.org/WxGrid and force a Refresh() in there, I wonder if there is another option (just sending a change-message doesn't seem to work... at least according to the same wiki-page)...?

smf

User avatar
doublemax
Moderator
Moderator
Posts: 15860
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: in derived wxGridTableBase SetValue() is never called

Post by doublemax » Mon May 19, 2014 1:42 pm

When using methods like wxTableBase::GetCellAttr(...) you must be aware that all these objects are reference counted and depending on what exactly you're doing, you have to manually increase or decrease the reference counter. Maybe show some code.
2. If a cell has it's content changed, eg. by data-entry, then many other cells do change their content, too
Shouldn't just catching the wxEVT_GRID_CELL_CHANGED event be enough?
http://docs.wxwidgets.org/trunk/classwx_grid_event.html
Use the source, Luke!

smf
Knows some wx things
Knows some wx things
Posts: 32
Joined: Wed Nov 12, 2008 7:04 pm

Re: in derived wxGridTableBase SetValue() is never called

Post by smf » Mon May 19, 2014 8:45 pm

Hi,

got everything working as I wanted it to, but the Attr-Handling. Seems like I have "some" misunderstanding of what is supposed to work how in that context...
doublemax wrote:Maybe show some code
Here we go. This is my overriden GetAttr() in my derived wxGridTableBase-class:

Code: Select all

    wxGridCellAttr* GetAttr( int row, int col, wxGridCellAttr::wxAttrKind kind )
    {
        // try to get current GridCellAttr
        wxGridCellAttr* attr = wxGridTableBase::GetAttr( row, col, kind );

        if( m_Data   .size() > (unsigned int)col &&
            m_Data[0].size() > (unsigned int)row )
        {
            // if no attribute associated with this cell, create one...
            if( !attr )
            {
                attr = new wxGridCellAttr();
                SetAttr( attr, row, col );
            }

            // modify it to suit needs
            if( m_Data[col][row].isResult() )
            {
                // try to set background
                attr->SetBackgroundColour( wxColour(240, 240, 240) );
                attr->SetReadOnly( true );
            }
        }

        return( attr );
    }
While I at first thought it would crash when setting the attributes it crashes (after some time) when creating and associating them with the corresponding GridCell. This puzzles me a little bit more... hmm,...

MTIA
smf

edit: added missing "and"...

User avatar
doublemax
Moderator
Moderator
Posts: 15860
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: in derived wxGridTableBase SetValue() is never called

Post by doublemax » Mon May 19, 2014 10:21 pm

The "grid" demo that comes with wxWidgets uses a similar method to get alternating row colors (File -> Bugs table test). Look at the IncRef() and DecRef() calls:

Code: Select all

wxGridCellAttr *MyGridCellAttrProvider::GetAttr(int row, int col,
                           wxGridCellAttr::wxAttrKind  kind /* = wxGridCellAttr::Any */) const
{
    wxGridCellAttr *attr = wxGridCellAttrProvider::GetAttr(row, col, kind);

    if ( row % 2 )
    {
        if ( !attr )
        {
            attr = m_attrForOddRows;
            attr->IncRef();
        }
        else
        {
            if ( !attr->HasBackgroundColour() )
            {
                wxGridCellAttr *attrNew = attr->Clone();
                attr->DecRef();
                attr = attrNew;
                attr->SetBackgroundColour(*wxLIGHT_GREY);
            }
        }
    }

    return attr;
}
if your code still crashes, try to get a callstack/backtrace.
Use the source, Luke!

Post Reply