wxPropertyGrid with additional checkbox to each property Topic is solved

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
User avatar
vouk
Knows some wx things
Knows some wx things
Posts: 25
Joined: Fri Feb 15, 2019 7:34 am
Location: Germany
Contact:

wxPropertyGrid with additional checkbox to each property

Post by vouk »

propgrid.png
propgrid.png (11.05 KiB) Viewed 1493 times
Can anybody tell me how to do something like this with wxWidgets? I'd like to have checkboxes next to some properties. I guess I have to overwrite some methods in the wxPGProperties, right? Or is there a more elegant way?

Thank you.
New Pagodi
Super wx Problem Solver
Super wx Problem Solver
Posts: 466
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: wxPropertyGrid with additional checkbox to each property

Post by New Pagodi »

This is a really good question, but I don't think there is a good answer. Looking over the code, I think you might have to derive a class for each renderer you use and re-implement the Render method for column 0 to draw the check box and then the property label. You'll then need some way to keep track of the checkbox states with something like std::map<wxPGProperty*,bool>. Finally you'll need to handle the left down mouse click for the property grid to check if it's over a checkbox and change the state if it is.

In hindsight, the property grid class should probably have had a state image like the tree control class does. Then the state image could be repurposed to do most of what you want to do here automatically.
User avatar
vouk
Knows some wx things
Knows some wx things
Posts: 25
Joined: Fri Feb 15, 2019 7:34 am
Location: Germany
Contact:

Re: wxPropertyGrid with additional checkbox to each property

Post by vouk »

That's basically what i have expected.

So i'd need to implement/overwrite:

- virtual wxPGCellRenderer* GetCellRenderer( int column ) const;

Do you know any good example code on how to do this?

btw. I could add a boolean flag that stores the state in the derived property.
New Pagodi
Super wx Problem Solver
Super wx Problem Solver
Posts: 466
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: wxPropertyGrid with additional checkbox to each property

Post by New Pagodi »

That does seem like a pretty good approach. Other than the wxWidgets source code itself, you probably won't find any example code. If you can't make any progress, I'll see if I can throw something together tomorrow.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7459
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: wxPropertyGrid with additional checkbox to each property

Post by ONEEYEMAN »

Hi,
Did you run the propgrid sample? I thought I saw something like this already there...

Thank you.
New Pagodi
Super wx Problem Solver
Super wx Problem Solver
Posts: 466
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: wxPropertyGrid with additional checkbox to each property

Post by New Pagodi »

Here's one way to do this. As discussed above, this uses a derived renderer and overrides the Render method. It basically just inappropriately injects a bitmap into the labels column and then calls the base class Render method.

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/dcmemory.h>
#include <wx/renderer.h>
#include <wx/propgrid/propgrid.h>
#include <wx/propgrid/advprops.h>

///////////// Declarations

class MyRenderer:public wxPGDefaultRenderer
{
public:
    virtual bool Render(wxDC&, const wxRect&, const wxPropertyGrid*,
                        wxPGProperty*, int column, int item, int flags )
                        const wxOVERRIDE;
};

class MyStringProperty:public wxStringProperty
{
public:
    MyStringProperty(const wxString &label=wxPG_LABEL,
                     const wxString &name=wxPG_LABEL,
                     const wxString &value=wxEmptyString,
                     bool isChecked = false);

    virtual wxPGCellRenderer* GetCellRenderer (int column) const wxOVERRIDE;

    bool IsChecked() const;
    void ChangeStatus();
    int GetCheckMinX() const;
    int GetCheckMaxX() const;
    void SetCheckMinX(int x);
    void SetCheckMaxX(int x);

private:
    bool m_checked;
    int m_checkMinX;
    int m_checkMaxX;

    wxDECLARE_ABSTRACT_CLASS(MyStringProperty);
};

class MyFrame : public wxFrame
{
    public:
        MyFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo",
                 wxPoint pos = wxDefaultPosition, wxSize size = wxSize(481,466),
                 int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
    private:
        void OnLeftDown(wxMouseEvent& event);
        wxPropertyGrid* m_propGrid;
};

class MyApp : public wxApp
{
    public:
        virtual bool OnInit() wxOVERRIDE;
        virtual int OnExit () wxOVERRIDE;
        MyRenderer* m_renderer;
};

wxDECLARE_APP(MyApp);


///////////// Implementation

bool MyRenderer::Render( wxDC& dc,
                         const wxRect& rect,
                         const wxPropertyGrid* propertyGrid,
                         wxPGProperty* property,
                         int column,
                         int item,
                         int flags ) const
{
    if ( column == 0 && item == -1 )
    {
        MyStringProperty* msp = wxDynamicCast(property, MyStringProperty);

        if ( msp )
        {
            // Make a bitmap of a checkbox
            wxRendererNative& renderer = wxRendererNative::Get();
            wxSize sz = renderer.GetCheckBoxSize(
                                    const_cast<wxPropertyGrid*>(propertyGrid));

            wxBitmap bmp(sz.GetWidth(), rect.GetHeight()-1);
            wxMemoryDC mem(bmp);
            mem.SetBackground(wxBrush(*wxGREEN));
            mem.Clear();
            wxRect r(0, 0, sz.GetWidth(), rect.GetHeight()-1);
            int cbFlags = msp->IsChecked() ? wxCONTROL_CHECKED : 0;

            renderer.DrawCheckBox(const_cast<wxPropertyGrid*>(propertyGrid),
                                  mem, r, cbFlags) ;
            mem.SelectObject(wxNullBitmap);
            bmp.SetMask(new wxMask(bmp, *wxGREEN));

            // Set the bitmap that was made to be the cell's bitmap
            property->GetCell(0).SetBitmap(bmp);

            // Record the location at which the checkbox was drawn, so that
            // we can tell if mouse clicks occur over it
            int checkMinX =
                rect.GetLeft() + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1;
            msp->SetCheckMinX(checkMinX);
            msp->SetCheckMaxX(checkMinX+sz.GetWidth());
        }
    }

    return wxPGDefaultRenderer::Render(dc, rect, propertyGrid, property,
                                       column,item,flags );
}

MyStringProperty::MyStringProperty(const wxString &label, const wxString &name,
                                   const wxString &value, bool isChecked)
                 :wxStringProperty (label, name, value)
{
    m_checked = isChecked;
}

wxPGCellRenderer* MyStringProperty::GetCellRenderer(int column) const
{
    if ( column == 0 )
        return wxGetApp().m_renderer;
    else
        return wxStringProperty::GetCellRenderer(column);
}

bool MyStringProperty::IsChecked() const
{
    return m_checked;
}

void MyStringProperty::ChangeStatus()
{
    m_checked=!m_checked;
}

int MyStringProperty::GetCheckMinX() const
{
    return m_checkMinX;
}

int MyStringProperty::GetCheckMaxX() const
{
    return m_checkMaxX;
}

void MyStringProperty::SetCheckMinX(int x)
{
    m_checkMinX=x;
}

void MyStringProperty::SetCheckMaxX(int x)
{
    m_checkMaxX=x;
}

MyFrame::MyFrame( wxWindow* parent, int id, wxString title, wxPoint pos,
                  wxSize size, int style )
        :wxFrame( parent, id, title, pos, size, style )
{
    wxPanel* panel =  new wxPanel( this, wxID_ANY );

    m_propGrid = new wxPropertyGrid(panel, wxID_ANY, wxDefaultPosition,
                                    wxDefaultSize,
                                    wxPG_DEFAULT_STYLE|wxPG_SPLITTER_AUTO_CENTER
                                    );
    m_propGrid->Append( new wxStringProperty("String without checkbox") );
    m_propGrid->Append( new MyStringProperty("String with checkbox") );
    m_propGrid->Bind(wxEVT_LEFT_DOWN,&MyFrame::OnLeftDown,this);

    wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
    bSizer->Add( m_propGrid, 1, wxALL|wxEXPAND, 5 );
    panel->SetSizer( bSizer );
    Layout();
}

void MyFrame::OnLeftDown(wxMouseEvent& event)
{
    wxPropertyGridHitTestResult htr = m_propGrid->HitTest(event.GetPosition());
    wxPGProperty* prop = htr.GetProperty();
    MyStringProperty* msp = wxDynamicCast(prop, MyStringProperty);

    if ( msp && htr.GetColumn()==0 )
    {
        int minx = msp->GetCheckMinX();
        int maxx = msp->GetCheckMaxX();
        int evx = event.GetPosition().x;

        if ( minx <= evx && evx <= maxx )
            msp->ChangeStatus();
    }

    event.Skip();
}

 bool MyApp::OnInit()
{
    m_renderer = new MyRenderer();
    MyFrame* frame = new MyFrame(NULL);
    frame->Show();
    return true;
}

int MyApp::OnExit()
{
    if(m_renderer)
        delete m_renderer;
    return wxApp::OnExit();
}

wxIMPLEMENT_ABSTRACT_CLASS(MyStringProperty,wxStringProperty);
wxIMPLEMENT_APP(MyApp);
sample.png
sample.png (4.92 KiB) Viewed 1430 times
There's probably much better ways to do this.
User avatar
vouk
Knows some wx things
Knows some wx things
Posts: 25
Joined: Fri Feb 15, 2019 7:34 am
Location: Germany
Contact:

Re: wxPropertyGrid with additional checkbox to each property

Post by vouk »

New Pagodi, thanks alot! This was really helpful. I can really start migrating from MFC to wxWidgets now.

ONEEYEMAN, I did not find this in the propgrid example.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7459
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: wxPropertyGrid with additional checkbox to each property

Post by ONEEYEMAN »

OK.
Post Reply