2012-11-15 61 views
4

有沒有將屬性設置爲按鈕或將按鈕添加到屬性的方法?翻翻格子樣我注意到,你可以做一些事情,如PropertyGrid中的按鈕

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

不過,我想有不同的按鈕,而不是一個類型,它這個會支持。

編輯: 通過不同的按鈕,我的意思是沒有上捎帶關閉使用編輯器的按鈕。我想要做的就是設置一個onClick回調函數,就像你通常爲wxButton所做的那樣,但是將其設置爲一個屬性。

EDIT2:爲了清楚起見,我希望屬性字段的自己只是一個按鈕。

+0

請解釋您的意思是'不同的按鈕'。 – ravenspoint

回答

1

您必須創建一個自定義的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

實際的「按鈕」不顯示,直到您在串場

編輯,直到選中屬性單擊未激活。 您必須創建一個自定義wxPGProperty,返回一個自定義wxPGCellRenderer以控制屬性的表示形式(而不是正在編輯)。 不幸的是,這會產生幻覺,並要求用戶點擊兩次按鈕:首先激活屬性(和編輯器),然後是實際的按鈕。 想到的一種解決方案是在單元格中顯示文本Click to edit,或者顯示屬性值的簡短摘要。

雖然可以讓自定義屬性創建一個按鈕並忽略編輯器系統,但屬性網格並不是以這種方式工作的,這種「黑客」可能會導致一些問題。不過,我在最後加上了黑客。

有一個字符串場,當時我只想按鈕佔據整個財產

這是我用來作爲例如基類的編輯器只是一個副作用,很容易改變。由於不需要在wxTextCtrl,只要立足於wxPGEditor直接 編輯和創建控件(一個按鈕)自己:

class ButtonEventEditor : public wxPGEditor { 
protected: 
    virtual wxPGWindowList CreateControls(wxPropertyGrid* propgrid, 
     wxPGProperty* property, 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, wxPGProperty* property, 
     wxWindow* wnd_primary, wxEvent& event) const { 
      if(event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED) 
       if(ButtonData* btn = dynamic_cast<ButtonData*>(property->GetClientObject())) 
        return btn->call(property); 
      return false; 
    } 
}; 

用這種方法,似乎只能有一個屬性編輯器

如果您的意思是總數: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 ... 
} 
+0

正如我的問題所述,我使用wxPGEditor,但是,我想有多個按鈕,而不僅僅是一種類型的操作(例如它們是編輯器)。我只是想按下按鈕來調用一個函數,比如wxButton onClick會做的。我已經通過了屬性網格示例,它顯示了您正在談論的內容,但是,這不是我正在尋找的內容。 – mmurphy

+0

這很接近,但是,有兩件事,也許是三件事,阻止它成爲我正在尋找的東西。首先是實際的「按鈕」不顯示,直到你點擊字符串字段。第二個是有一個字符串字段,當我只想要按鈕佔據整個屬性。第三個是用這種方法,似乎只能有一個屬性編輯器。 – mmurphy

+0

@mmurphy我已經更新了我的答案,並且包含了一個替代方法,該方法應該完全符合您的要求(在更新結束時)。但是,這是一個黑客攻擊,我不能保證它不會造成任何問題。 –