Как показать строки справки для всплывающих меню wxWidgets? - PullRequest
3 голосов
/ 26 апреля 2011

Приложения wxWidgets показывают строки справки для обычных пунктов меню в строке состояния главного окна. К сожалению, он не показывает их для меню, вызванного командой wxWindow::PopupMenu, и мне это нужно.

Я пытался добавить обработчик EVT_MENU_HIGHLIGHT_ALL в родительское окно, но он не вызывается.

Должен быть какой-то способ обработки или перенаправления сообщений для отображения текста справки. Чего мне не хватает?

Ответы [ 2 ]

1 голос
/ 28 апреля 2011

Я пытался вызвать его через wxFrame вместо текущего окна (a wxListCtrl).Это помогло, но не сильно: оно очистило бы строку состояния, когда указатель мыши перемещался над элементом всплывающего меню, но не показывало бы текст справки для него.

Когда я копался в исходном коде wxWidgets, яобнаружил причину: пункты моего всплывающего меню не были в строке меню.wxWidgets отправляет идентификатор пункта меню в строку меню для извлечения текста, что в данном случае явно не получается.

Это заняло некоторое время, но я нашел способ обойти проблему:

////////////////////////////////////////////////////////////////////////////
// In a header file...

class PopupMenu: public wxMenu {
    public: //
    PopupMenu(): mPushed(false) { }

    void OnOpen(wxMenuEvent &evt);
    void OnClose(wxMenuEvent &evt);
    void OnShowMenuHelp(wxMenuEvent &evt);

    private: //
    bool mPushed;

    DECLARE_EVENT_TABLE()
};

////////////////////////////////////////////////////////////////////////////
// In a cpp file...

BEGIN_EVENT_TABLE(PopupMenu, wxMenu)
    EVT_MENU_OPEN(PopupMenu::OnOpen)
    EVT_MENU_CLOSE(PopupMenu::OnClose)
    EVT_MENU_HIGHLIGHT(wxID_ANY, PopupMenu::OnShowMenuHelp)
END_EVENT_TABLE()

void PopupMenu::OnOpen(wxMenuEvent &evt) {
    if (!mPushed) {
        // Clear it
        findStatusBar()->PushStatusText(wxString());
        mPushed = true;
    }
}

void PopupMenu::OnClose(wxMenuEvent &evt) {
    if (mPushed) {
        findStatusBar()->PopStatusText();
        mPushed = false;
    }
}

void PopupMenu::OnShowMenuHelp(wxMenuEvent &evt) {
    if (mPushed) {
        findStatusBar()->SetStatusText(GetHelpString(evt.GetMenuId()));
    } else {
        findStatusBar()->PushStatusText(GetHelpString(evt.GetMenuId()));
        mPushed = true;
    }
}

(findStatusBar - это вспомогательная функция, которая находит рамочное окно программы и вызывает на нем GetStatusBar.)

Теперь я просто извлекаю класс из PopupMenu для всех всплывающих окон, которые мне нужны.Результаты превосходны.

Возможно, есть более простой способ обойти эту проблему, но без размещения элементов всплывающего окна в строке меню я не смог его найти.

0 голосов
/ 03 февраля 2017

Решение Head Geek у меня не сработало для wxWidgets 3.0.2, но я нашел другое: используйте Bind, чтобы временно зарегистрировать обработчик событий wxEVT_MENU_HIGHLIGHT на wxFrame, содержащем элемент управления, по которому щелкнули.Полный пример:

class FunctionMenuWindow : public wxWindow
{
public:
    int option;

    FunctionMenuWindow(wxWindow *parent) : wxWindow(parent, -1), option(0), mPushed(false)
    {
        this      ->Bind(wxEVT_MENU          , &FunctionMenuWindow::OnMenu     , this, wxID_ANY);
        theMainWin->Bind(wxEVT_MENU_OPEN     , &FunctionMenuWindow::OnOpen     , this, wxID_ANY);
        theMainWin->Bind(wxEVT_MENU_CLOSE    , &FunctionMenuWindow::OnClose    , this, wxID_ANY);
        theMainWin->Bind(wxEVT_MENU_HIGHLIGHT, &FunctionMenuWindow::OnHighlight, this, wxID_ANY);
    }

    ~FunctionMenuWindow()
    {
        theMainWin->Unbind(wxEVT_MENU_OPEN     , &FunctionMenuWindow::OnOpen     , this, wxID_ANY);
        theMainWin->Unbind(wxEVT_MENU_CLOSE    , &FunctionMenuWindow::OnClose    , this, wxID_ANY);
        theMainWin->Unbind(wxEVT_MENU_HIGHLIGHT, &FunctionMenuWindow::OnHighlight, this, wxID_ANY);
    }

private:
    void OnMenu(wxCommandEvent& event)
    {
        option = event.GetId();
    }

    void OnOpen(wxMenuEvent &evt)
    {
        this->mMenu = evt.GetMenu();
        if (!mPushed)
        {
            theMainWin->GetStatusBar()->PushStatusText(wxString());
            mPushed = true;
        }
    }

    void OnClose(wxMenuEvent &evt)
    {
        if (mPushed)
        {
            theMainWin->GetStatusBar()->PopStatusText();
            mPushed = false;
        }
    }

    const wxString GetHelpString(wxMenuEvent &evt)
    {
        if (evt.GetMenuId() < 0)
            return wxString();
        else
            return mMenu->GetHelpString(evt.GetMenuId());
    }

    void OnHighlight(wxMenuEvent &evt)
    {
        if (mPushed)
            theMainWin->GetStatusBar()->SetStatusText(GetHelpString(evt));
        else
        {
            theMainWin->GetStatusBar()->PushStatusText(GetHelpString(evt));
            mPushed = true;
        }
    }

    bool mPushed;
    wxMenu* mMenu;
};

///////////////////////////////////////////////////////////////////

void ShowMenu()
{
    FunctionMenuWindow funcWindow(theMainWin);
    wxMenu *menu = new wxMenu;

    // ... set up wxMenu ...

    funcWindow.PopupMenu(menu);

    switch(funcWindow.option)
    {
        // ... switch by wxID as usual ...
    }
}
...