加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – PropertyGrid中的按钮

发布时间:2020-12-16 07:33:28 所属栏目:百科 来源:网络整理
导读:有没有办法将属性设置为按钮或向属性添加按钮?通过网格示例,我注意到你可以做一些事情 wxPGEditor* editorButton = wxPropertyGrid::RegisterEditorClass(someButton);propertyGrid-SetPropertyEditor(wxT("Name"),editorButton ); 但是,我希望有不同的按钮
有没有办法将属性设置为按钮或向属性添加按钮?通过网格示例,我注意到你可以做一些事情

wxPGEditor* editorButton = wxPropertyGrid::RegisterEditorClass(someButton);
propertyGrid->SetPropertyEditor(wxT("Name"),editorButton );

但是,我希望有不同的按钮,而不仅仅是一种类型,这将支持.

编辑:
通过不同的按钮,我的意思是按钮不需要使用编辑器.我想要做的是设置onClick回调函数,就像你通常用于wxButton,但将其设置为属性.

编辑2:要清楚,我希望属性字段只能是一个按钮.

解决方法

您必须创建一个自定义wxPGEditor,它根据存储在属性中的数据来中继按钮事件.
wxPGProperty可以存储用户定义的数据(wxClientData),该数据可用于存储回调函数.

首先,您必须定义将在按钮事件上调用的处理程序的函数签名.

typedef bool (wxEvtHandler::*ButtonEventMethod)(wxPGProperty*);

处理程序接收附加属性作为参数,如果属性被修改,则应返回true.

现在需要一个基于wxClientData的类来存储回调:

struct ButtonData : wxClientData {
    ButtonData(ButtonEventMethod method,wxEvtHandler* handler)
        : _method(method),_handler(handler) {}
    bool call(wxPGProperty* property) {
        return (*_handler.*_method)(property);
    }
private:
    ButtonEventMethod _method;
    wxEvtHandler* _handler;
};

该类只存储方法的地址及其所属的类.编辑器将从属性中提取此对象并执行call()方法,该方法依次执行回调:

class ButtonEventEditor : public wxPGTextCtrlAndButtonEditor {
protected:
    virtual bool OnEvent(wxPropertyGrid* propgrid,wxPGProperty* property,wxWindow* wnd_primary,wxEvent& event) const {
            // handle the button event
            if( event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED )
                // extract the client data from the property
                if( ButtonData* btn = dynamic_cast<ButtonData*>(property->GetClientObject()) )
                    // call the method
                    return btn->call(property);
            return wxPGTextCtrlAndButtonEditor::OnEvent(propgrid,property,wnd_primary,event);
    }
};

要将它包装起来,可以编写一个将方法“绑定”到属性的函数:

void BindButton(wxPGProperty* property,ButtonEventMethod method,wxEvtHandler* handler) {
    property->SetClientObject(new ButtonData(method,handler));
}

还有一个宏,使它更简单:

#define BIND_BUTTON(property,method,handler,editor) 
    property->SetEditor(editor); 
    BindButton(property,static_cast<ButtonEventMethod>(method),handler)

现在您可以将成员函数绑定到属性:

// register the editor
wxPGEditor* editor = propertyGrid->RegisterEditorClass(new ButtonEventEditor());

// create a property
wxPGProperty* prop = propertyGrid->Append(new wxStringProperty("StringProperty"));

// bind method foo to the property
BIND_BUTTON(prop,&Frame::foo,this,editor);

方法foo可能如下所示:

bool Frame::foo(wxPGProperty* p) {
    p->SetValue("foo");
    return true;
}

这只是一个示例,用于演示wxPGProperty如何存储回调(而不是创建多个wxPGEditors).可以修改回调存储(此处为ButtonData)以存储std::functionboost::function(这将需要C 11或boost).

另一种方法是将回调信息存储在wxPGEditor实例中.但是,这需要多个编辑器实例,每个不同的回调函数一个.

UPDATE

the actual “button” does not show up until you click in the string field

在选择属性之前,不会激活编辑器.
您必须创建一个自定义wxPGProperty,返回一个自定义wxPGCellRenderer来控制属性的表示(当它没有被编辑时).
不幸的是,这会产生幻觉,并要求用户单击按钮两次:首先激活属性(和编辑器),然后激活实际按钮.
我们想到的一个解决方案是在单元格中显示单击以进行编辑等文本,或者显示属性值的简短摘要.

虽然可以让自定义属性创建一个按钮并忽略编辑器系统,但属性网格不是设计为以这种方式工作而且这种“黑客”可能会导致一些问题.但是,我最后加入了黑客攻击.

there is a string field,when I just want the button to take up the entire property

这只是我用作示例基类的编辑器的副作用,并且很容易更改.由于不需要wxTextCtrl,只需基于
直接编辑wxPGEditor并自己创建控件(单个按钮):

class ButtonEventEditor : public wxPGEditor {
protected:
    virtual wxPGWindowList CreateControls(wxPropertyGrid* propgrid,const wxPoint& pos,const wxSize& size) const {
            // create and return a single button to be used as editor
            // size and pos represent the entire value cell: use that to position the button
            return wxPGWindowList(new wxButton(propgrid,wxPG_SUBID1,"Edit",pos,size));
    }
    // since the editor does not need to change the primary control (the button)
    // to reflect changes,UpdateControl is just a no-op
    virtual void UpdateControl(wxPGProperty* property,wxWindow* ctrl) const {}
    // and here we remove the call to the base class because it is abstract
    virtual bool OnEvent(wxPropertyGrid* propgrid,wxEvent& event) const {
            if( event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED )
                if( ButtonData* btn = dynamic_cast<ButtonData*>(property->GetClientObject()) )
                    return btn->call(property);
            return false;
    }
};

with this method,it seems there could only be one property editor

如果你的意思是总:wxPropertyGrid :: RegisterEditorClass只是注册一个带有属性网格的编辑器(网格将取得编辑器的所有权,并在销毁属性网格时自动删除它).您可以根据需要注册任意数量的编辑器.您将编辑器设置为特定属性,而不是整个属性网格.

如果您的意思是同时:是的,遗憾的是,在任何给定时间只有一个属性编辑器可以处于活动状态.

黑客

让我用前面提到的黑客来完成这个任务.

首先,我们需要一个自定义的wxPGCellRenderer来定位属性网格上的按钮:

class ButtonMover : public wxPGCellRenderer {
public:
    // pointer to the button from the property
    ButtonMover(wxButton* btn) : _btn(btn) {}
protected:
    virtual bool Render(wxDC &dc,const wxRect &rect,const wxPropertyGrid *propertyGrid,wxPGProperty *property,int column,int item,int flags) const {
            if( column == 0 ) { // 0 = label,1 = value
                // instead of actually drawing the cell,// move the button to the cell position:
                wxRect rc(rect);
                // calculate the full property width
                rc.SetWidth(propertyGrid->GetClientRect().width-rect.GetX());
                _btn->SetSize(rc); // move button
                _btn->Show(); // initially hidden,show once 'rendered' (moved)
            }
            return true;
    }
private:
    wxButton* _btn;
};

现在我们可以创建自定义属性:

class ButtonProperty : public wxPGProperty {
public:
    // [parent] should be the property grid
    // [func] is the event handler
    // [button] is the button label
    // [label] is the property display name (sort name with autosort)
    // [name] is the internal property name
    ButtonProperty(wxWindow* parent,wxObjectEventFunction func,const wxString& button,const wxString& label=wxPG_LABEL,const wxString& name=wxPG_LABEL) 
        : wxPGProperty(label,name),_btn(new wxButton(parent,wxID_ANY,button)),_renderer(_btn) {
                // connect the handler to the button
                _btn->Connect(wxEVT_COMMAND_BUTTON_CLICKED,func);
                _btn->Hide(); // when it's off the grid,it's not rendered 
                              // (thus not moved properly)
    }
protected:
    virtual wxPGCellRenderer* GetCellRenderer(int column) const {
        return &_renderer; // return button mover
    }
    virtual const wxPGEditor* DoGetEditorClass () const {
        return 0; // not using an editor
    }
private:
    wxButton* _btn; // the button attached to the property
    mutable ButtonMover _renderer; // the button mover
};

删除了对编辑器的需求后,您现在可以将事件处理程序直接附加到属性:

propertyGrid->Append( new ButtonProperty(
    propertyGrid,// parent window
    wxCommandEventHandler(Frame::OnClick1),// event handler
    "Click me!") // button label
);

propertyGrid->Append( new ButtonProperty(
    propertyGrid,wxCommandEventHandler(Frame::OnClick2),"Edit this!")
);

处理程序看起来像这样:

void OnClick1(wxCommandEvent& event) {
    //TODO ...
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读