Кратко о отрисовке иконок в заголовке лист-бокса.
Как известно, в Кларионе не предусмотрен стандартный вывод иконок в заголовки колонок лист-бокса. В этой статье я расскажу вам о том, каким образом
можно обойти это ограничение.
Идея достаточно проста. Если рассмотреть заголовок как таковой, то он похож на обычную кнопку.
![]()
На стандартной кнопке мы легко можем показать иконку. Более того мы можем отцентрировать иконку по правому/левому краю или по центру. Таким образом, наложив стандартную кнопку на заголовок колонки мы добьемся желаемого результата. Поэтому все что нужно, это знать координаты заголовка.
Создание кнопки
В Кларионе есть возможность создания контролов «на лету». Для этого используется оператор CREATE. Команда создает контрол. Атрибуты контрола (текст, размеры, иконка и т.д.) задаются через соответствующие свойства. Создание кнопки выглядит примерно так:
ButtonFEQ LONG ! переменная, которая будет использована для идентификации кнопки
code
ButtonFEQ=CREATE(0,CREATE:Button) ! создаем кнопку
ButtonFEQ{Prop:Icon}=clip(ImageName) ! присваиваем какую-нибудь картинку
ButtonFEQ{Prop:Flat}=TRUE ! кнопка будет плоской
ButtonFEQ{Prop:Skip}=TRUE ! пропускать кнопку при переходе по TAB
ButtonFEQ{Prop:Trn}=TRUE ! прозрачная кнопка
ButtonFEQ{Prop:Left}=TRUE ! выравнивание влево, на кнопке ничего не будет написано
ButtonFEQ{Prop:Text}='' ! строка нужна для правильного выравнивания
ButtonFEQ{Prop:Xpos}=10 ! задание размеров кнопки
ButtonFEQ{Prop:Ypos}=10
ButtonFEQ{Prop:Width}=20
ButtonFEQ{Prop:Height}=10
unhide(ButtonFEQ) ! показать вновь созданную кнопку
Определение координат
Определение координат, это чистой воды лирика. Нет ничего сложного, используются известные свойства лист-бокса … и эмпирические наблюдения, на которые было потрачено каких-то полных 3 дня 🙂
Таблица: Свойства лист-бокса Свойство Описание
- Prop:Xposx координата лист-бокса
- Prop:Yposy координата лист-бокса
- Prop:Widthширина лист-бокса
- Prop:HeaderHeightвысота заголовка
- Prop:HScrollPosзначение горизонтального скролл бара
- Proplist:Width, ColumnNumширина колонки ColumnNumProplist:Exists, ColumnNumвозвращает TRUE, если колонка существует, в противном случае FALSE
- Proplist:HeaderLeft, ColumnNumвозвращает TRUE, если текст колонки выравнивается по левому краю
- Proplist:HeaderRight, ColumnNumвозвращает TRUE, если текст колонки выравнивается по правому краю
- Proplist:HeaderCenter, ColumnNumвозвращает TRUE, если текст колонки выравнивается по центру
- Proplist:HeaderLeftOffset, ColumnNumотступ текста колонки слева
- Proplist:HeaderRightOffset, ColumnNumотступ текста колонки справа
- Proplist:HeaderCenterOffset, ColumnNumотступ текста колонки по центру — не работает
- Proplist:MouseDownRowномер строки, на которой нажали кнопку мыши, 0 если нажали на заголовке колонки
- Proplist:MouseDownZoneзона, в которой нажали кнопку мыши, LISTZONE:Header если нажали на заголовке колонки
- Proplist:MouseDownFieldномер колонки, на которой нажали кнопку мыши
- Proplist:GroupNo, ColumnNumвозвращает номер группы, если колонка входит в группу, если не входит возвращает номер колонки
- Proplist:GroupNo+Proplist:Group, ColumnNumвозвращает количество колонок в группе, если колонка входит в группу, если не входит возвращает ноль
- Proplist:Width+Proplist:Group, ColumnNumвозвращает ширину группы, в которую входит указанная колонка
Это далеко не полный перечень свойств лист-бокса.
Известные проблемы
Свойство Proplist:Width,ColumnNum не всегда возвращает корректную ширину колонки. Это происходит в случае если колонка является последней колонкой в лист-боксе или в группе.
Если колонка является последней колонкой в листе: ширина определяется как разница между всей шириной лист-бокса и шириной всех видимых колонок левее искомой. Если колонка является последней колонкой в группе — как разница между шириной группы и шириной всех колонок в группе левее искомой.
Свойство Prop:HScrollPos. Возвращает значение горизонтального скролл-бара. Это значение изменяется от 0 до N, где N = (количества колонок в листе) — 1.
Немного расшифрую: допустим у вас есть 4 (четыре) колонки в листе. Следовательно свойство Prop:HScrollPos может принимать значения 0, 1, 2, 3. Когда горизонт. скролл бар установлен в крайнее левое положение свойство Prop:HScrollPos=0, в крайнее правое Prop:HScrollPos=3. Т.е. это свойство как бы говорит — сколько колонок спрятано, не видно, находится левее первой видимой колонки в листе.
Это свойство работает хорошо … пока не появляются группы колонок. При наличии групп свойство изменяется до M, где M = (количество колонок без групп) + (количество групп) — 1.
Вертикальный скролл-бар. Вертикальный скролл-бар может присутствовать или отсутствовать в лист-боксе. Также ширина скролл-бара зависит от настроек Windows. Я не нашел стандартной возможности Клариона определить эти параметры. Существуют две API функции: GetSystemMetrics(SM_CXVSCROLL) — возвращает ширину скролл-бара, GetScrollInfo — помогает определить видимость скролл-бара.
Точность измерения размеров. Все измерения желательно проводить в пикселях. Для этого для окна необходимо установить свойство MyWindow{Prop:Pixels}=TRUE. Не забудьте восстановить это свойство в первоначальное значение после всех измерений.
Я измеряю x-координату путем суммирования ширины всех колонок левее искомой. При таком способе необходимо помнить о наличии разделительной линии Proplist:RightBorder,ColumnNum шириной в 1 пиксель.
При измерении высоты заголовка колонки и y-координаты необходимо помнить о возможности группирования колонок.
Перерисовка кнопок
После того как вы создали кнопку и наложили ее на заголовок лист-бокса попробуйте изменить размеры колонки. Вы увидите, что кнопка останется на месте, т.е. не переместится и не изменит своих размеров вместе с колонкой. Если вы переместите ползунки вертикального или горизонтального скролл-бара, то кнопка вообще исчезнет. «Исчезновение» произойдет также и при изменении размеров лист-бокса. Раз так, следует учесть этот момент и при возникновении таких событий перерисовывать кнопки (опять узнать размеры заголовков колонки и присвоить их свойствам кнопки).
Для учета изменения размеров колонок, можно использовать событие EVENT:ColumnResize. Например, так:
REGISTER(EVENT:ColumnResize,address(self.Redraw),address(SELF),,self.ListBoxFEQ)
эта строка говорит о том, что при возникновении события EVENT:ColumnResize в контроле self.ListBoxFEQ (лист-бокс) будет вызван метод self.Redraw (перерисовать кнопки). Возможно вы уже подумали, что для обработки изменения размеров лист-бокса необходимо использовать событие Event:Sized. Неа…нельзя 🙂 Потому что при обработке события Event:Sized Кларионом system is modal, а это означает, что пока идет обработка этого сообщения вы ничего не можете сделать с контролами. Если не можем напрямую обработать событие, то это можно сделать через сабклассинг. Я отлавливаю сообщения WM_HSCROLL/WM_VSCROLL (перемещение ползунка горизонт/вертик. скролл-баров ), WM_SIZE (изменение размеров) и посылаю свое собственное событие EVENT:Redraw лист-боксу.
А для этого события, также выполнен код:
REGISTER(EVENT:Redraw,address(self.Redraw),address(SELF),,self.ListBoxFEQ)
пока происходит этот несколько «хитрый» обмен сообщениями system перестает быть modal 🙂 и вы сможете изменить размеры ваших кнопок так как вам нужно. Следует помнить, что может возникнуть ситуация, что заголовка колонки, на котором вы хотите отрисовать кнопку, не видно на экране.
В этом случае ранее отрисованную кнопку необходимо скрывать, используя свойство Prop:Hide или совсем уничтожать, используя команду DESTROY.
Эмуляция нажатия кнопки мыши на заголовке
Здесь тоже все просто. Опять используем сабклассинг и отлавливаем события WM_LBUTTONDOWN — нажатие левой кнопки мыши, WM_LBUTTONUP — отпускание левой кнопки мыши.
Используя свойства Proplist:MouseDownField, Proplist:MouseDownRow, Proplist:MouseDownZone убеждаемся, что нажали именно на заголовке, и узнаем номер колонки.
По нажатию кнопки создаем на заголовке контрол Region. Эффект нажатия создается за счет выставления атрибута ?Region{Prop:Bevel,1}=-1. По отпусканию кнопки регион уничтожается.

Код
Эта статья сможет вам помочь понять и разобраться в коде класса, который позволит вам отрисовывать иконки в заголовке лист-бокса и отлавливать момент нажатия кнопок мыши. Переопределив виртуальные методы, вы сможете задать свое поведение при нажатии на заголовок: это может быть сортировка колонок; реверсная сортировка; вы можете обработать нажатие клавиш Ctrl и Shift вместе с кнопкой мыши для создания множественной сортировки и т.д.
Код выполнен на C55H, ABC, на Legacy-шаблонах не проверялся.
© Still Zero, 2005-2006. Все права защищены.
