2
votes

I am using wxWidgets 2.8, together with wxPropertyGrid 1.4 in an application. For float values, I would like to use a slider to edit them. However, a slider editor is not provided by default, so I have resorted to implementing my own editor, following the guidelines mentioned in the documentation.

However, with this new editor, even though I set it as the editor for my float property, it's not actually appearing until the property grid cell is in any way interacted with (e.g. clicked). Until then, the classic, textbox based controller is still visible.

Apparently, the actual CreateControl method for the slider editor isn't called when the propgrid gets generated - it's only called when the cell itself is somehow interacted with.

Here's my custom property editor:

wxpgslider.h

class WXDLLIMPEXP_PG wxPGSliderEditor : public wxPGEditor 
{
#ifndef SWIG
  WX_PG_DECLARE_EDITOR_CLASS(wxPGSliderEditor)
#endif

public:
  wxPGSliderEditor (int p = 10000)
    : precision(p)
  {
  }

  ~wxPGSliderEditor ()
  {}

  // Macro for the CreateControls method stub
  wxPG_DECLARE_CREATECONTROLS

  void UpdateControl ( wxPGProperty* property, wxWindow* wnd) const;
  bool OnEvent ( wxPropertyGrid* propgrid, wxPGProperty* property, wxWindow* wnd, wxEvent& event) const;
  bool GetValueFromControl ( wxVariant& variant, wxPGProperty* property, wxWindow* wnd) const;
  void SetValueToUnspecified ( wxPGProperty* property, wxWindow* wnd) const;
  //void DrawValue ( wxDC& dc, const wxRect& rect, wxPGProperty* property, const wxString& text) const;

private:
  int precision;
};

wxpgslider.cpp

#include "cseditor/wxpgslider.h"

//----------------- wxPGSliderEditor ---------------------

WX_PG_IMPLEMENT_EDITOR_CLASS(SliderEditor, wxPGSliderEditor, wxPGEditor)

wxPGWindowList wxPGSliderEditor::CreateControls( wxPropertyGrid*  propgrid,
                                                 wxPGProperty*    property,
                                                 const wxPoint&   pos,
                                                 const wxSize&    size ) const
{
  double v_d = property->GetValue().GetDouble();
  if ( v_d  1 )
    v_d = 1;

  wxSlider *ctrl = new wxSlider();

#ifdef __WXMSW__
  ctrl->Hide();
#endif

  ctrl->Create ( propgrid->GetPanel(),
                 wxPG_SUBID2,
                 (int)(v_d * precision),
                 0,
                 precision,
                 pos,
                 size,
                 wxSL_HORIZONTAL );

  return wxPGWindowList(ctrl);
}

void wxPGSliderEditor::UpdateControl ( wxPGProperty* property, wxWindow* wnd ) const
{
  wxSlider* ctrl = wxDynamicCast ( wnd, wxSlider );
  if ( ctrl )
  {
    double val;
    if (wxPGVariantToDouble (property->DoGetValue(), &val))
    {
      if ( val  1 )
        val = 1;
      ctrl->SetValue ( (int)(val * precision) );

      //static_cast(property)->GetLabel()
      //  ->SetValue( wxString::Format(wxT("%ld"), val * precision) );
    }
  }
}

bool wxPGSliderEditor::OnEvent ( wxPropertyGrid*  propgrid, 
                                 wxPGProperty*    property,
                                 wxWindow*        wnd,
                                 wxEvent&         event ) const
{
  if(event.GetEventType() == wxEVT_SCROLL_CHANGED)
  {
    // Update the value    
    event.Skip();
    propgrid->EditorsValueWasModified();

    return true;
  }
  
  return false;
}

bool wxPGSliderEditor::GetValueFromControl ( wxVariant&     variant,
                                             wxPGProperty*  property,
                                             wxWindow*      wnd ) const
{
  wxSlider* ctrl = wxDynamicCast ( wnd, wxSlider );
  if ( ctrl )
  {
    variant = wxVariant ( (double)(ctrl->GetValue())/(double)(precision) );
    property->SetValue ( variant );
  }

  return true;
}

void wxPGSliderEditor::SetValueToUnspecified ( wxPGProperty* property, wxWindow* wnd) const
{
  wxSlider* ctrl = wxDynamicCast ( wnd, wxSlider );
  if ( ctrl )
  {
    ctrl->SetValue (0);
  }
}

And this is the code I'm using to generate the slider, in a Populate function:

double value = variant->GetFloat();

// Generate a homebrewed slider
wxFloatProperty* fp = new wxFloatProperty(translatedName, originalName, value);
wxPGEditor* rHandle = wxPropertyGrid::RegisterEditorClass(new wxPGSliderEditor(), wxT("SliderEditor"));
fp->SetEditor(rHandle);
page->AppendIn(categoryID, fp);

I register the class, in case it's not been registered before, then set the property's editor. Then I add the property to the grid. Why is the slider not showing up until the cell gets interacted with?

Is calling pgMan->GetGrid()->SelectProperty(fp, false); the only way to make it get drawn?

1

1 Answers

0
votes

you are using

#ifdef __WXMSW__
  ctrl->Hide();
#endif

what's about

#ifdef __WXMSW__
    ctrl->Show();
#endif

sample:

....
  wxSlider* ctrl = new wxSlider();
#ifdef __WXMSW__
    ctrl->Hide();
#endif
....
ctrl->Create ( propgrid->GetPanel(),
             wxPG_SUBID2,
             (int)(v_d * precision),
             0,
             precision,
             pos,
             size,
             wxSL_HORIZONTAL );

#ifdef __WXMSW__
    ctrl->Show();
#endif

return wxPGWindowList(ctrl);
}

EDIT

I can not see an OnCustomEditorEvent in your code.

with wxEVT_SCROLL_THUMBTRACK or wxEVT_SCROLL_CHANGED.

....

propgrid->Connect( wxPG_SUBID2, wxEVT_SCROLL_CHANGED,
                       (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
                       &wxPropertyGrid::OnCustomEditorEvent, NULL, propgrid );

#ifdef __WXMSW__
  ctrl->Show();
#endif

return wxPGWindowList(ctrl);
}