Introduction
Код для контекстного меню win32. Цепляются на кнопку и позволяют значительно расширить функционал кнопки без дополнительно вводимых визуальных элементов на канву.
Полезный код для меня по той причине, что такого рода контекстными менюшками я пользуюсь довольно часто.
Details
Имеется два класса
MenuHandle - класс для заполнения менюшки пунктами и обработки их нажатия.
Имеет две виртуальные функции ItemCollect, ItemPress. Их следует переопределить чтобы заполнять меню пунктами и затем обрабатывать выбор пользователя.
ToolMenu - класс от FBComponent, который реализует кнопку и появляющееся по нажатию контекстное меню
Методы для работы с меню
| GetControl | полезен для установки кнопки на форму, для того чтобы присоединить к требуемому региону |
| SetHandle | задать обработкик пунктов меню (наполнение и нажатие). Обработчиков может быть сколько угодно, можно разными способами и с разным назначением выполнять заполнение пунктов меню |
| Show | показать контекстное меню под курсором мыши |
| Title | свойство для задания заголовка меню |
Пример использования
Чтобы именовать пункты меню в полу-автоматическом режиме я сделал следующую уловку, используя вложение хедера
MainMenuItems.h
// edit menu
#ifdef EDITCLASS
EDITCLASS(Undo, MF_STRING, "Undo")
EDITCLASS(Redo, MF_STRING, "Redo")
EDITCLASS(Sep1, MF_SEPARATOR, "")
EDITCLASS(ImpOpt, MF_STRING, "Import from FBOptical")
EDITCLASS(ExpOpt, MF_STRING, "Export to FBOptical")
EDITCLASS(Sep2, MF_SEPARATOR, "")
EDITCLASS(SelectAll, MF_STRING, "Select All")
EDITCLASS(SelectInvert, MF_STRING, "Select Invert")
EDITCLASS(SelectNone, MF_STRING, "Select None")
EDITCLASS(Sep3, MF_SEPARATOR, "")
EDITCLASS(FilterGaps, MF_STRING, "Filter Gaps")
EDITCLASS(FilterSegments, MF_STRING, "Filter Segments")
EDITCLASS(Sep4, MF_SEPARATOR, "")
EDITCLASS(DisplayDebug, MF_STRING, "Display debug drawings")
#endif
// menu segments
#ifdef SEGCLASS
SEGCLASS(Pick, MF_STRING, "Pick")
SEGCLASS(Trackable, MF_STRING, "Trackable")
SEGCLASS(Paste, MF_STRING, "Assign data from FBOpticalMarker")
SEGCLASS(Merge, MF_STRING, "Merge")
SEGCLASS(CutLeft, MF_STRING, "Cut Left")
SEGCLASS(CutRight, MF_STRING, "Cut Right")
SEGCLASS(Remove, MF_STRING, "Remove")
#endif
Файл MainMenu.h
enum
{
#define EDITCLASS(menuName, menuType, menuText) MENU_##menuName,
#include "MainMenuItems.h"
#undef EDITCLASS
MENU_SEG_START,
#define SEGCLASS(menuName, menuType, menuText) MENU_##menuName,
#include "MainMenuItems.h"
#undef SEGCLASS
};
class EditHandle : public MenuHandle
{
public:
EditHandle()
{
MenuItem item;
#define EDITCLASS(menuName, menuType, menuText) item.id = (int)MENU_##menuName; \
item.type = menuType; sprintf(item.text, ""##menuText); \
mItems.Add(item);
#include "MainMenuItems.h"
#undef EDITCLASS
mItems[MENU_FilterGaps].state = true;
mItems[MENU_FilterSegments].state = true;
}
int ItemPress(int item)
{
return 1;
}
MenuItem *ItemCollect(int *count)
{
CEPointsCloudSettings &settings = CESystem::instance().OpticalSettings;
mItems[MENU_DisplayDebug].state = settings.DisplayDebug;
*count = mItems.GetCount();
return mItems.GetArray();
}
private:
FBArrayTemplate <MenuItem> mItems;
};Таким образом я определяю локальный массив mItems для класс управления и заполняю его данными из файла MainMenuItems в соотвествии с заполненными там пунктами. В ItemsCollect я обновляю положение переключателей (checkboxes) и возвращаю количество элементов и указатель на массив данных. В ItemPress можно обрабатывать нажатие того или иного пункта.
Example
Для примера возьмем меню для выбора некоторого типа.
mainmenuitem.h
//menu gap
#ifdef GAPCLASS
GAPCLASS(Linear, MF_STRING, "Linear")
GAPCLASS(Smooth, MF_STRING, "Smooth")
#endif
MainMenu.h
class GapHandle : public MenuHandle
{
public:
GapHandle()
{
MenuItem item;
#define GAPCLASS(menuName, menuType, menuText) item.id = (int)MENU_##menuName; \
item.type = menuType; sprintf(item.text, ""##menuText); \
mItems.Add(item);
#include "MainMenuItems.h"
#undef GAPCLASS
mItems[MENU_Linear - MENU_GAP_START-1].state = true;
}
int ItemPress(int item)
{
// do some action here
return 1;
}
MenuItem *ItemCollect(int *count)
{
*count = mItems.GetCount();
return mItems.GetArray();
}
private:
FBArrayTemplate <MenuItem> mItems;
};tool.h
GapHandle gaphandle;
tool.cpp
mGapMenu.SetTitle( ORTOOLTEMPLATE__LABEL );
mGapMenu.SetHandle( &gaphandle );
layout.SetControl( "ButtonGap", mGapMenu.GetControl() );
mGapMenu.GetControl().Caption = "Gap >";