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
PB wrote: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".
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);
}