Page 1 of 2
wxDataViewListCtrl and wxVariant
Posted: Tue Feb 05, 2019 8:23 pm
by refaelsh
I have a simple setup, a wxDataViewListCtrl, the first column uses wxDataViewCustomRenderer and the second column is just text.
Code: Select all
class MyCustomRenderer : public wxDataViewCustomRenderer
I add a line to the wxDataViewListCtrl like this:
Code: Select all
wxVector<wxVariant> item;
item.push_back(wxVariant(/*a raw pointer of MyClass goes here*/));
item.push_back(wxVariant("some string goes here"));
m_data_view_list_ctrl->AppendItem(item);
item.clear();
And this is MyClass:
Code: Select all
class MyClass final : public wxObject
And this is how my SetValue method looks like:
Code: Select all
bool MyCustomRenderer::SetValue(const wxVariant& value)
{
MyClass* temp = static_cast<MyClass*>(value.GetWxObjectPtr());
/*Do stuff with temp here...*/
return true;
}
It worked, now it does not. It fails with the following error:
https://www.dropbox.com/s/acxbzthp3ltad ... s.png?dl=0
The only thing I changed is that I updated my static libs of wxWidgets from 3.0.4 to 3.1.2.
Why has it stopped working? What am I missing here?
Please help me
Re: wxDataViewListCtrl and wxVariant
Posted: Wed Feb 06, 2019 5:51 pm
by ONEEYEMAN
Hi,
Looking at the SO question: are you populating the data in a thread? Maybe its just a timing issue?
Thank you.
Re: wxDataViewListCtrl and wxVariant
Posted: Wed Feb 06, 2019 7:05 pm
by refaelsh
ONEEYEMAN wrote:Hi,
Looking at the SO question: are you populating the data in a thread? Maybe its just a timing issue?
Thank you.
No, I am not populating it in a thread. I am populating it in the wxApp::OnInit method.
Re: wxDataViewListCtrl and wxVariant
Posted: Wed Feb 06, 2019 7:31 pm
by ONEEYEMAN
Hi,
Where the data is coming from? External device? Internet? File?
Right after you populated the data, is it good?
Thank you.
Re: wxDataViewListCtrl and wxVariant
Posted: Wed Feb 06, 2019 8:05 pm
by refaelsh
ONEEYEMAN wrote:
Hi,
Where the data is coming from? External device? Internet? File?
Its kinda hard to explain, but a good approximation would be "Internal" and/or "File".
I execute some shell command and parse the output to get the data.
ONEEYEMAN wrote:
Right after you populated the data, is it good?
Yes, it does. I've verified it.
Code: Select all
wxVector<wxVariant> item;
for (unsigned int i = 0; i < 400; ++i)
{
item.push_back(wxVariant(/*Raw pointer to an instance of MyClass*/));
item.push_back(wxVariant("some string goes here"));
frame->m_data_view_list_ctrl->AppendItem(item);
item.clear();
}
The data is good after the loop and in between iterations of the loop.
Re: wxDataViewListCtrl and wxVariant
Posted: Wed Feb 06, 2019 8:23 pm
by doublemax
Based on the callstack, i would suspect an error in MyCustomRenderer. I guess it's called before the control is filled with data and your code doesn't handle the situation properly.
But it's only a guess.
I don't know why it happened after the switch to 3.1.2.
Re: wxDataViewListCtrl and wxVariant
Posted: Wed Feb 06, 2019 8:27 pm
by ONEEYEMAN
Hi,
So this "Raw pointer to an instance of MyClass" is a good pointer and not NULL?
Thank you.
Re: wxDataViewListCtrl and wxVariant
Posted: Wed Feb 06, 2019 8:37 pm
by refaelsh
ONEEYEMAN wrote:Hi,
So this "Raw pointer to an instance of MyClass" is a good pointer and not NULL?
Thank you.
Correct.
Re: wxDataViewListCtrl and wxVariant
Posted: Thu Feb 07, 2019 7:45 am
by refaelsh
doublemax wrote:Based on the callstack, i would suspect an error in MyCustomRenderer. I guess it's called before the control is filled with data and your code doesn't handle the situation properly.
But it's only a guess.
I don't know why it happened after the switch to 3.1.2.
Your answer got me thinking. Since I did not change my code, something else must have changed. And now I notice a subtle change in the constructor of `wxDataViewCustomRenderer`.
Here is how I use it in my code:
Code: Select all
MyCustomRenderer::MyCustomRenderer() : wxDataViewCustomRenderer("commit", wxDATAVIEW_CELL_INERT, wxALIGN_CENTER)
They changed the constructor. Especially the first parameter. The documnantation for version 3.0.x says this:
https://docs.wxwidgets.org/3.0/classwx_ ... 89f70af50c
And fot version 3.1.x it says this:
https://docs.wxwidgets.org/3.1/classwx_ ... 350e1e3e6f
Notice the difference in the first parameter of the constructor? Maybe this causes the problem? Maybe I discovered a bug? Should I post it on
https://trac.wxwidgets.org?
Re: wxDataViewListCtrl and wxVariant
Posted: Thu Feb 07, 2019 8:09 am
by PB
FWIW, the change was made here
https://github.com/wxWidgets/wxWidgets/ ... 42eed7bcf2
I wonder if it makes an actual difference here, since wxDataViewCustomRenderer::GetDefaultType() still returns "string".
TBH, I am not familiar with the class so I have no idea if "commit" was actually a correct value for wxDataViewCustomRenderer's ctor...
Re: wxDataViewListCtrl and wxVariant
Posted: Thu Feb 07, 2019 8:22 am
by refaelsh
I agree, it does seems to make no difference.
PB wrote:
TBH, I am not familiar with the class so I have no idea if "commit" was actually a correct value for wxDataViewCustomRenderer's ctor...
After I've seen the difference in documentation of this class between v3.0 and v3.1, I also now understand that "commit" was wrong, bit it worked.
I've tried changing it to "string" (after updating to v3.1.2), it did not help.
Re: wxDataViewListCtrl and wxVariant
Posted: Thu Feb 07, 2019 8:23 am
by doublemax
Set a breakpoint in MyCustomRenderer::SetValue(), single step through the code and see what happens.
Re: wxDataViewListCtrl and wxVariant
Posted: Thu Feb 07, 2019 8:29 am
by refaelsh
Here is an mcve (
https://stackoverflow.com/help/mcve):
Code: Select all
#include <wx/wxprec.h>
#include <wx/dataview.h>
#include "MyCustomRenderer.h"
#include <wx/wx.h>
class MyApp : public wxApp
{
public:
virtual bool OnInit();
};
class MyFrame : public wxFrame
{
public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
};
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340));
frame->Show(true);
return true;
}
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame(NULL, wxID_ANY, title, pos, size)
{
wxDataViewListCtrl* data_view_list_ctrl = new wxDataViewListCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(-1, -1), wxDV_ROW_LINES | wxDV_SINGLE);
MyCustomRenderer* custom_renderer = new MyCustomRenderer();
wxDataViewColumn* data_view_column = new wxDataViewColumn("Some title goes here", custom_renderer,0);
data_view_list_ctrl->AppendColumn(data_view_column);
data_view_list_ctrl->AppendTextColumn("Some cool column title goes here");
wxVector<wxVariant> data;
data.push_back(wxVariant(42));
data.push_back(wxVariant("row 1"));
data_view_list_ctrl->AppendItem(data);
data.clear();
data.push_back(wxVariant(43));
data.push_back(wxVariant("row 3"));
data_view_list_ctrl->AppendItem(data);
}
And here is the `MyCustomRenderer` class:
Code: Select all
#include "MyCustomRenderer.h"
#include <wx/wx.h>
MyCustomRenderer::MyCustomRenderer() : wxDataViewCustomRenderer("string", wxDATAVIEW_CELL_INERT, wxALIGN_CENTER)
{
}
bool MyCustomRenderer::SetValue(const wxVariant& value)
{
if (value.IsNull() == true)
{
return false;
}
return true;
}
bool MyCustomRenderer::GetValue(wxVariant& value) const
{
return true;
}
wxSize MyCustomRenderer::GetSize() const
{
return wxSize(42, 42);
}
bool MyCustomRenderer::Render(wxRect cell, wxDC* dc, int state)
{
// Do lots of stuff here ...
return true;
}
All of the above works on 3.0.4 but not in 3.1.2.
The `return true` statement in `MyCustomRenderer::SetValue` is never hit.
I think its a bug in 3.1.2. What do you think guys?
Re: wxDataViewListCtrl and wxVariant
Posted: Thu Feb 07, 2019 8:30 am
by refaelsh
doublemax wrote:Set a breakpoint in MyCustomRenderer::SetValue(), single step through the code and see what happens.
I tried it, `value.IsNull()` is always true.
Re: wxDataViewListCtrl and wxVariant
Posted: Thu Feb 07, 2019 8:49 am
by doublemax
When does it crash? Directly at the start?
I tested with this code and it worked fine:
Code: Select all
#include <wx/wxprec.h>
#include <wx/dataview.h>
#include <wx/wx.h>
class MyCustomRenderer : public wxDataViewCustomRenderer
{
public:
MyCustomRenderer(const wxString &varianttype = "string", wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, int align = wxDVR_DEFAULT_ALIGNMENT )
:wxDataViewCustomRenderer(varianttype, mode, align )
{
};
bool SetValue(const wxVariant& value)
{
if (value.IsNull() == true)
{
return false;
}
return true;
}
bool GetValue(wxVariant& value) const
{
return true;
}
wxSize GetSize() const
{
return wxSize(42, 42);
}
bool Render(wxRect cell, wxDC* dc, int state)
{
// Do lots of stuff here ...
return true;
}
};
class MyApp : public wxApp
{
public:
virtual bool OnInit();
};
class MyFrame : public wxFrame
{
public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
};
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340));
frame->Show(true);
return true;
}
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame(NULL, wxID_ANY, title, pos, size)
{
wxDataViewListCtrl* data_view_list_ctrl = new wxDataViewListCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(-1, -1), wxDV_ROW_LINES | wxDV_SINGLE);
MyCustomRenderer* custom_renderer = new MyCustomRenderer();
wxDataViewColumn* data_view_column = new wxDataViewColumn("Some title goes here", custom_renderer,0);
data_view_list_ctrl->AppendColumn(data_view_column);
data_view_list_ctrl->AppendTextColumn("Some cool column title goes here");
wxVector<wxVariant> data;
data.push_back(wxVariant(42));
data.push_back(wxVariant("row 1"));
data_view_list_ctrl->AppendItem(data);
data.clear();
data.push_back(wxVariant(43));
data.push_back(wxVariant("row 3"));
data_view_list_ctrl->AppendItem(data);
}