Juri Shutenko Personal Homepage. Visual FoxPro.

Из старого сундучка. Часть 2.

  1. Комбинированные элементы управления
    1. Сплиттер.

Сплиттер. (timestamp not defined)

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

Для построения требуемого элемента управления нужно три простых элемента:

  • Textbox, используемый вместо метки
  • Объект, динамически изменяемого типа связанный с текстбоксом (в зависимости от контекста им может быть текстбокс, комбобокс и т.п.)
  • Shape - накладываемый поверх связанных объектов.

Вариант первый, примитивный.
 
Ограничения: класс помещается в контейнер, с четко заданными параметрами отступа справа и слева от границ. В качестве связанного с текстбоксом-меткой элемента ввода/выбора используется текстбокс. Суммарная ширина связанных элементов равняется ширине контейнера за вычетом отступов. Изначально оба элемента равны по ширине.

Теперь собственно о методе проектирования такого комбинированного элемента. Управляемым элементом является textbox-метка, управляющим элементом является shape и подчиненным - textbox ввода/выбора данных. Откроем новую форму в дизайнере форм и введем в нее перечисленные элементы. Оставляем, пока, названия по умолчанию.

Для начала определимся с элементом shape. Изначально его размер не должен превышать удвоенного значения свойства Margin подчиненного элемента + 2. Это сделано для того, чтобы исключить влияние объекта shape на нормальное поведение textbox'а, в случае, если он используется для ввода значения.
 
C появлением событий MouseEnter и MouseLeave жизнь значительно упростилась. Чтобы было легче "попадать" в диапазон реагирования, в методах, ассоциированных с этими событиями, можно соответственно немного увеличивать/уменьшать ширину объекта Shape. Очевидно, что нужно как-то фиксировать позицию разделительной линии, которая должно проходить через центр объекта Shape и совпадать по координате Х со совмещенными сторонами связанных объектов. Кроме того, нужно учитывать разницу в координатах этой линии, и координаты nXCoord, получаемой методом, ассоциированным с событием MouseDown. Для этого, присвоим нашему объекту Shape два пользовательских свойства - nSplitLine и nDeltaX. Памятуя о повышении точности попадания пользователем в границы реагирования, добавим еще одно свойство nExpOffset. Это можно сделать с помощью метода AddProperty в методе, ассоциированным с событием Init, примерно так, как это приведено ниже:

With This
   .AddProperty("nExpOffset",4)
   .AddProperty("nSplitLine",.Left+.Width/2)
   .AddProperty("nDeltaX",0)
EndWith

Поскольку в новых версиях имеются события MouseEnter/MouseLeave, то в ассоциированных с ними методах будем увеличивать/уменьшать ширину объекта Shape

* code for MouseEnter
With This
   .Width=.Width+.nExpOffset
   .Left=.Left-.nExpOffset/2
EndWith

* code for MouseLeave
With This
   .Width=.Width-.nExpOffset
   .Left=.Left+.nExpOffset/2
EndWith

Осталось определить "неточность" попадания указателем мыши в разделительную линию, за что у нас отвечает свойство nDeltaX. Понятно, что это будет просто разница между значением свойства nSplitLine и значением координаты nXCoord, получаемой методом, ассоциированным с событием MouseDown. Код для этого метода может выглядеть так:

If nButton=1
   With This
      .nDeltaX=.nSplitLine-nXCoord
   Endwith
Endif

Теперь собственно об игре с ширинами связанных объектов. Этим мы займемся в методе MouseMove все того же объекта Shape.

Во-первых, мы должны смешать сам объект Shape, что можно сделать с помощью изменения значения свойства Left. Во-вторых, мы должны переопределять значение введенного нами свойства nSplitLine И, в-третьих, изменять размер связанных элементов управления. Поскольку было оговорено, что суммарный размер связанных элементов постоянен, мы должны его также где-то зафиксировать. В данном примере мы сделаем это в методе, ассоциированным с событием Init формы. Код для этого метода приведен ниже

* код для метода, ассоциированного с событием Init формы
This.AddProperty(;
   "nJoinedWidth",;
   This.Text1.Width+This.Text2.Width;
)

Код для метода, ассоциированого с событием MouseMove объекта shape выглядит следующим образом:

* код для метода, ассоциированного с событием MouseMove объекта shape
If nButton=1
   With This
      .Left=nXCoord+.nDeltaX-.Width/2
      .nSplitLine=.Left+.Width/2
      .Parent.Text1.Width=.nSplitLine-.Parent.Text1.Left
      .Parent.Text2.Left=.Parent.Text1.Width+.Parent.Text1.Left
      .Parent.Text2.Width=.Parent.nJoinedWidth-.Parent.Text1.Width
   Endwith
Endif

И это все! Внизу показан "живой" пример со сплиттером, в котором объект shape имеет гипертрофированные размеры, а значение свойства BorderStyle установлено в 1, тогда как в реальном приложении это значение должно быть равно нулю - 0.

Будет продолжено...





Cелектор для быстрого перехода на сайты, связанные с Visual FoxPro.