Вывод popup-меню под кнопкой

Коротенькая статья о выводе контекстного меню

  • Автор: Still Zero
  • Уровень знаний: начальный
  • Подразделы: нет
  • Дата публикации: 27.05.2005

Задача: создать всплывающее (контекстное, popup) меню, вызвать его при нажатии на кнопку, показать меню прямо под кнопкой.
Зачем именно под кнопкой: … так красивее 🙂

Создание меню
В ABC-шаблонах существует класс PopupClass, который предназначен для создания контекстного меню. Подробнее о нем вы можете прочитать в стандартной документации. Описание класса и его код находятся в файлах abpopup.inc, abpopup.clw в каталоге LIBSRC.

Из недокументированного:

  • метод SetIcon служит для установки пункту меню иконки, прототип метода:
SetIcon               PROCEDURE(STRING Name, STRING IconName) ! Name - метка пункта меню
  • при добавлении пункта меню вы можете использовать свойства шрифта, например, Prop:FontStyle, это может понадобиться если вы захотите сделать текст пункта меню, например, наклонным.
PopupRefers  PopupClass                        ! объявление объекта класса
 code
 PopupRefers.Init()                            ! инициализация
 PopupRefers.AddItem('Справочник #1','Refer1') ! добавление пунктов меню
 PopupRefers.AddItem('Справочник #2','Refer2')
 PopupRefers.AddItem('Справочник #3','Refer3')
 PopupRefers.AddItem('Справочник #4','Refer4')
 PopupRefers.AddItem('Справочник #5','Refer5')
 PopupRefers.AddItem('['&PROP:FontStyle&'(700)]Справочник #6','Refer6') !"толстый" шрифт
 ...
 PopupRefers.Kill()                            ! завершим работу класса

Вывод меню
Для того чтобы показать меню используется метод PopupClass с именем Ask. Метод принимает два необязательных параметра: координаты, в которых будет показано меню. Соответственно, все что необходимо для вывода, это выполнить метод Ask, передав в него координаты нижнего левого угла кнопки.
Для определения координат будем использовать API-функцию GetWindowRect, которая определяет координаты окна. Окном в нашем случае будет выступать кнопка.

По большому счету, наверное, можно обойтись и без API. Можно использовать свойства кнопки Prop:Xpos, Prop:Ypos+Prop:Heigth. Правда в этом случае, придется переключаться в MyWindow{Prop:Pixel}=TRUE, а потом обратно. Использование GetWindowRect избавляет вас о необходимости думать о DLU и пикселах, и, по моему мнению, более универсально.

Прототип GetWindowRect:

GetWindowRect(ULONG hWnd,LONG lpRect),BOOL,PASCAL

hWnd — хэндл окна, для которого необходимо определить координаты, в нашем случае это будет примерно так: ?MyButton{Prop:Handle}
lpRect — адрес на структуру Rect, в Кларионе это группа следующего вида:

Rect    GROUP
Left       LONG
Top        LONG
Right      LONG
Bottom     LONG
        END
где Left, Top, Right, Bottom соответствующие координаты

Таким образом код для вывода меню будем выглядеть следующим образом:

loc:Rect GROUP          ! группа координат окна
rLeft       LONG
rTop        LONG
rRight      LONG
rBottom     LONG
         END
SelectedItem STRING(20) ! выбранный пункт меню

 сode
 ...
 if GetWindowRect(?Button1{Prop:Handle},address(loc:Rect))        ! узнать координаты кнопки
    SelectedItem=PopupRefers.Ask(loc:Rect.rLeft,loc:Rect.rBottom) ! если все ОК, то выводим меню
 end

Известные проблемы
Кларион сам определяет с каким выравниванием показывать popup-меню. По умолчанию меню показывается «справа и вниз» от курсора мыши. Если ваше окно будет расположено слишком близко к правому краю десктопа, то меню будет показано слева от курсора мыши, так как при выводе «вправо» его не будет видно. По этой же причине меню может быть показано «вверх» от курсора мыши. Когда вы жестко фиксируете координаты вывода меню и возникает ситуация отличная от выравнивания «справа-вниз», то вся «красота» рушится 🙂
Я решил не обращать внимание на эту проблему, так как случаи ее возникновения достаточно редки, но это минус. По хорошему, я думаю, необходимо определять размер десктопа, используя API GetClientRect и GetDesktopWindow и в зависимости от координат кнопки и предполагаемого размера меню обрабатывать такие ситуации.

Пример выполнен на C55H, ABC

Popup Button (1077)
© Project Zero, 2005-2006. Все права защищены.