Search code examples
c++wxwidgetsdouble-buffering

Why does turning on double buffering break my list control and resizing the window then fixes it?


I am using a wxListCtrl in report style in a programming project on Windows 10, using Visual Studio 2017. I noticed that when the program first starts, there are some strange artifacts: the vertical lines between the columns don't move with the headers when I resize them with the mouse. Also, the scrollbar does not move when I drag it but the list jumps to the position when I release the mouse button. Once I resize the window however, everything is fine.

After reducing the program to a minimal example, I found out that turning off double buffering for the frame that contains the list control fixes everything. But I don't really understand why. Can anybody explain this to me?

#include <wx/wx.h>
#include <wx/listctrl.h>

class MainWindow : public wxFrame
{

public:
    MainWindow();
    void updateWidgets();


private:
    wxListCtrl *listCtrl;
        void initWidgets();

};

MainWindow::MainWindow()
{
    // ****************************************************************
    // Set window properties and init the widgets.
    // ****************************************************************

    wxFrame::Create(NULL, wxID_ANY, wxT("wxListCtrl Issue"), wxDefaultPosition,
        wxDefaultSize, wxCLOSE_BOX | wxMINIMIZE_BOX | wxMAXIMIZE_BOX |
        wxSYSTEM_MENU | wxCAPTION | wxRAISED_BORDER | wxRESIZE_BORDER);

    // Comment the following line to fix the list control, but why?
    this->SetDoubleBuffered(true);

    initWidgets();
}

void MainWindow::initWidgets()
{

    listCtrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition,
        wxDefaultSize, wxLC_REPORT);
    listCtrl->InsertColumn(0, wxT("Col 0"), wxLIST_FORMAT_LEFT, 50);
    for (int i = 0; i < 60; i++)
    {
        long index = listCtrl->InsertItem(0, wxT("Item"));
    }   

}

class wxListCtrl_Issue : public wxApp
{
public:
    virtual bool OnInit();
};

bool wxListCtrl_Issue::OnInit()
{
    MainWindow *mainWindow = new MainWindow();
    mainWindow->Show(true);
    return true;
}

wxIMPLEMENT_APP(wxListCtrl_Issue);


Solution

  • Generally speaking, you shouldn't interfere with the drawing of native controls and wxListCtrl is native under MSW. Moreover, it already is double-buffered using its own specific mechanism for this (LVS_EX_DOUBLEBUFFER) and so it's not surprising at all that setting WS_EX_COMPOSITED for it unexpectedly (from the controls point of view) breaks it.

    I.e. the answer is simple: just don't call SetDoubleBuffered() for it, nor any other native control.