double buffering makes spin button disappear

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
mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 449
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

double buffering makes spin button disappear

Post by mael15 » Fri Apr 24, 2020 7:04 am

Hello everyone,
I have a little visual problem. As you can see in this minimal example, when one clicks the upper button on a wxSpinCtrl, the lower button under the cursor disappears and stays gone if one moves the mouse to the right afterwards. This is because I use SetDoubleBuffered(true) to avoid flickering when changing the wxNotebook pages.
Another tiny detail: the border lines around the spin buttons have a different color than the lines around the text control, but I could live with that.
spin.jpg
spin.jpg (6.83 KiB) Viewed 261 times

Code: Select all

#pragma once

#include <wx/frame.h>
#include <wx/app.h>
#include <wx/notebook.h>
#include <wx/spinctrl.h>

enum class NBPageType : int {
	WITH_BUTTON = 0,
	WITH_SPIN
};

class nbPage {
public:
	nbPage(NBPageType _type) : type(_type){}
	NBPageType type = NBPageType::WITH_BUTTON;
};

class MyFrame1 : public wxFrame 
{
public:
	MyFrame1( wxWindow* parent = NULL, 
		wxWindowID id = wxID_ANY, 
		const wxString& title = wxEmptyString, 
		const wxPoint& pos = wxDefaultPosition, 
		const wxSize& size = wxSize( 300,500 ), 
		long style = wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) :
		wxFrame(parent, id, title, pos, size, style)
	{
		SetDoubleBuffered(true);
		SetSizer(new wxBoxSizer(wxHORIZONTAL));
		notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_FIXEDWIDTH | wxNB_NOPAGETHEME | wxCLIP_CHILDREN);
		Bind(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &MyFrame1::onNotebookPageChanged, this);
		GetSizer()->Add(notebook, 1, wxEXPAND);

		pages.push_back(nbPage(NBPageType::WITH_SPIN));
		pages.push_back(nbPage(NBPageType::WITH_SPIN));
		//pages.push_back(nbPage(NBPageType::WITH_BUTTON));

		for (auto page : pages) {
			wxPanel* pan = new wxPanel(notebook);
			pan->SetSizer(new wxBoxSizer(wxVERTICAL));
			notebook->AddPage(pan, wxEmptyString);

			wxBoxSizer* radioSiz = new wxBoxSizer(wxHORIZONTAL);
			wxRadioButton* radioButton = new wxRadioButton(pan, wxID_ANY, wxT("with button"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
			radioButton->SetValue(true);
			radioButton->Bind(wxEVT_RADIOBUTTON, &MyFrame1::onTypeChoice, this);
			radioSiz->Add(radioButton, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 1);
			wxRadioButton* radioSpin = new wxRadioButton(pan, wxID_ANY, wxT("with spin"));
			radioSpin->Bind(wxEVT_RADIOBUTTON, &MyFrame1::onTypeChoice, this);
			radioSiz->Add(radioSpin, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 1);
			pan->GetSizer()->Add(radioSiz);

			for (int i = 0; i < 10; i++) {
				pan->GetSizer()->Add(new wxButton(pan, wxID_ANY, wxT("button")));
				pan->GetSizer()->AddSpacer(5);
				pan->GetSizer()->Add(new wxStaticText(pan, wxID_ANY, wxT("text")));
				wxSpinCtrl* spinCtrl = new wxSpinCtrl(pan, wxID_ANY/*, wxEmptyString, wxDefaultPosition, wxSize(60- -1), 1, 100*/);
				spinCtrl->Bind(wxEVT_SPINCTRL, &MyFrame1::onSpin, this);
				pan->GetSizer()->Add(spinCtrl);
			}
		}

		notebook->SetSelection(0);

		initControls();

		this->SetSizeHints(wxDefaultSize, wxDefaultSize);
		this->Centre(wxBOTH);
	}

	~MyFrame1(){}
	void onNotebookPageChanged(wxBookCtrlEvent& evt) {
		initControls();
	}
	void onTypeChoice(wxCommandEvent& evt) {
		int idx = notebook->GetSelection();
		wxRadioButton* thisBtn = (wxRadioButton*)evt.GetEventObject();
		NBPageType newType = thisBtn->GetLabel() == wxT("with button") ? NBPageType::WITH_BUTTON : NBPageType::WITH_SPIN;
		pages.at(idx).type = newType;
		initControls();
	}
private:
	wxNotebook* notebook = nullptr;

	std::vector<nbPage>pages;
	std::vector<wxButton*>buttons;
	std::vector<wxSpinCtrl*>spins;

	void initControls() {
		int idx = notebook->GetSelection();
		NBPageType curPageType = pages.at(idx).type;
		wxWindow *curWin = notebook->GetCurrentPage();

		wxWindow* win = nullptr;
		for (unsigned int i = 0; i < curWin->GetChildren().GetCount(); i++) {
			win = curWin->GetChildren().Item(i)->GetData();
			if (win->IsKindOf(wxCLASSINFO(wxButton)) || win->IsKindOf(wxCLASSINFO(wxStaticText)))
				win->Show(curPageType == NBPageType::WITH_BUTTON);
			else if (win->IsKindOf(wxCLASSINFO(wxSpinCtrl)))
				win->Show(curPageType == NBPageType::WITH_SPIN);
			else if (win->IsKindOf(wxCLASSINFO(wxRadioButton)))
				static_cast<wxRadioButton*>(win)->SetValue(curPageType == NBPageType::WITH_BUTTON && static_cast<wxRadioButton*>(win)->GetLabel() == wxT("with button") ||
					curPageType == NBPageType::WITH_SPIN && static_cast<wxRadioButton*>(win)->GetLabel() == wxT("with spin"));
		}

		curWin->Layout();
		curWin->Refresh();
	}

	void onSpin(wxSpinEvent& evt) {
		OutputDebugString(wxT("onSpin\n"));
		Update();
		Refresh();
		evt.Skip(); 
	}
};

class MyApp : public wxApp {
	virtual bool OnInit() {
		MyFrame1* mainFrame = new MyFrame1();
		mainFrame->Show();
		SetTopWindow(mainFrame);

		return TRUE;
	}
};

wxIMPLEMENT_APP(MyApp);
Is there a way to have perfect visuals, a not disappearing lower spin button and no flickering?
Thank you!

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2662
Joined: Sun Jan 03, 2010 5:45 pm

Re: double buffering makes spin button disappear

Post by PB » Fri Apr 24, 2020 8:03 am

Maybe is it related to this unsolved bug
https://trac.wxwidgets.org/ticket/18231#comment:3

Are you doing anything in the spin event handler?

mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 449
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: double buffering makes spin button disappear

Post by mael15 » Fri Apr 24, 2020 8:49 am

PB wrote:
Fri Apr 24, 2020 8:03 am
Maybe is it related to this unsolved bug
https://trac.wxwidgets.org/ticket/18231#comment:3

Are you doing anything in the spin event handler?
That is probably it. I am not doing anything in the spin event handler, I was just trying to fresh the wxSpinCtrl to make the arrow appear again, but it doesn´t, with or without the handler.
Then I guess I will have to live with it for now. Or maybe there is some other way than SetDoubleBuffered(true) to avoid the wxNotebook flicker when changing pages?

Post Reply