关闭弹出窗口并设置按钮标签

Closing Popup and setting button label

我正在编写一个 C++ wxWidgets 计算器应用程序。我想将三角函数按钮压缩成一个按钮以节省 space,使用的基本上是一个拆分按钮。如果您左键单击它,将使用当前选项。如果右键单击,将打开一个弹出菜单,其中包含所有按钮;当您单击其中之一时,它会被使用并且大按钮会发生变化。

我被建议使用 wxComboBox 和其他东西来完成这项工作,但我更喜欢使用 wxPopupTransientWindow,因为这样我可以在网格中显示按钮,使一切 - 在我看来 - 更整洁。

问题是,当我从菜单中选择一个选项时,主按钮的 ID 发生了变化(因为当我重新打开菜单时,之前单击的按钮会亮起,因为它的 ID 和大按钮的 ID 匹配),但是标签才不是。此外,当您左键单击其中一个按钮时,弹出窗口应该会自行关闭,但事实并非如此。

这是弹出窗口中自定义按钮的代码,它应该执行所有这些操作:

void expandButton::mouseReleased(wxMouseEvent& evt)
{
    if (pressed) {
        pressed = false;
        paintNow();

        wxWindow* mBtn = this->GetParent()->GetParent();
        mBtn->SetLabel(this->GetLabel());
        mBtn->SetId(this->GetId());

        this->GetParent()->Close(true);
    }
}

这是主框架中用于打开弹出窗口的自定义按钮的代码(临时设置只是为了测试整个功能是否正常工作):

void ikeButton::rightClick(wxMouseEvent& evt) // CREA PANNELLO ESTENSIONE
{
    if (flags & EXPANDABLE)
    {
        std::vector<expandMenuInfo> buttons;
        buttons.push_back(expandMenuInfo(L"sin", 3001));
        buttons.push_back(expandMenuInfo(L"cos", 3002));
        buttons.push_back(expandMenuInfo(L"tan", 3003));
        buttons.push_back(expandMenuInfo(L"arcsin", 3004));
        buttons.push_back(expandMenuInfo(L"arccos", 3005));
        buttons.push_back(expandMenuInfo(L"arctan", 3006));

        wxPoint p = this->GetScreenPosition();
        size_t sz = this->GetSize().GetHeight() / 1.15;

        expandMenu* menu = new expandMenu(this, buttons, sz, wxPoint(
                p.x, p.y + this->GetSize().GetHeight() + 2));
        menu->SetPosition(wxPoint(
            menu->GetPosition().x - ((menu->GetSize().GetWidth() - this->GetSize().GetWidth()) / 2),
            menu->GetPosition().y));
        menu->Popup();
    }
}

如果我需要显示更多代码,请告诉我。 这可能是一种糟糕的做法,但这基本上是我使用 wxWidgets 框架创建的第一个“严肃”应用程序。感谢任何帮助。

when I choose an option from the menu, the main button's ID changes (because when I reopen the menu the previously clicked button is light up as its ID and the big button's ID match), but the label does not.

如果您像在之前的 post 中那样创建弹出菜单,您有一个弹出菜单 window,其中一个面板作为其子项,然后按钮是面板的子项一个 sizer.

如果仍然如此,this->GetParent() 应该是面板,this->GetParent()->GetParent() 应该是弹出窗口。所以 this->GetParent()->GetParent()->GetParent() 应该是触发功能按钮(假设您使用触发功能按钮作为父级创建了弹出窗口)。

所以我认为 wxWindow* mBtn = this->GetParent()->GetParent(); 行应该改为 wxWindow* mBtn = this->GetParent()->GetParent()->GetParent();

或稍短wxWindow* mBtn = this->GetGrandParent()->GetParent();;


the popup is supposed to close itself when you left click on one of the buttons, but it does not.

看起来 wxPopupTransientWindow 有一个特殊的 Dismiss 方法可以用来关闭它。

所以我认为行 this->GetParent()->Close(true); 应该更改为 this->GetGrandParent()->Dismiss();(假设弹出窗口中的按钮是面板的子按钮)。


或者,如果您想要一个解决方案,无论弹出窗口中控件的出身如何,都可以工作window,您可以使用一个实用函数来查找弹出窗口的祖先,它看起来像这样:

wxPopupTransientWindow* FindPopup(wxWindow* w)
{
    wxPopupTransientWindow* popup = NULL;

    while ( w != NULL )
    {
        popup = wxDynamicCast(w, wxPopupTransientWindow);

        if ( popup )
        {
            break;
        }

        w = w->GetParent();
    }

    return popup;
}

这使用了 wxDynamicCast 函数,它与 c++ dynamic_cast 表达式略有不同。 wxDynamicCast 使用 wxWidgets 的 RTTI 系统检查给定的指针是否可以转换为给定的类型。

然后 mouseReleased 方法可以像这样使用这个实用函数:

void expandButton::mouseReleased(wxMouseEvent& evt)
{
    if (pressed) {
        pressed = false;
        paintNow();

        wxPopupTransientWindow* popup = FindPopup(this);
        if (popup ) {
            wxWindow* mBtn = popup->GetParent();
            mBtn->SetLabel(this->GetLabel());
            mBtn->SetId(this->GetId());
            mBtn->Refresh();

            popup->Dismiss();
        }
    }
}

我不确定您为什么要将触发功能按钮设置为具有新 ID,但我认为您是有原因的。


要使 SetLabel 方法在您的自定义按钮 class 中工作,我认为最简单的方法是在按钮的构造函数中调用 SetLabel() 方法。这会将传递给构造函数的字符串存储在按钮的内部标签成员中。

基于其他问题,我认为 ikeButton 构造函数看起来像这样:

ikeButton::ikeButton(wxFrame* parent, wxWindowID id, wxString text,...
{
...
    this->text = text;

要存储标签,您需要将行 this->text = text; 更改为

    SetLabel(text);

而当您绘制按钮时,我认为您使用的方法如下所示:

void ikeButton::render(wxDC& dc)
{
   ...
    dc.DrawText(text, ...);
}

您需要将 dc.DrawText(text, ...); 行更改为

    dc.DrawText(GetLabel(), ...);

同样,对按钮的 text 成员的任何其他引用都应更改为 GetLabel()

最后,当您在 expandButton::mouseReleased 方法中设置标签时,调用按钮的 Refresh() 方法强制按钮重绘自身可能是个好主意。我在上面添加了我对 mouseReleased 方法的建议。