Access violation exception when use own wxDataViewVirtualListModel. 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
Kvaz1r
Super wx Problem Solver
Super wx Problem Solver
Posts: 357
Joined: Tue Jun 07, 2016 1:07 pm

Access violation exception when use own wxDataViewVirtualListModel.

Post by Kvaz1r »

If size of vector not less than NUMBER_OF_ITEMS all works as expected, if I change it to something less - getting access violation. I've created model by analogy to model from dataview sample.

MCVE:

Code: Select all

#include <wx/wx.h>
#include <wx/dialog.h>
#include <wx/dataview.h>
#include <utility>

typedef std::pair<wxString,wxDouble> Data;
#define NUMBER_OF_ITEMS 50

class MyListModel: public wxDataViewVirtualListModel
{
public:
    enum { Col_Key, Col_Value, Col_Max};

    MyListModel(const wxVector<Data> &vec):
        wxDataViewVirtualListModel( NUMBER_OF_ITEMS ),m_values(vec)
    { }

    virtual unsigned int GetColumnCount() const wxOVERRIDE
    {
        return Col_Max;
    }

    virtual wxString GetColumnType( unsigned int col ) const wxOVERRIDE
    {
        return wxT("string");
    }

    virtual void GetValueByRow( wxVariant &variant,
                                unsigned int row, unsigned int col ) const wxOVERRIDE
    {
        switch ( col )
        {
        case Col_Key:
        {
            variant = m_values[row].first;
        }
        break;
        case Col_Value:
        {
            variant = wxString::Format("%lf", m_values[row].second);
        }
        break;
        case Col_Max:
            wxFAIL_MSG( "invalid column" );
        }
    }
    virtual bool SetValueByRow( const wxVariant &variant,
                                unsigned int row, unsigned int col ) wxOVERRIDE
    {
        switch ( col )
        {
        case Col_Key:
        {
            m_values[row].first = variant.GetString();
        }
        break;
        case Col_Value:
        {
            m_values[row].second = variant.GetDouble();
        }
        break;
        case Col_Max:
            return false;
        }
        return true;
    }

private:
    wxVector<Data> m_values;
};

class TableDialog : public wxDialog
{
public:
    TableDialog(): wxDialog( nullptr, wxID_ANY, "")
    {
        wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
        m_dataviewctrl = new wxDataViewCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_HORIZ_RULES|wxDV_VERT_RULES );
        wxVector<Data> vec(NUMBER_OF_ITEMS/2);
        for(std::size_t i = 0; i<vec.size(); i++)
        {
            vec[i] = std::make_pair(wxString::Format("%d",i),i*i);
        }
        m_list_model = new MyListModel(vec);
        m_dataviewctrl->AssociateModel( m_list_model.get() );

        m_dataviewctrl->AppendTextColumn("Ключ",MyListModel::Col_Key,
                                         wxDATAVIEW_CELL_INERT,wxCOL_WIDTH_AUTOSIZE,wxALIGN_NOT,
                                         wxDATAVIEW_COL_SORTABLE);
        m_dataviewctrl->AppendTextColumn("Значение", MyListModel::Col_Value,
                                         wxDATAVIEW_CELL_INERT,wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT,
                                         wxDATAVIEW_COL_SORTABLE);
        topSizer->Add( m_dataviewctrl, 1, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5 );

        m_BClose = new wxButton( this, wxID_ANY, wxT("Закрыть"), wxDefaultPosition, wxDefaultSize, 0 );
        m_BClose->Bind(wxEVT_BUTTON, [&](wxCommandEvent&)
        {
            Close();
        });

        topSizer->Add( m_BClose, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
        this->SetSizer( topSizer );
        this->Maximize();
        this->Layout();
        topSizer->Fit( this );
        this->Centre( wxBOTH );
    }
    ~TableDialog(void) {}

protected:
    wxObjectDataPtr<MyListModel> m_list_model;
    wxDataViewCtrl* m_dataviewctrl;
    wxButton* m_BClose;
};

class TestFrame : public wxFrame
{
public:
    TestFrame(const wxString& title): wxFrame(NULL, wxID_ANY, title)
    {
        wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
        m_Button = new wxButton( this, wxID_ANY, wxT("Try"), wxDefaultPosition, wxDefaultSize, 0 );
        m_Button->Bind(wxEVT_BUTTON, [&](wxCommandEvent&)
        {
            TableDialog().ShowModal();
        });
        topSizer->Add( m_Button, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
        this->SetSizer( topSizer );
        this->Layout();
        topSizer->Fit( this );
        this->Centre( wxBOTH );
    }

protected:
    wxButton* m_Button;
};

class MyApp : public wxApp
{
public:
    virtual bool OnInit() wxOVERRIDE
    {
        if ( !wxApp::OnInit() )
            return false;

        TestFrame *frame = new TestFrame("Test");
        frame->Show(true);
        return true;
    }
};

wxIMPLEMENT_APP(MyApp);
Windows 7, wxWidgets 3.1.1 , dataview sample works.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Access violation exception when use own wxDataViewVirtualListModel.

Post by doublemax »

If size of vector not less than NUMBER_OF_ITEMS all works as expected, if I change it to something less - getting access violation.
That's to be expected. If you say the list has 50 items, GetValueByRow() will be called with row values from 0 to 49. And if your vector is too small, you get an exception.

The sample is a little confusing, in a real world application you wouldn't have a certain number of "real" items and then the rest "virtual" items.
Use the source, Luke!
Kvaz1r
Super wx Problem Solver
Super wx Problem Solver
Posts: 357
Joined: Tue Jun 07, 2016 1:07 pm

Re: Access violation exception when use own wxDataViewVirtualListModel.

Post by Kvaz1r »

doublemax wrote: Wed May 08, 2019 4:09 pm That's to be expected. If you say the list has 50 items, GetValueByRow() will be called with row values from 0 to 49. And if your vector is too small, you get an exception.

The sample is a little confusing, in a real world application you wouldn't have a certain number of "real" items and then the rest "virtual" items.
Thanks. It was indeed unclear for me where is real size and where is virtual. Now I see that it's an expected behaviour. I somehow thought that rows outside the active list window would load into control only by request.
Post Reply