您好,参考“PropertyGrid 中的按钮”帖子,该帖子提出了向 wxPropertyGrid 添加按钮的解决方案,我实现了上述代码(在 Linux 和 Windows 下)并且“图形”内容工作正常。虽然,从功能的角度来看,我的行为很奇怪。 在建议的示例中,我实现了一个带有 2 个按钮的 PG。 Button1 (OnClick1) 的事件处理程序切换顶部 wxFrame 类中布尔变量的值。按钮 2 (OnClick2) 的事件处理程序只是 wxLogs 该变量的值。我看到事件处理程序按预期被调用,但不知何故,第二个事件处理程序看不到按钮 1 的事件处理程序所做的更改...出现了问题。有其他人观察到奇怪的行为并可能发现问题吗?
请参阅下面的代码来重现观察到的行为
#include "stdafx.h"
#include "wx/wx.h"
#include <wx/window.h>
#include "wx/propgrid/propgrid.h"
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 //mutable
};
class MyApp : public wxApp
{
public:
virtual bool OnInit();
virtual int OnExit();
};
wxIMPLEMENT_APP(MyApp);
class MyFrame : public wxFrame
{
public:
MyFrame(wxWindow* parent);
private:
void OnClick1(wxCommandEvent& evt);
void OnClick2(wxCommandEvent& evt);
bool mBool;
wxDECLARE_EVENT_TABLE();
};
int MyApp::OnExit()
{
return wxApp::OnExit();
}
bool MyApp::OnInit()
{
if (!wxApp::OnInit())
return false;
wxImage::AddHandler(new wxPNGHandler);
MyFrame* frame = new MyFrame(0L);
frame->Show(true);
return true;
}
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
wxEND_EVENT_TABLE()
MyFrame::MyFrame(wxWindow* parent):
wxFrame(parent, wxID_ANY, " Application"),
mBool(false)
{
wxPropertyGrid* lPG = new wxPropertyGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_SPLITTER_AUTO_CENTER);
lPG->Append(new ButtonProperty(
lPG,
wxCommandEventHandler(MyFrame::OnClick1),
wxString("Click me!")));
lPG->Append(new ButtonProperty(
lPG,
wxCommandEventHandler(MyFrame::OnClick2),
"Edit this!")
);
// Layout stuff
lPG->SetMinSize(wxSize(300, 300));
wxBoxSizer* lGlobalVertSizer = new wxBoxSizer(wxVERTICAL);
lGlobalVertSizer->Add(lPG, 1, wxEXPAND | wxALL, 0);
SetSizerAndFit(lGlobalVertSizer);
// Open the log window and redirect messages to it
wxLogWindow* lLogWindow = new wxLogWindow(this, "Log Messages", false, false);
lLogWindow->GetFrame()->Move(GetPosition().x + GetSize().x + 10,GetPosition().y);
lLogWindow->Show();
}
void MyFrame::OnClick1(wxCommandEvent& evt)
{
mBool = !mBool;
wxLogMessage("OnClick1 mBool status: %s %llx", mBool ? "true": "false", (unsigned long long) & mBool);
}
void MyFrame::OnClick2(wxCommandEvent& evt)
{
wxLogMessage("OnClick2 mBool status: %s %llx", mBool ? "true": "false", (unsigned long long) & mBool);
}
OnClick1 和 OnClick2 报告 mBool 的不同地址和值。
OnClick1 和 OnClick2 必须报告相同的 mBool 值,因为成员变量相同......
wxLogMessage 报告: 11:46:36:OnClick1 mBool 状态:假 1ff29be5fa8 11:46:37:OnClick2 mBool 状态 false 1ff29c739b8 11:46:39:OnClick1 mBool 状态:true 1ff29be5fa8 11:46:40:OnClick2 mBool 状态 false 1ff29c739b8
如果您从未将事件处理程序传递给
func
,则您不可能期望事件处理程序知道要调用 Connect()
的正确对象。您需要显式地将 MyFrame*
传递给它才能正常工作。
更好的是,通过定义函子(可能但不一定使用 lambda)来使代码类型安全,并使用
Bind()
而不是 Connect()
。