PropertyGrid 中的按钮行为不当

问题描述 投票:0回答:1

您好,参考“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

c++ button wxwidgets
1个回答
0
投票

如果您从未将事件处理程序传递给

func
,则您不可能期望事件处理程序知道要调用
Connect()
的正确对象。您需要显式地将
MyFrame*
传递给它才能正常工作。

更好的是,通过定义函子(可能但不一定使用 lambda)来使代码类型安全,并使用

Bind()
而不是
Connect()

© www.soinside.com 2019 - 2024. All rights reserved.