wxRendererNative::Get does not work with updated wxwidgets 3.1.5 - c++

I came across the following MRE that does not work anymore as it generates the error given below. The user who wrote this MRE at the time claimed that this works but after trying this example now, i get the error given below. My question is that how can I make the MRE working again. That is how to get rid of this error. Also, I want to know why it doesn't work anymore.
Note also that this example was written and provided here by #NewPagodi.
#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif
#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__
#include <wx/dcmemory.h>
#include <wx/renderer.h>
#include <wx/vlbox.h>
#include <wx/sizer.h>
#include <wx/panel.h>
#include <wx/statusbr.h>
#include <wx/frame.h>
#include <wx/app.h>
#include <set>
#include "lock.xpm"
#include "trash.xpm"
wxDECLARE_EVENT(myEVT_VLIST_BUTTON_CLICK, wxCommandEvent);
wxDECLARE_EVENT(myEVT_VLIST_CHECK_CLICK, wxCommandEvent);
class myVListBox:public wxVListBox
{
public:
myVListBox(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=0, const wxString &name=wxVListBoxNameStr);
virtual void OnDrawItem (wxDC &dc, const wxRect &rect, size_t n) const;
virtual wxCoord OnMeasureItem (size_t n) const;
private:
void OnVListLeftUp( wxMouseEvent& event );
wxBitmap CheckPlainBitmap;
wxBitmap CheckCheckedBitmap;
wxBitmap TrashBitmap;
wxBitmap LockBitmap;
//configurable
int CheckSide;
int CheckTextSide;
int ButtonSide;
//computed
int TextStart;
int CheckEnd;
int ButtonWidth;
int BoxHeight;
int CheckGap;
int TextGap;
int ButtonGap;
std::set<int> selected;
};
wxDEFINE_EVENT(myEVT_VLIST_BUTTON_CLICK, wxCommandEvent);
wxDEFINE_EVENT(myEVT_VLIST_CHECK_CLICK, wxCommandEvent);
myVListBox::myVListBox(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style, const wxString &name)
:wxVListBox(parent, wxID_ANY, pos, size, style, name)
{
wxDelegateRendererNative rn = wxRendererNative::Get();
wxSize sz = rn.GetCheckBoxSize(this);
CheckPlainBitmap = wxBitmap(sz);
CheckCheckedBitmap = wxBitmap(sz);
wxMemoryDC temp_dc;
temp_dc.SelectObject(CheckPlainBitmap);
rn.DrawCheckBox(this, temp_dc, wxRect(0,0,sz.GetWidth(),sz.GetHeight()),wxCONTROL_NONE );
temp_dc.SelectObject(CheckCheckedBitmap);
rn.DrawCheckBox(this, temp_dc, wxRect(0,0,sz.GetWidth(),sz.GetHeight()),wxCONTROL_CHECKED );
temp_dc.SelectObject(wxNullBitmap);
CheckSide=5;
CheckTextSide=5;
ButtonSide=5;
TrashBitmap=wxBitmap(trash_xpm);
LockBitmap=wxBitmap(lock_xpm);
//computed
CheckEnd=CheckSide+sz.GetX();
TextStart=CheckEnd+CheckTextSide;
ButtonWidth=TrashBitmap.GetWidth();
wxSize textSz = GetTextExtent("Test");
//Compute the box heights and the gaps
BoxHeight = sz.GetHeight();
if(textSz.GetHeight()>BoxHeight)
{
BoxHeight=textSz.GetHeight();
}
if(TrashBitmap.GetHeight()>BoxHeight)
{
BoxHeight=TrashBitmap.GetHeight();
}
BoxHeight+=4;
CheckGap=(BoxHeight-sz.GetHeight())/2;
TextGap=(BoxHeight-textSz.GetHeight())/2;
ButtonGap=(BoxHeight-TrashBitmap.GetHeight())/2;
Bind( wxEVT_LEFT_UP, &myVListBox::OnVListLeftUp , this );
}
wxCoord myVListBox::OnMeasureItem (size_t n) const
{
return BoxHeight;
}
void myVListBox::OnDrawItem(wxDC &dc, const wxRect &rect, size_t n) const
{
int textLeft=rect.GetLeft()+TextStart;
int textTop=rect.GetTop()+TextGap;
int checkLeft=rect.GetLeft()+CheckSide;
int checkTop=rect.GetTop()+CheckGap;
int buttonLeft=rect.GetRight()-ButtonWidth-ButtonSide;
int buttonTop=rect.GetTop()+ButtonGap;
if(selected.find(n) == selected.end())
{
dc.DrawBitmap( CheckPlainBitmap, checkLeft, checkTop );
}
else
{
dc.DrawBitmap( CheckCheckedBitmap, checkLeft, checkTop );
}
if(IsSelected(n) )
{
wxColour c= dc.GetTextForeground();
dc.SetTextForeground(*wxWHITE);
dc.DrawText( wxString::Format("entry %d",n), textLeft, textTop );
dc.SetTextForeground(c);
}
else
{
dc.DrawText( wxString::Format("entry %d",n), textLeft, textTop );
}
if(n%3==1)
{
dc.DrawBitmap( TrashBitmap, buttonLeft,buttonTop, true );
}
else
{
dc.DrawBitmap( LockBitmap, buttonLeft,buttonTop, true );
}
}
void myVListBox::OnVListLeftUp( wxMouseEvent& event )
{
int item = VirtualHitTest(event.GetY());
if(item==wxNOT_FOUND)
{
return;
}
wxRect r=GetItemRect(item);
bool OnButton(false);
if( CheckSide<=event.GetX() && event.GetX()<=CheckEnd )
{
if(r.GetTop()+CheckGap <= event.GetY() &&event.GetY() <=r.GetBottom()-CheckGap )
{
std::set<int>::iterator it= selected.find(item);
if( it == selected.end() )
{
selected.insert(item);
}
else
{
selected.erase(it);
}
RefreshRow(item);
wxCommandEvent event2(myEVT_VLIST_CHECK_CLICK,GetId());
event2.SetEventObject(this);
event2.SetInt(item);
event2.SetExtraLong(it == selected.end());
ProcessWindowEvent(event2);
}
}
else if( r.GetRight()-ButtonSide-ButtonWidth<=event.GetX() && event.GetX()<=r.GetRight()-ButtonSide )
{
if(r.GetTop()+ButtonGap <= event.GetY() &&event.GetY() <=r.GetBottom()-ButtonGap )
{
wxCommandEvent event2(myEVT_VLIST_BUTTON_CLICK,GetId());
event2.SetEventObject(this);
event2.SetInt(item);
ProcessWindowEvent(event2);
}
}
event.Skip();
}
class vlistFrame : public wxFrame
{
public:
vlistFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("myVListBox demo"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 481,466 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
private:
void OnVListButton(wxCommandEvent& event);
void OnVListCheck(wxCommandEvent& event);
myVListBox* m_vlist;
};
vlistFrame::vlistFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
wxPanel* m_panel1 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer2 = new wxBoxSizer( wxVERTICAL );
m_vlist=new myVListBox(m_panel1);
m_vlist->SetItemCount (20);
bSizer2->Add( m_vlist, 1, wxALL|wxEXPAND, 5 );
m_panel1->SetSizer( bSizer2 );
m_panel1->Layout();
bSizer2->Fit( m_panel1 );
CreateStatusBar( 2, wxST_SIZEGRIP, wxID_ANY );
// Connect Events
m_vlist->Bind( myEVT_VLIST_BUTTON_CLICK, &vlistFrame::OnVListButton , this );
m_vlist->Bind( myEVT_VLIST_CHECK_CLICK, &vlistFrame::OnVListCheck , this );
}
void vlistFrame::OnVListButton(wxCommandEvent& event)
{
SetStatusText( wxString::Format("Item %d button clicked",event.GetInt()),1);
}
void vlistFrame::OnVListCheck(wxCommandEvent& event)
{
SetStatusText( wxString::Format("Item %d check clicked %s",event.GetInt(),
(event.GetExtraLong()?"true":"false")),1);
}
class vlistApp : public wxApp
{
public:
virtual bool OnInit()
{
vlistFrame* frame = new vlistFrame(0L);
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(vlistApp);
The above produces the following error:
/home/user/Documents/folder/somefo/anj/sno/vlistMain.cpp: In constructor ‘myVListBox::myVListBox(wxWindow*, wxWindowID, const wxPoint&, const wxSize&, long int, const wxString&)’:
/home/user/Documents/folder/somefo/anj/sno/vlistMain.cpp:10:57: error: ‘wxDelegateRendererNative::wxDelegateRendererNative(const wxDelegateRendererNative&)’ is private within this context
wxDelegateRendererNative rn = wxRendererNative::Get();
^
In file included from /usr/local/include/wx-3.1/wx/memory.h:14:0,
from /usr/local/include/wx-3.1/wx/object.h:19,
from /usr/local/include/wx-3.1/wx/dc.h:18,
from /usr/local/include/wx-3.1/wx/dcmemory.h:14,
from /home/user/Documents/folder/somefo/anj/sno/../../headers/sno/vlistMain.h:14,
from /home/user/Documents/folder/somefo/anj/sno/vlistMain.cpp:2:
/usr/local/include/wx-3.1/wx/renderer.h:594:5: note: declared private here
wxDECLARE_NO_COPY_CLASS(wxDelegateRendererNative);
^
/home/user/Documents/folder/somefo/anj/sno/vlistMain.cpp:10:57: error: use of deleted function ‘wxDelegateRendererNative::wxDelegateRendererNative(const wxDelegateRendererNative&)’
wxDelegateRendererNative rn = wxRendererNative::Get();
^
In file included from /usr/local/include/wx-3.1/wx/memory.h:14:0,
from /usr/local/include/wx-3.1/wx/object.h:19,
from /usr/local/include/wx-3.1/wx/dc.h:18,
from /usr/local/include/wx-3.1/wx/dcmemory.h:14,
from /home/user/Documents/folder/somefo/anj/sno/../../headers/sno/vlistMain.h:14,
from /home/user/Documents/folder/somefo/anj/sno/vlistMain.cpp:2:
/usr/local/include/wx-3.1/wx/renderer.h:594:5: note: declared here
wxDECLARE_NO_COPY_CLASS(wxDelegateRendererNative);
^
In file included from /home/user/Documents/folder/somefo/anj/sno/../../headers/sno/vlistMain.h:15:0,
from /home/user/Documents/folder/somefo/anj/sno/vlistMain.cpp:2:
/usr/local/include/wx-3.1/wx/renderer.h:428:5: note: after user-defined conversion: wxDelegateRendererNative::wxDelegateRendererNative(wxRendererNative&)
wxDelegateRendererNative(wxRendererNative& rendererNative)

The problem is that wxRendererNative::Get() returns a reference (see documentation) to the renderer you intend to use for drawing, but you try to create a new renderer as local variable. Moreover, it returns wxRendererNative&, but you try to create wxDelegateRendererNative (which is derived from wxRendererNative), so the type of new renderer is different, and in its documentation you can see that it doesn't have appropriate constructors to be constructed from wxRendererNative. And even if such constructor was available, the copied renderer could behave differently than what you wanted (e.g. draw something in its own state/buffer and not copy that to original one). So, you should use the returned reference instead by, e.g., saving it to local reference variable and using it to access original native renderer:
wxRendererNative& rn = wxRendererNative::Get();
// ...
P.S. Note that the previous version of this answer was to save returned reference to wxDelegateRendererNative& rn, which was wrong (thanks VZ.) because renderer could have different dynamic type than wxDelegateRendererNative, and wouldn't even compile since initializing derived lvalue reference to base object is not allowed in reference initialization (except when conversion from base to derived lvalue reference is defined, which is not the case here). Also, note that delegate renderer is needed only when you try to define your own renderer with limited additional functionality and delegate everything else (via inheritance from wxDelegateRendererNative) to other renderer (which is passed as constructor parameter to delegate; see example). If your renderer was implemented this way and you know dynamic type of renderer at compile time, you can do explicit reference cast using static_cast and actually use wxDelegateRendererNative& (beware of UB if cast is unsuccessful), but in this case using actual type of renderer (e.g. MyRendererNative&) will be more likely to help optimizer 'devirtualize' virtual method calls through this reference (which is the only reason I can think of to do downcast in this situation).

Related

Error with using wxWidgets alongside SFML

This error is with wxWidgets 3.1.5, and SFML 2.5.1
I have the following code:
(main.cpp) :-
#include <SFML/Graphics.hpp>
#include <wx/wx.h>
#include "wxSfmlCanvas.h"
#include "main.h"
TestFrame::TestFrame() :
wxFrame(NULL, wxID_ANY, "SFML 2.5 w/ wxWidgets 3.1", wxDefaultPosition, wxSize(650, 490))
{
mCanvas = new TestSfmlCanvas(this, wxID_ANY, wxPoint(5, 25), wxSize(640, 480));
// Also add a button.
wxButton *button = new wxButton(
this,
wxID_ANY,
wxT("Toggle Size"),
wxPoint(5, 5)
);
button->Bind(wxEVT_BUTTON, [&](wxCommandEvent& arg) -> void {
mCanvas->toggleSize();
});
wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
mainSizer->Add(mCanvas, 6, wxALIGN_TOP | wxEXPAND);
mainSizer->Add(button, 0, wxALIGN_RIGHT | wxALIGN_BOTTOM);
SetSizerAndFit(mainSizer);
}
TestSfmlCanvas::TestSfmlCanvas(
wxWindow* Parent,
wxWindowID Id,
wxPoint& Position,
wxSize& Size,
long Style
) : wxSfmlCanvas(Parent, Id, Position, Size, Style),
mLarge(false)
{
// Load a texture and create a sprite.
mTexture.loadFromFile("data/ball.png");
mSprite = std::make_unique<sf::Sprite>(mTexture);
}
void
TestSfmlCanvas::OnUpdate()
{
clear(sf::Color(64, 196, 196));
draw(*mSprite);
}
void
TestSfmlCanvas::toggleSize()
{
if (mLarge) {
mSprite->setScale(sf::Vector2f(1.2f, 1.2f));
}
else {
mSprite->setScale(sf::Vector2f(0.5f, 0.5f));
}
mLarge = !mLarge;
}
IMPLEMENT_APP(TestApplication);
(and main.h) :-
#pragma once
#include <memory>
#include <SFML/Graphics.hpp>
#include <wx/wx.h>
#include <string>
#include "wxSfmlCanvas.h"
// Our overridden class that does some SFML drawing.
class TestSfmlCanvas : public wxSfmlCanvas
{
public:
TestSfmlCanvas(
wxWindow* Parent,
wxWindowID Id,
wxPoint& Position,
wxSize& Size,
long Style = 0
);
void toggleSize();
protected:
void OnUpdate() override;
private:
sf::Texture mTexture;
std::unique_ptr<sf::Sprite> mSprite;
bool mLarge;
};
// wx Frame to contain the main canvas control. Can have extra controls added to it as desired.
class TestFrame : public wxFrame
{
public :
TestFrame();
protected:
TestSfmlCanvas* mCanvas;
};
// Main wx Application instance.
class TestApplication : public wxApp
{
private :
virtual bool OnInit()
{
// Create the main window
TestFrame* MainFrame = new TestFrame;
MainFrame->Show();
return true;
}
};
(wxSFMLCanvas.h) :-
#pragma once
#include <SFML/Graphics.hpp>
#include <wx/wx.h>
#include <string>
class wxSfmlCanvas : public wxControl, public sf::RenderWindow
{
public:
wxSfmlCanvas(wxWindow* Parent = nullptr,
wxWindowID Id = -1,
//const wxPoint& Position = wxDefaultPosition,
const wxSize& Size = wxDefaultSize,
long Style = 0);
virtual ~wxSfmlCanvas();
protected:
virtual void OnUpdate();
void OnIdle(wxIdleEvent&);
void OnPaint(wxPaintEvent&);
void OnEraseBackground(wxEraseEvent&);
void OnSize(wxSizeEvent&);
DECLARE_EVENT_TABLE()
};
(wxSFMLCanvas.cpp) :-
#include "wxSfmlCanvas.h"
#include <wx/wx.h>
#include <string>
BEGIN_EVENT_TABLE(wxSfmlCanvas, wxControl)
EVT_PAINT(wxSfmlCanvas::OnPaint)
EVT_IDLE(wxSfmlCanvas::OnIdle)
EVT_ERASE_BACKGROUND(wxSfmlCanvas::OnEraseBackground)
EVT_SIZE(wxSfmlCanvas::OnSize)
END_EVENT_TABLE()
#ifdef __WXGTK__
#include <string>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include <wx/gtk/win_gtk.h>
#endif
wxSfmlCanvas::wxSfmlCanvas(wxWindow* Parent,
wxWindowID Id,
const wxPoint& Position,
const wxSize& Size,
long Style) :
wxControl(Parent, Id, Position, Size, Style)
{
#ifdef __WXGTK__
#else
sf::RenderWindow::create(GetHandle());
#endif
}
void wxSfmlCanvas::OnIdle(wxIdleEvent&)
{
// Send a paint message when the control is idle, to ensure maximum framerate
Refresh();
}
wxSfmlCanvas::~wxSfmlCanvas()
{
}
void wxSfmlCanvas::OnUpdate()
{
}
void wxSfmlCanvas::OnEraseBackground(wxEraseEvent&)
{
}
void wxSfmlCanvas::OnSize(wxSizeEvent& args)
{
// Set the size of the sfml rendering window
setSize(sf::Vector2u(args.GetSize().x, args.GetSize().y));
// Also adjust the viewport so that a pixel stays 1-to-1.
setView(sf::View(sf::FloatRect(0, 0, args.GetSize().x, args.GetSize().y)));
}
void wxSfmlCanvas::OnPaint(wxPaintEvent&)
{
// Prepare the control to be repainted
wxPaintDC Dc(this);
// Let the derived class do its specific stuff
OnUpdate();
// Display on screen
display();
}
With this code, I get the following compile errors:
Severity Code Description Project File Line Suppression State Error C4996 '_wgetenv': This function or variable may be unsafe. Consider using _wdupenv_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. ae D:\wxwidg\include\wx\wxcrt.h 1050
And 100 similar others.
Why? what did I do wrong for this?
wxWidgets is properly built, SFML and wx work fine on their own, but when combined, this error takes place for some reason.
The messages you show are not errors at all, they are static analyser warnings and can be safely ignored, the "unsafe" functions are not used in unsafe way inside wxWidgets.

Custom wxPanel problems

I'm writing a C++ wxWidgets application. I want my custom wxButton's that have a EXPANDABLE flag to open up a panel on top of them when I right click. Said panel is also supposed to automatically close when the cursor leaves it, or when the user clicks on one of the buttons it contains.
I created a custom wxPanel class for this job, but I'm having some trouble. The panel is successfully created when I right click on the button, but:
The panel is not removed when the cursor leaves it
There's an awkward graphical glitch when I move the cursor that cause the other interface elements to get on top of it (?)
Here's my code:
expandPanel.h
#pragma once
#include "wx/wx.h"
#include "ikeButton.h"
class expandPanel : public wxPanel
{
wxBoxSizer* sizer;
int type;
public:
expandPanel(wxWindow* parent, wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL,
const wxString & name = wxPanelNameStr);
~expandPanel();
void paintEvent(wxPaintEvent& evt);
void paintNow();
void Render(wxDC& dc);
void mouseLeftWindow(wxMouseEvent& evt);
DECLARE_EVENT_TABLE()
};
expandPanel.cpp
#include "expandPanel.h"
BEGIN_EVENT_TABLE(expandPanel, wxPanel)
EVT_LEAVE_WINDOW(expandPanel::mouseLeftWindow)
EVT_PAINT(expandPanel::paintEvent)
END_EVENT_TABLE()
expandPanel::expandPanel(wxWindow* parent, wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
wxPanel::Create(parent, id, pos, size, style, name);
sizer = new wxBoxSizer(wxHORIZONTAL);
SetSizer(sizer);
}
expandPanel::~expandPanel()
{
}
void expandPanel::paintEvent(wxPaintEvent& evt)
{
wxPaintDC dc(this);
Render(dc);
}
void expandPanel::paintNow()
{
wxClientDC dc(this);
Render(dc);
}
void expandPanel::Render(wxDC& dc)
{
dc.SetBrush(wxColour(80, 83, 111));
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(0, 0, this->GetSize().GetWidth(), this->GetSize().GetHeight());
}
void expandPanel::mouseLeftWindow(wxMouseEvent& evt)
{
this->Close();
}
(I'm fairly new to this framework)
Ok, I tried switching to wxPopupTransientWindow, but the buttons appear on a different location on screen and sometimes disappear when I move the cursor, but the popup placed in the correct position do not disappear in any way. I feel like I'm doing this completely wrong.
expandMenu.h
#pragma once
#include "wx/wx.h"
#include "wx/popupwin.h"
#include "ikeButton.h"
class expandMenu : public wxPopupTransientWindow
{
wxBoxSizer* sizer;
public:
expandMenu(wxWindow* parent, wxPoint pos, wxSize size, int flags = wxBORDER_NONE);
~expandMenu();
void AddButton(ikeButton* btn);
};
expandMenu.cpp
#include "expandMenu.h"
expandMenu::expandMenu(wxWindow* parent, wxPoint pos, wxSize size, int flags)
: wxPopupTransientWindow(parent, flags)
{
this->SetPosition(pos);
this->SetSize(size);
this->SetBackgroundColour(wxColour(90, 93, 121));
sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Layout();
SetSizer(sizer);
}
expandMenu::~expandMenu()
{
}
void expandMenu::AddButton(ikeButton* btn)
{
unsigned int w = this->GetSize().GetWidth(), h = this->GetSize().GetHeight();
if (sizer->GetItemCount() > 0)
this->SetSize(wxSize(w, h + h / sizer->GetItemCount() ));
sizer->Add(btn, 0, wxEXPAND);
sizer->Layout();
}
Then I generate them like this:
void Main::OnExpandableRightClick(wxMouseEvent& evt)
{
expandMenu* menu = new expandMenu(this, wxGetMousePosition(), wxSize(50, 50));
for (int i = 0; i < 3; i++) menu->AddButton(new ikeButton(this, wxID_ANY, "TEST " + std::to_string(i), OP));
menu->Popup();
evt.Skip();
}
(This is a test scenario to see if everything is working)

Panel class module initialization in C++ GUIapp

I am a novice in C++ and wxWidgets, and use wxFormBuilder to help me create the GUI.
I like the idea to put similar functions together in 1 module, which means that my apps have multiple modules.
One of the modules is for the GUI (it now contains code for the main Frame (with only a menu and taskbar) and
a Panel (with 2 StaticText controls and a button).
The button increments a counter and the value is shown in one of the StaticTexts on the Panel.
Sofar so good. (compiles without errors)
I can make the Panel show/Hide, but I seem to miss an essential piece of knowledge to make the Panel button work.
The ways I tried are all similar to the way the Main module is coded, but that is not working.
I understand how it works with GUI class elements in the same file.
However, I like to keep all GUI code in one module (GUIFrame.h/.cpp),
and all the 'function' code in e.g. the Panel module (MyPanel.h/.cpp).
Just because I am not sure where I make my mistake, I present all code in this post.
My aplologies if it is too much.
Hopefully someone can help me bridge my gap in knowledge about this way of working.
Regards,
Ruud
=== GUIFrame.h
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/string.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/menu.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/statusbr.h>
#include <wx/frame.h>
#include <wx/stattext.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/panel.h>
///////////////////////////////////////////////////////////////////////////
#define idMenuQuit 1000
///////////////////////////////////////////////////////////////////////////////
/// Class GUIFrame
///////////////////////////////////////////////////////////////////////////////
class GUIFrame : public wxFrame
{
private:
protected:
wxMenuBar* mbar;
wxMenu* mainMenu;
wxStatusBar* statusBar;
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
virtual void m_menuItemPanelMainOnMenuSelection( wxCommandEvent& event ) { event.Skip(); }
virtual void OnQuit( wxCommandEvent& event ) { event.Skip(); }
public:
GUIFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Test application"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 500,500 ), long style = wxDEFAULT_FRAME_STYLE );
~GUIFrame();
};
///////////////////////////////////////////////////////////////////////////////
/// Class PanelMAIN
///////////////////////////////////////////////////////////////////////////////
class PanelMAIN : public wxPanel
{
private:
protected:
wxStaticText* m_staticText3;
// Virtual event handlers, overide them in your derived class
virtual void m_btn_Counter_OnButtonClick( wxCommandEvent& event ) { event.Skip(); }
public:
wxStaticText* m_staticTextPMain;
wxButton* m_buttonPMain;
PanelMAIN( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxPoint( 3,3 ), const wxSize& size = wxSize( 350,300 ), long style = wxBORDER_RAISED, const wxString& name = wxEmptyString );
~PanelMAIN();
};
==== GUIFrame.cpp
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif //WX_PRECOMP
#include "GUIFrame.h"
///////////////////////////////////////////////////////////////////////////
GUIFrame::GUIFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
mbar = new wxMenuBar( 0 );
mainMenu = new wxMenu();
wxMenuItem* m_menuItemPanelMain;
m_menuItemPanelMain = new wxMenuItem( mainMenu, wxID_ANY, wxString( wxT("To Main Panel") ) , wxEmptyString, wxITEM_NORMAL );
mainMenu->Append( m_menuItemPanelMain );
wxMenuItem* menuFileQuit;
menuFileQuit = new wxMenuItem( mainMenu, idMenuQuit, wxString( wxT("&Quit") ) + wxT('\t') + wxT("Alt+F4"), wxT("Quit the application"), wxITEM_NORMAL );
mainMenu->Append( menuFileQuit );
mbar->Append( mainMenu, wxT("&Menu") );
this->SetMenuBar( mbar );
statusBar = this->CreateStatusBar( 2, wxSTB_SIZEGRIP, wxID_ANY );
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( GUIFrame::OnClose ) );
mainMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GUIFrame::m_menuItemPanelMainOnMenuSelection ), this, m_menuItemPanelMain->GetId());
mainMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GUIFrame::OnQuit ), this, menuFileQuit->GetId());
}
GUIFrame::~GUIFrame()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( GUIFrame::OnClose ) );
}
PanelMAIN::PanelMAIN( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name )
{
this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) );
wxBoxSizer* bSizer1;
bSizer1 = new wxBoxSizer( wxVERTICAL );
m_staticTextPMain = new wxStaticText( this, wxID_ANY, wxT("We are on PanelMAIN now"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextPMain->Wrap( -1 );
bSizer1->Add( m_staticTextPMain, 0, wxALL, 5 );
m_buttonPMain = new wxButton( this, wxID_ANY, wxT("Counter++"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer1->Add( m_buttonPMain, 0, wxALL, 5 );
m_staticText3 = new wxStaticText( this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText3->Wrap( -1 );
bSizer1->Add( m_staticText3, 0, wxALL, 5 );
this->SetSizer( bSizer1 );
this->Layout();
// Connect Events
m_buttonPMain->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PanelMAIN::m_btn_Counter_OnButtonClick ), NULL, this );
}
PanelMAIN::~PanelMAIN()
{
// Disconnect Events
m_buttonPMain->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PanelMAIN::m_btn_Counter_OnButtonClick ), NULL, this );
}
==== wxPanelAPP.h
#ifndef WXPANELAPP_H
#define WXPANELAPP_H
#include <wx/app.h>
class wxPanelApp : public wxApp
{
public:
virtual bool OnInit();
};
#endif // WXPANELAPP_H
==== wxPanelAPP.cpp
#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif
#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__
#include "wxPanelApp.h"
#include "wxPanelMain.h"
IMPLEMENT_APP(wxPanelApp);
bool wxPanelApp::OnInit()
{
wxPanelFrame* frame = new wxPanelFrame(0L);
frame->SetIcon(wxICON(aaaa)); // To Set App Icon
frame->Show();
return true;
}
==== wxPanelMain.h
#ifndef WXPANELMAIN_H
#define WXPANELMAIN_H
#include "wxPanelApp.h"
#include "GUIFrame.h"
#include "MyPanel.h"
#include <iostream>
class wxPanelFrame: public GUIFrame
{
public:
wxPanelFrame(wxFrame *frame);
~wxPanelFrame();
wxPanel *m_wxpMain = new PanelMAIN(this, wxID_ANY);
private:
virtual void OnClose(wxCloseEvent& event);
virtual void OnQuit(wxCommandEvent& event);
void m_menuItemPanelMainOnMenuSelection( wxCommandEvent& event );
};
#endif // WXPANELMAIN_H
==== wxPanelMain.cpp
#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif
#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__
#include "wxPanelMain.h"
wxPanelFrame::wxPanelFrame(wxFrame *frame) : GUIFrame(frame)
{
#if wxUSE_STATUSBAR
statusBar->SetStatusText(_("Simple Panel Test"), 0);
#endif
// Hide the panel
m_wxpMain->Show(false);
}
wxPanelFrame::~wxPanelFrame()
{
}
void wxPanelFrame::OnClose(wxCloseEvent &event)
{
Destroy();
}
void wxPanelFrame::OnQuit(wxCommandEvent &event)
{
Destroy();
}
void wxPanelFrame::m_menuItemPanelMainOnMenuSelection( wxCommandEvent& event )
{
// Show the panel
m_wxpMain->Show(true);
}
==== MyPanel.h
#ifndef MYPANEL_H
#define MYPANEL_H
#include "GUIFrame.h"
#include <iostream>
class MyPanel : public PanelMAIN
{
public:
MyPanel(wxPanel *panel);
virtual ~MyPanel();
int i{0};
protected:
private:
void m_btn_Counter_OnButtonClick( wxCommandEvent& event );
};
#endif // MYPANEL_H
==== MyPanel.cpp
#include "MyPanel.h"
MyPanel::MyPanel(wxPanel *panel) : PanelMAIN(panel)
{
std::cout << "MyPanel::MyPanel /*CONSTRUCTOR*/\n";
}
MyPanel::~MyPanel()
{
std::cout << "MyPanel::~MyPanel /*DESTRUCTOR*/\n";
}
void MyPanel::m_btn_Counter_OnButtonClick( wxCommandEvent& event )
{
wxString wxs_Count{};
i++;
wxs_Count << i;
m_staticText3->SetLabelText(wxs_Count);
}
You define your event handler in your derived class MyPanel, but you never create and instance of it. The line
wxPanel *m_wxpMain = new PanelMAIN(this, wxID_ANY);
only creates on object of the base class.
You should change this to
MyPanel *m_wxpMain = new MyPanel(this);
You also have an problem with the constructor for MyPanel. The parent needs to be a wxWindow not wxPanel. So the declaration should be something like
MyPanel(wxWindow *panel);
and the body should look something like
MyPanel::MyPanel(wxWindow *panel) : PanelMAIN(panel)
{
std::cout << "MyPanel::MyPanel /*CONSTRUCTOR*/\n";
}

Can I use custom color for a specific wx[Aui]Notebook tab

I'm triying to color each tab on wxWidgets with a different color, like when you tag an Excel Sheet, is there a way to do that in the C++ version of wxWidgets, with or without AUI?
I don't think there is anything that will let you do this out of the box; but with an Aui notebook, you can write a custom tab art to color the tabs as you see fit. Here's a hideous example that I just threw together to demonstrate one way to do this:
// 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/aui/auibook.h>
#include <map>
class MyTabArt:public wxAuiGenericTabArt
{
public:
MyTabArt():wxAuiGenericTabArt(){}
wxAuiTabArt* Clone()
{
return new MyTabArt(*this);
}
void AddTabColor(wxWindow* w, const wxColor& c)
{
m_tabColors[w] = c;
}
virtual void DrawTab(wxDC& dc, wxWindow* wnd, const wxAuiNotebookPage& page,
const wxRect& rect, int closeButtonState,
wxRect* outTabRect, wxRect* outButtonRect,
int* xExtent) wxOVERRIDE
{
wxSize tabSize = GetTabSize(dc, wnd, page.caption, page.bitmap,
page.active, closeButtonState, xExtent);
wxCoord tabHeight = m_tabCtrlHeight;
wxCoord tabWidth = tabSize.x;
wxCoord tabX = rect.x;
wxCoord tabY = rect.y + rect.height - tabHeight;
wxRect tabRect(tabX, tabY, tabWidth, tabHeight);
wxDCClipper clipper(dc, tabRect);
auto it = m_tabColors.find(page.window);
if ( it != m_tabColors.end() )
{
wxDCBrushChanger bchanger(dc, it->second);
wxDCPenChanger pchanger(dc, it->second);
dc.DrawRectangle(tabRect);
}
else
{
wxDCBrushChanger bchanger(dc, *wxGREEN);
wxDCPenChanger pchanger(dc, *wxGREEN);
dc.DrawRectangle(tabRect);
}
dc.DrawText(page.caption,tabRect.x,tabRect.y);
*outTabRect = tabRect;
}
private:
std::map<wxWindow*,wxColor> m_tabColors;
};
class MyFrame: public wxFrame
{
public:
MyFrame();
private:
};
MyFrame::MyFrame()
:wxFrame(NULL, wxID_ANY, "AUI Tab", wxDefaultPosition, wxSize(600, 400))
{
wxAuiNotebook * auiNotebook =
new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
wxPanel* panel1 = new wxPanel( auiNotebook, wxID_ANY );
wxPanel* panel2 = new wxPanel( auiNotebook, wxID_ANY );
auiNotebook->AddPage(panel1, "Page 1");
auiNotebook->AddPage(panel2, "Page 2");
MyTabArt* art = new MyTabArt();
art->AddTabColor(panel1, *wxRED);
art->AddTabColor(panel2, *wxBLUE);
auiNotebook->SetArtProvider(art);
}
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
::wxInitAllImageHandlers();
MyFrame* frame = new MyFrame();
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(MyApp);
On windows, this monstrosity looks like this:
You can look at the source wxWidgets source for the other tab arts to see an example of how to make this prettier.

How to drag and drop between two (or more) wxListCtrl (wxGTK)?

I'm trying to organize a wxListCtrl-derived control (xList) which support DnD between items (LC_REPORT view). So, I catch BEGIN_DRAG event
Connect(wxEVT_COMMAND_LIST_BEGIN_DRAG,
(wxObjectEventFunction)&xList::OnBeginDrag
);
and OnBeginDrag function is designed in a way to catch mouse motion and mouse left button up events for each instance of xList (list):
list->Connect(wxEVT_MOTION,
wxMouseEventHandler(xList::OnMoveDrag)
);
list->Connect(wxEVT_LEFT_UP,
wxMouseEventHandler(xList::OnEndDrag)
);
(and OnEndDrag disconnect them all). When I have single xList instance (one panel) it works perfectly, but when I have two it looks like motion and left-up events are caught only for the panel I start dragging from: I can DnD inside single panel, but when I drag mouse from one panel to another it still acts like xList::OnMoveDrag is still working for first panel. What I am missing to?
Is wxEVT_MOTION handled for each widget separately? If so, why program acts like this. If not, why it is always handled for widget I start dragging from, not the last connected one?
Here is a sample code (as far simple as I could reach) to show what's happening:
#include <wx/wx.h>
#include <vector>
class xList;
// class to store group of xList to DnD between
class DnDxList
{public:
void BeginDrag ();
void EndDrag ();
void AddList (xList* l) {list.push_back (l); }; // register new xList object
private:
std::vector<xList*> list;
};
class xList: public wxListCtrl
{public:
xList (DnDxList& dnd,
wxWindow *parent,
wxWindowID winid = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxLC_ICON,
const wxValidator &validator = wxDefaultValidator,
const wxString &name = wxListCtrlNameStr
);
virtual ~xList () {};
void OnBeginDrag(wxListEvent& event);
void OnEndDrag(wxMouseEvent& event);
void OnMoveDrag(wxMouseEvent& event);
DnDxList& dndsource; // keep reference to common DnDxList object
};
void DnDxList::BeginDrag () // connect motion and left-up events for all lists in group
{for (std::vector<xList*>::const_iterator i = list.begin(); i != list.end(); i++)
{(*i)->Connect(wxEVT_MOTION,
wxMouseEventHandler(xList::OnMoveDrag)
);
(*i)->Connect(wxEVT_LEFT_UP,
wxMouseEventHandler(xList::OnEndDrag)
);
}
};
void DnDxList::EndDrag () // disconnect all
{for (std::vector<xList*>::const_iterator i = list.begin(); i != list.end(); i++)
{(*i)->Disconnect(wxEVT_MOTION,
wxMouseEventHandler(xList::OnMoveDrag)
);
(*i)->Disconnect(wxEVT_LEFT_UP,
wxMouseEventHandler(xList::OnEndDrag)
);
}
}
xList::xList (DnDxList& dnd,
wxWindow *parent,
wxWindowID winid,
const wxPoint& pos,
const wxSize& size,
long style,
const wxValidator &validator,
const wxString &name
): wxListCtrl (parent, winid, pos, size, style, validator, name),
dndsource (dnd)
{Connect(wxEVT_COMMAND_LIST_BEGIN_DRAG,
(wxObjectEventFunction)&xList::OnBeginDrag
);
dndsource.AddList (this);
};
void xList::OnBeginDrag(wxListEvent& event) // begin drag
{SetCursor(wxCursor(wxCURSOR_HAND));
dndsource.BeginDrag();
}
void xList::OnMoveDrag(wxMouseEvent& event)
{std::cout << "Movie: " << this << std::endl; // to show the object for which the move event is called for
}
void xList::OnEndDrag(wxMouseEvent& event)
{std::cout << "End: " << this << std::endl;
dndsource.EndDrag();
SetCursor(wxCursor(*wxSTANDARD_CURSOR));
}
class xFrame: public wxFrame
{
public:
xFrame (const wxString& title,
const wxPoint& pos,
const wxSize& size
);
~xFrame () { }
private:
void OnExit(wxCommandEvent& event);
DECLARE_EVENT_TABLE();
DnDxList* dndxlist;
xList* lp;
xList* rp;
wxPanel* panel;
};
BEGIN_EVENT_TABLE(xFrame, wxFrame)
EVT_MENU(wxID_EXIT, xFrame::OnExit)
END_EVENT_TABLE()
xFrame::xFrame(const wxString& title,
const wxPoint& pos,
const wxSize& size
): wxFrame(NULL, wxID_ANY, title, pos, size)
{
panel = new wxPanel(this);
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
// create common DnDxList
dndxlist = new DnDxList();
// create two panels
lp = new xList (*dndxlist,
panel,
wxID_ANY,
wxDefaultPosition,
wxDefaultSize,
wxLC_REPORT | wxLC_SINGLE_SEL
);
rp = new xList (*dndxlist,
panel,
wxID_ANY,
wxDefaultPosition,
wxDefaultSize,
wxLC_REPORT | wxLC_SINGLE_SEL
);
// some contents
lp->InsertColumn(0, _("A"));
lp->InsertColumn(1, _("B"));
lp->InsertColumn(2, _("C"));
lp->InsertColumn(3, _("D"));
lp->SetColumnWidth(0, 100);
lp->SetColumnWidth(1, 100);
lp->SetColumnWidth(2, 100);
lp->SetColumnWidth(3, 100);
for (long i = 0; i < 100; i++)
{lp->InsertItem(i, 1);
for (int j = 0; j < 4; j++)
{wxString s;
s << _("lp [") << i << _(", ") << j << _("]");
lp->SetItem (i, j, s);
}
}
rp->InsertColumn(0, _("A"));
rp->InsertColumn(1, _("B"));
rp->InsertColumn(2, _("C"));
rp->InsertColumn(3, _("D"));
rp->SetColumnWidth(0, 100);
rp->SetColumnWidth(1, 100);
rp->SetColumnWidth(2, 100);
rp->SetColumnWidth(3, 100);
for (long i = 0; i < 100; i++)
{rp->InsertItem(i, 1);
for (int j = 0; j < 4; j++)
{wxString s;
s << _("rp [") << i << _(", ") << j << _("]");
rp->SetItem (i, j, s);
}
}
sizer->Add(lp,1, wxEXPAND | wxALL, 10);
sizer->Add(rp,1, wxEXPAND | wxALL, 10);
panel->SetSizer(sizer);
}
void xFrame::OnExit(wxCommandEvent& event)
{
Close( true );
}
class xApp: public wxApp
{
public:
virtual bool OnInit();
};
IMPLEMENT_APP(xApp);
bool xApp::OnInit()
{
xFrame *frame = new xFrame(_("Frame"), wxPoint(50, 50), wxSize(450, 340) );
frame->Show(true);
return true;
}
Looking into console output one can find that mouse motion event and mouse left-up event always calls methods for the same object, where dragging starts from, not the object mouse is actually on.
wxListCtrl-specific drag events are indeed only meant to be used for dragging the items inside the same control. To drag and drop stuff between different controls, or even between different applications, you need to use the general wxDragSource and wxDropTarget classes.