Search code examples
c++visual-studiowxwidgets

How to make a window/frame/control draggable?


How can I make the wxGrid instance draggable? That is the wxGrid is embedded on the main wxFrame. By default one can move the whole app window by clicking on the title bar and just dragg. How to make the whole app window be movable/draggable that is also when clicked/grabbed inside the inner wxGrid object?

Here is the illustration:

And the code:

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

class ImageBgFrame : public wxFrame
{
public:
    ImageBgFrame(wxFrame* frame, const wxString& title);

private:

    void OnImagePanelPaint(wxPaintEvent&);
    void OnExit(wxCommandEvent&);
    void CreateScaledBg();

    wxImageHandler* m_pngLoader;
    wxPanel* m_imagePanel;
    wxImage m_image;
    wxBitmap m_BgBitmap;
    wxGrid* m_grid;

};

ImageBgFrame::ImageBgFrame(wxFrame* frame, const wxString& title)
    :wxFrame(frame, wxID_ANY, title)
{
    m_pngLoader = new wxPNGHandler();
    wxImage::AddHandler(m_pngLoader);

    m_grid = new wxGrid( this, -1, wxPoint(0, 0), wxSize(400, 300) );
    m_grid->CreateGrid(3, 8);
    m_grid->SetCellValue(0, 0, "823");
    m_grid->SetColFormatFloat(1);
    m_grid->SetColFormatFloat(2);

    // Try to load the image.
    m_image = wxImage("D:\\Pobrane_2\\armor_info3.png", wxBITMAP_TYPE_PNG);
    if (!m_image.IsOk())
    {
        return;
    }

    // Create the controls.
    m_imagePanel = new wxPanel(this, wxID_ANY);
    CreateScaledBg();
    
    Layout();

    // Bind Event Handlers
    m_imagePanel->Bind(wxEVT_PAINT, &ImageBgFrame::OnImagePanelPaint, this);
}

void ImageBgFrame::OnImagePanelPaint(wxPaintEvent&)
{
    if (m_imagePanel->GetSize() != m_BgBitmap.GetSize())
    {
        CreateScaledBg();
    }
}

void ImageBgFrame::OnExit(wxCommandEvent&)
{
    Close();
}

void ImageBgFrame::CreateScaledBg()
{
    wxSize sz = m_imagePanel->GetSize();
    m_BgBitmap = wxBitmap(m_image.Scale(sz.GetWidth(), sz.GetHeight(),
        wxIMAGE_QUALITY_NORMAL));
}


class ImageBgApp : public wxApp
{
public:
    bool OnInit()
    {
        ImageBgFrame* frame = new ImageBgFrame(NULL, "Image BG");
        frame->SetTransparent(150);
        frame->Show();
        return true;
    }
};

wxIMPLEMENT_APP(ImageBgApp);

Solution

  • You will have to capture mouse events (button down, move, release, capture loss) on all grid windows, i.e. wxGrid::GetGridWindow(), GetGridRowLabelWindow(), GetGridColLabelWindow() and GetGridCornerLabelWindow() and move the window yourself accordingly.

    Under Windows (only) a simpler to make the whole window draggable is by returning HTCAPTION from WM_NCHITTEST handler, but this will almost surely prevent the user from using wxGrid normally.