Есть ли способ использовать обычные символы ASCII (например, запятую) в качестве ускорителей меню wxWidgets? - PullRequest
0 голосов
/ 08 ноября 2011

Я хочу несколько пунктов меню, которые показывают ускорители, которые являются обычными клавишами, такими как клавиша пробела или запятая, но я не хочу, чтобы wxWidgets сам создавал эти ускорители (потому что тогда они могут ' не может использоваться в любом месте в программе, включая такие элементы, как поля ввода).

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

Я ищу какой-либо способ поместить произвольный текст в столбец ускорителя (который, я думаю, не существует, я посмотрел на исходный код), или получить таблицу ускорителя, используемую для меню. так что я могу изменить его сам (пока не нашел). Кто-нибудь может указать мне правильное направление?

Ответы [ 2 ]

1 голос
/ 10 ноября 2011

Я не смог найти способ прямого доступа к клавишам меню, но изменение текста меню акселератора также работает. Вот код, который я придумал:

В заголовочном файле:

class accel_t {
    public:
    // If idcount == -1, idlist must be null or terminated with a -1 entry.
    accel_t(): mMenu(0) { }
    accel_t(wxMenuBar *m, int *idlist = 0, int idcount = -1);
    void reset(wxMenuBar *m, int *idlist = 0, int idcount = -1);
    void restore() const;
    void remove() const;

    private: //
    struct accelitem_t {
        accelitem_t(int _id, wxAcceleratorEntry _key): id(_id), hotkey(_key) { }
        int id;
        wxAcceleratorEntry hotkey;
    };
    typedef std::vector<accelitem_t> data_t;

    void noteProblemMenuItems(wxMenu *m);
    static bool isProblemAccelerator(wxAcceleratorEntry *a);

    wxMenuBar *mMenu;
    data_t mData;
};

В файле cpp:

accel_t::accel_t(wxMenuBar *m, int *idlist, int idcount) {
    reset(m, idlist, idcount);
}

void accel_t::reset(wxMenuBar *m, int *idlist, int idcount) {
    mMenu = m;
    mData.clear();
    if (idlist == 0) {
        for (int i = 0, ie = m->GetMenuCount(); i != ie; ++i)
            noteProblemMenuItems(m->GetMenu(i));
    } else {
        if (idcount < 0) {
            int *i = idlist;
            while (*i != -1) ++i;
            idcount = (i - idlist);
        }

        for (int *i = idlist, *ie = i + idcount; i != ie; ++i) {
            wxMenuItem *item = mMenu->FindItem(*i);
            if (item) {
                wxAcceleratorEntry *a = item->GetAccel();
                if (a != 0) mData.push_back(accelitem_t(*i, *a));
            }
        }
    }
}

bool accel_t::isProblemAccelerator(wxAcceleratorEntry *a) {
    if (a == 0) return false;
    int flags = a->GetFlags(), keycode = a->GetKeyCode();

    // Normal ASCII characters, when used with no modifier or Shift-only, would
    // interfere with editing.
    if ((flags == wxACCEL_NORMAL || flags == wxACCEL_SHIFT) &&
        (keycode >= 32 && keycode < 127)) return true;

    // Certain other values, when used as normal accelerators, could cause
    // problems too.
    if (flags == wxACCEL_NORMAL) {
        if (keycode == WXK_RETURN ||
            keycode == WXK_DELETE ||
            keycode == WXK_BACK) return true;
    }

    return false;
}

void accel_t::noteProblemMenuItems(wxMenu *m) {
    // Problem menu items have hotkeys that are ASCII characters with normal or
    // shift-only modifiers.
    for (size_t i = 0, ie = m->GetMenuItemCount(); i != ie; ++i) {
        wxMenuItem *item = m->FindItemByPosition(i);
        if (item->IsSubMenu())
            noteProblemMenuItems(item->GetSubMenu());
        else {
            wxAcceleratorEntry *a = item->GetAccel();
            if (isProblemAccelerator(a))
                mData.push_back(accelitem_t(item->GetId(), *a));
        }
    }
}

void accel_t::restore() const {
    if (mMenu == 0) return;
    for (data_t::const_iterator i = mData.begin(), ie = mData.end(); i != ie;
        ++i)
    {
        wxMenuItem *item = mMenu->FindItem(i->id);
        if (item) {
            wxString text = item->GetItemLabel().BeforeFirst(wxT('\t'));
            wxString hotkey = i->hotkey.ToString();
            if (hotkey.empty()) {
                // The wxWidgets authors apparently don't expect ASCII
                // characters to be used for accelerators, because
                // wxAcceleratorEntry::ToString just returns an empty string for
                // them. This code deals with that.
                int flags = i->hotkey.GetFlags(), key = i->hotkey.GetKeyCode();
                if (flags == wxACCEL_SHIFT) hotkey = wx("Shift-") + wxChar(key);
                else hotkey = wxChar(key);
            }
            item->SetItemLabel(text + '\t' + hotkey);
        }
    }
}

void accel_t::remove() const {
    if (mMenu == 0) return;
    for (data_t::const_iterator i = mData.begin(), ie = mData.end(); i != ie;
        ++i)
    {
        wxMenuItem *item = mMenu->FindItem(i->id);
        if (item) {
            wxString text = item->GetItemLabel().BeforeFirst(wxT('\t'));
            item->SetItemLabel(text);
        }
    }
}

Самый простой способ его использования - создать панель меню как обычно, со всеми клавишами ускорения (включая проблемные), а затем создать из нее элемент accel_t примерно так:

// mProblemAccelerators is an accel_t item in the private part of my frame class.
// This code is in the frame class's constructor.
wxMenuBar *menubar = _createMenuBar();
SetMenuBar(menubar);
mProblemAccelerators.reset(menubar);

Он будет определять и записывать клавиши-акселераторы, которые создают проблемы. Наконец, при необходимости вызовите функции remove и restore, чтобы удалить или восстановить проблемные клавиши ускорения. Я вызываю их с помощью сообщений, передаваемых во фрейм всякий раз, когда открываю окно, в котором требуется стандартное редактирование.

1 голос
/ 09 ноября 2011

Вы можете попробовать wxKeyBinder . Позволяет привязывать горячие клавиши к командам (обычно пунктам меню), сохранять / загружать / добавлять / удалять / изменять ... их легко

...