Which files I need to modify to customize wxOwnerDrawnComboBox? Topic is solved
Which files I need to modify to customize wxOwnerDrawnComboBox?
Hi
I am making for me a version of wxOwnerDrawnComboBox whose m_strings member is std::shared_ptr<wxArrayString>.
I located files odcombo.h and odcombo.cpp, but what for is odcombocmn.cpp? Do I need to copy that as well?
I think I only need to copy those odcombo files into my project and adjust them for a bit, leaving no need to recompile whole wxWidgets.
I'm getting hundreds of "redeclared without dllimport attribute: previous dllimport ignored [-Wattributes]" warnings. How do I get rid of them?
I am making for me a version of wxOwnerDrawnComboBox whose m_strings member is std::shared_ptr<wxArrayString>.
I located files odcombo.h and odcombo.cpp, but what for is odcombocmn.cpp? Do I need to copy that as well?
I think I only need to copy those odcombo files into my project and adjust them for a bit, leaving no need to recompile whole wxWidgets.
I'm getting hundreds of "redeclared without dllimport attribute: previous dllimport ignored [-Wattributes]" warnings. How do I get rid of them?
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
Hi,
I assume that the original real issue is not excessive memory consumption caused by duplicating the strings for each control but (as already reported here) the long time it on MSW takes to create a huge number of comboboxes containing many items? If so, you may consider a different approach. The code below creates 50 regular wxComboCtrls and 50 default wxOwnerDrawnComboBoxes, each having the same 100 strings, see the difference: On my PC, according to wxStopWatch, creating a single wxComboBox (with passing wxArray with 100 strings to its constructor) takes about 50 ms while creating the default owner drawn combobox the exactly same way takes about 2 ms.
The code, please test on your PC if you get a similar difference between the regular and default owner drawn combobox:
I assume that the original real issue is not excessive memory consumption caused by duplicating the strings for each control but (as already reported here) the long time it on MSW takes to create a huge number of comboboxes containing many items? If so, you may consider a different approach. The code below creates 50 regular wxComboCtrls and 50 default wxOwnerDrawnComboBoxes, each having the same 100 strings, see the difference: On my PC, according to wxStopWatch, creating a single wxComboBox (with passing wxArray with 100 strings to its constructor) takes about 50 ms while creating the default owner drawn combobox the exactly same way takes about 2 ms.
The code, please test on your PC if you get a similar difference between the regular and default owner drawn combobox:
Code: Select all
#include <wx/wx.h>
#include <wx/odcombo.h>
class MyFrame : public wxFrame
{
public:
MyFrame()
: wxFrame(NULL, wxID_ANY, _("Test"), wxDefaultPosition, wxSize(600, 800))
{
const size_t stringCount = 100;
wxArrayString strings;
strings.reserve(stringCount);
for ( size_t i = 0; i < stringCount; i++ )
{
wxString s;
s.Printf(_T("%d ab cdeXYZ fghijk lmnop %d"), rand(), rand());
s.Shrink();
strings.push_back(s);
}
wxPanel* panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
wxBoxSizer* mainSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* cbSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* odSizer = new wxBoxSizer(wxVERTICAL);
wxStopWatch watch;
const size_t comboCount = 50;
long cbTime;
watch.Start();
for (size_t i = 0; i < comboCount; i++) {
wxStopWatch watchControl;
wxComboBox* comboBox = new wxComboBox(panel, wxID_ANY, _T("Combo!"), wxDefaultPosition, wxDefaultSize, strings, wxCB_READONLY);
wxLogDebug("wxComboBox #%zu created in %ld ms.", i + 1, watchControl.Time());
comboBox->Select(0);
cbSizer->Add(comboBox, 0, wxALL, 5);
}
cbTime = watch.Time();
long odTime;
watch.Start();
for (size_t i = 0; i < comboCount; i++) {
wxStopWatch watchControl;
wxOwnerDrawnComboBox* odComboBox = new wxOwnerDrawnComboBox(panel, wxID_ANY, _T("ODCombo!"), wxDefaultPosition, wxDefaultSize, strings, wxCB_READONLY | wxODCB_STD_CONTROL_PAINT);
wxLogDebug("wxOwnerDrawnComboBox #%zu created in %ld ms.", i + 1, watchControl.Time());
odComboBox->Select(0);
odSizer->Add(odComboBox, 0, wxALL, 5);
}
odTime = watch.Time();
wxLogMessage("Created %zu comboboxes in %ld ms.\n Created %zu wxOwnerDrawnComboBoxes in %ld ms.\n",
comboCount, cbTime, comboCount, odTime);
mainSizer->Add(cbSizer, 0, wxALL, 5);
mainSizer->Add(odSizer, 0, wxALL, 5);
panel->SetSizerAndFit(mainSizer);
Layout();
}
};
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
(new MyFrame())->Show();
return true;
}
};
wxIMPLEMENT_APP(MyApp);
Last edited by PB on Mon Oct 03, 2016 6:09 pm, edited 1 time in total.
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
I'm already using wxOwnerDrawnComboBoxes
Believe it or not, the strings take half of the memory my program uses.
In any case, I seem to need odcombo.h, odcombo.cpp and odcombocmn.cpp to customize wxOwnerDrawnComboBox to anything I want.
Believe it or not, the strings take half of the memory my program uses.
In any case, I seem to need odcombo.h, odcombo.cpp and odcombocmn.cpp to customize wxOwnerDrawnComboBox to anything I want.
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
I know, I meant simply using the provided implementation without additional trouble.Tapsa wrote:I'm already using wxOwnerDrawnComboBoxes
TBH, I personally wouldn't bother with saving a megabyte, two, or three in a rich GUI desktop app in this age, however wasteful the implementation may seem, and I learned to program on a PC with a 1 MB RAM in total... But I'm old, if I were young I can imagine being so wasteful would bother me.
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
We are talking about 40 to 160 MB of wasted memory. Qt also has this kind of functionality (model-view system) implemented long ago.
-
- Super wx Problem Solver
- Posts: 469
- Joined: Tue Jun 20, 2006 6:47 pm
- Contact:
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
Would it help to create a custom popup that uses a virtual listctrl? That way, each combobox won't need to store a copy of the set of strings.Tapsa wrote:We are talking about 40 to 160 MB of wasted memory. Qt also has this kind of functionality (model-view system) implemented long ago.
I'm not sure I understand what you're trying to do, so sorry if that's a useless suggestion.
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
Yes indeed! I am currently copying and editing wx codes to achieve "virtual" popup list.
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
wxOwnerDrawnComboBox uses a wxVListBox internally which is a "virtual" control. It's just not exposed in the public API.
Use the source, Luke!
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
Can I already use it as such via some undocumented functions?
I tried to set the item count in my wxODCB subclassed constructor along with custom OnDrawItem function, but the program segmentation faults at vlbox.cpp file on line 116, which makes no sense since there aren't even any pointers there.
I tried to set the item count in my wxODCB subclassed constructor along with custom OnDrawItem function, but the program segmentation faults at vlbox.cpp file on line 116, which makes no sense since there aren't even any pointers there.
Code: Select all
GetVListBoxComboPopup()->wxVListBox::SetItemCount(10);
Does this mean that SetItemCount is operating on NULL object?Program received signal SIGSEGV, Segmentation fault.
0x65915674 in wxVListBox::SetItemCount (this=0x0, count=10)
at ../../src/generic/vlbox.cpp:116
116 if ( m_current != wxNOT_FOUND && (size_t)m_current >= count )
(gdb) bt
#0 0x65915674 in wxVListBox::SetItemCount (this=0x0, count=10)
at ../../src/generic/vlbox.cpp:116
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
Can't you just use a custom pop-up (e.g. a wxVListBox or wxListView with wxLC_REPORT and wxLC_VIRTUAL) for a wxComboCtrl, as shown in the comboctrl sample? It may need some tweaking to match the native appearance and the behaviour of the default combo pop-up but may still be worth a try.
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
I have tried to do that with wxVListBox for one full day, but I can no longer even get any drop box appear.
-
- Super wx Problem Solver
- Posts: 469
- Joined: Tue Jun 20, 2006 6:47 pm
- Contact:
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
Here's a sample I threw together which uses a VListBox as a custom popup for a ComboCtrl. You would obviously need different overrides for getting and setting the strings.Tapsa wrote:I have tried to do that with wxVListBox for one full day, but I can no longer even get any drop box appear.
Code: Select all
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include <wx/vlbox.h>
#include <wx/combo.h>
class wxVListComboPopup : public wxVListBox, public wxComboPopup
{
public:
//wxComboPopup virtual methods
// Initialize member variables
virtual void Init()
{
m_textHt=GetTextExtent("item 0").GetHeight();
}
// Create popup control
virtual bool Create(wxWindow* parent)
{
SetItemCount(20);
Bind(wxEVT_LEFT_UP,&wxVListComboPopup::OnMouseClick,this);
Bind(wxEVT_MOTION,&wxVListComboPopup::OnMouseMove,this);
return wxVListBox::Create(parent);
}
// Return pointer to the created control
virtual wxWindow *GetControl() { return this; }
// Translate string into a list selection
virtual void SetStringValue(const wxString& s)
{
wxString temp=s;
temp.Replace("item ","");
long tlong;
temp.ToLong(&tlong);
SetSelection(tlong);
}
// Get list selection as a string
virtual wxString GetStringValue() const
{
int i = GetSelection();
if(i==wxNOT_FOUND)
{
return wxEmptyString;
}
else
{
return GetString(i);
}
}
//wxVListBox virtual methods
virtual wxCoord OnMeasureItem (size_t n) const
{
return m_textHt;
}
virtual void OnDrawItem (wxDC &dc, const wxRect &rect, size_t n) const
{
dc.DrawText(GetString(n),rect.GetLeft(),rect.GetTop());
}
//MouseHelpers
// Do mouse hot-tracking (which is typical in list popups)
void OnMouseMove(wxMouseEvent& event)
{
int i=VirtualHitTest(event.GetY());
if(i!=wxNOT_FOUND)
{
SetSelection(i);
}
}
// On mouse left up, set the value and close the popup
void OnMouseClick(wxMouseEvent& WXUNUSED(event))
{
// TODO: Send event as well
Dismiss();
}
private:
wxString GetString(int n) const {return wxString::Format("item %d",n);}
int m_textHt;
};
class comboctrlFrame : public wxFrame
{
public:
comboctrlFrame( wxWindow* parent, wxWindowID id = wxID_ANY,
const wxString& title = wxEmptyString,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxSize( 481,466 ),
long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
private:
wxComboCtrl* comboCtrl;
};
comboctrlFrame::comboctrlFrame( wxWindow* parent, wxWindowID id,
const wxString& title,const wxPoint& pos, const wxSize& size, long style)
:wxFrame(parent,id,title)
{
comboCtrl = new wxComboCtrl(this, wxID_ANY, wxEmptyString);
comboCtrl->SetPopupControl(new wxVListComboPopup());
wxBoxSizer* bSizer1 = new wxBoxSizer( wxVERTICAL );
bSizer1->Add( comboCtrl , 0, wxALL, 5 );
SetSizer(bSizer1);
}
class comboctrlApp : public wxApp
{
public:
virtual bool OnInit()
{
comboctrlFrame* frame = new comboctrlFrame(0L);
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(comboctrlApp);
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
And here is another approach (I created it before I noticed NewPagodi's post), using wxListView in virtual report mode, based on simple modification of the comboctrl sample. It certainly needs a polishing but I think it could be used as a base. OTOH, there may be an issue hard to work around, difficult to say without using the control in the real application...
Code: Select all
#include <wx/wx.h>
#include <wx/combo.h>
#include <wx/listctrl.h>
#include <memory>
typedef std::shared_ptr<wxArrayString> wxSharedArrayString;
class wxMyComboPopup : public wxListView, public wxComboPopup
{
public:
virtual void Init() wxOVERRIDE
{
m_value = -1;
m_itemHere = -1; // hot item in list
Bind(wxEVT_MOTION, &wxMyComboPopup::OnMouseMove, this);
Bind(wxEVT_LEFT_DOWN, &wxMyComboPopup::OnMouseClick, this);
Bind(wxEVT_CHAR, &wxMyComboPopup::OnChar, this);
}
virtual bool Create(wxWindow* parent) wxOVERRIDE
{
/* This would create a pop-up with strings in columns
return wxListView::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxLC_LIST | wxLC_VIRTUAL | wxLC_SINGLE_SEL | wxSIMPLE_BORDER);
*/
if ( wxListView::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxLC_REPORT | wxLC_VIRTUAL | wxLC_SINGLE_SEL | wxLC_NO_HEADER | wxSIMPLE_BORDER) )
{
AppendColumn(("Dummy"));
SetColumnWidth(0, GetClientSize().GetWidth());
return true;
}
return false;
}
void SetStrings(const wxSharedArrayString& strings)
{
wxASSERT( strings.get() && !strings->empty() );
m_strings = strings;
SetItemCount(m_strings->size());
}
virtual void OnPopup() wxOVERRIDE
{
if ( m_value != wxNOT_FOUND )
EnsureVisible(m_value);
wxComboPopup::OnPopup();
}
// Return pointer to the created control
virtual wxWindow *GetControl() wxOVERRIDE { return this; }
virtual wxString OnGetItemText(long item, long column) const wxOVERRIDE
{
wxCHECK( (size_t)item < m_strings->size() && column == 0, wxEmptyString );
return (*m_strings)[item];
}
// Translate string into a list selection
virtual void SetStringValue(const wxString& s) wxOVERRIDE
{
int n = wxListView::FindItem(-1, s);
if ( n != wxNOT_FOUND && n < wxListView::GetItemCount() )
{
m_value = n;
wxListView::Select(n);
}
}
// Get list selection as a string
virtual wxString GetStringValue() const wxOVERRIDE
{
if ( m_value >= 0 )
{
wxASSERT( (size_t)m_value < m_strings->size() );
return (*m_strings)[(size_t)m_value];
}
return wxEmptyString;
}
protected:
wxSharedArrayString m_strings;
int m_value; // current item index
int m_itemHere; // hot item in popup
// Do mouse hot-tracking (which is typical in list popups)
void OnMouseMove(wxMouseEvent& event)
{
// Move selection to cursor if it is inside the popup
int resFlags = wxLIST_HITTEST_ONITEM;
int itemHere = HitTest(event.GetPosition(), resFlags);
if ( itemHere != wxNOT_FOUND )
{
wxListView::SetItemState(itemHere,
wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
m_itemHere = itemHere;
}
event.Skip();
}
// On mouse left up, set the value and close the popup
void OnMouseClick(wxMouseEvent&)
{
ClosePopup(m_itemHere);
}
void OnChar(wxKeyEvent& event)
{
if ( event.GetKeyCode() == WXK_RETURN )
ClosePopup(GetNextItem(0, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED));
else
event.Skip();
}
void ClosePopup(int value)
{
// TODO: Send event as well
if ( value != wxNOT_FOUND )
m_value = value;
Dismiss();
}
};
class MyFrame : public wxFrame
{
public:
MyFrame()
: wxFrame(NULL, wxID_ANY, _("Test"), wxDefaultPosition, wxSize(1200, 800))
{
const size_t stringCount = 100 * 1000;
wxSharedArrayString strings(new wxArrayString());
strings->reserve(stringCount);
for ( size_t i = 0; i < stringCount; i++ )
strings->push_back(wxString::Format("Item %zu: This is just a rest of the string", i+1));
const size_t colCount = 8;
const size_t comboCount = colCount * 25;
wxPanel* panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
wxGridSizer* cbSizer = new wxGridSizer(colCount, 5, 5);
for ( size_t i = 0; i < comboCount; i++ )
{
wxComboCtrl* cc = new wxComboCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxCB_READONLY);
cc->UseAltPopupWindow();
cc->SetPopupMinWidth(300);
wxMyComboPopup* pp = new wxMyComboPopup();
cc->SetPopupControl(pp);
pp->SetStrings(strings);
cc->SetValue((*strings)[0]);
cbSizer->Add(cc);
}
panel->SetSizer(cbSizer);
}
};
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
(new MyFrame())->Show();
return true;
}
};
wxIMPLEMENT_APP(MyApp);
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
Thanks guys. I'm getting forward now
Re: Which files I need to modify to customize wxOwnerDrawnComboBox?
I looked into it a bit more and solutions using a custom pop-up with wxComboCtrl compared to wxComboBox lacks so many features from both the user and programmer point of view....
I believe your original approach was better, i.e., to copy and modify the code of wxOwnerDrawnComboBox.
I believe your original approach was better, i.e., to copy and modify the code of wxOwnerDrawnComboBox.