Создание классов в Конструкторе классов

В главе 5 вы познакомились с объектами — управляющими элементами, создаваемыми на основе базовых классов Visual FoxPro. Рассматриваемые в этом разделе классы Container и Control позволяют создавать новые визуальные управляющие элементы, которые вы так же можете использовать в своих приложениях наряду с базовыми.

Создание класса на основе базового класса Visual FoxPro

При конструировании формы в Конструкторе форм вам постоянно приходится изменять свойства размещаемых на ней управляющих элементов, например, тип шрифта и высоту символов в текстовом блоке TextBox. Если вы применяете этот элемент с несколькими изменёнными реквизитами достаточно часто, то это приводит к необходимости многократной однотипной настройки его свойств при каждом очередном размещении элемента на форме. Но можно поступить иначе: создать пользовательский класс на базе класса TextBox, установить в нём необходимые значения свойств, и затем использовать этот класс во всех (или многих) разрабатываемых формах. Конструктор классов предоставляет вам возможность, которая не была реализована в Конструкторе форм —включение новых свойств и методов в управляющий элемент на этапе разработки класса этого элемента.
Добавьте в библиотеку классов новый класс, в качестве родительского выберите класс TextBox, для чего в Менеджере проектов выделите любой узел с именем класса, включенного в библиотеку, и нажмите на кнопку New. В появившемся окне New Class в поле Class Name введите MyTextBox, в списке Base On выберите TextBox. Нажмите кнопку OK. Загрузится Конструктор классов, в окне которого вы увидите окно MyTextBox (согласитесь, непривычно видеть управляющий элемент со стандартным оконным заголовком!)

Рис. 11.8. Класс MyTextBox в окне Конструктора классов

Все ваши следующие действия — это установка новых значений свойств элемента в окне Свойств.
После того, как вы сохраните этот новый класс в библиотеке классов, в окне Менеджера проектов будет создан новый узел (рис. 11.9).

Рис. 11.9. Окно Менеджера проектов после добавления класса MyTextBox

Давайте ужесточим предъявляемые требования к функциональности класса MyTextBox. Мы добавим в класс новое свойство, которое позволит узнавать, изменялось ли содержимое текстового поля. Назовём это свойство lChange.
В Менеджере проектов выделите узел mytextbox и нажмите кнопку Modify. Загрузится Конструктор классов. Выберите в меню Class пункт New Property. Конструктор выведет окно New Property для добавления в класс нового свойства (рис. 11.10).

Рис. 11.10. Окно New Property

Это окно отличается от аналогичного окна Конструктора форм только наличием поля Visibility. В этом поле вы определяете уровень видимости добавляемого свойства:

  • Public — свойство доступно из вне класса объекта.

  • Protected — свойство доступно только из методов класса; оно недоступно как из вне класса, так и вложенным в класс-контейнер объектам. Свойство доступно при наследовании (доступно из методов дочерних классов).

  • Hidden — свойство доступно только из методов класса; оно недоступно как из вне класса, так и вложенным в класс-контейнер объектам. Свойство недоступно для классов-наследников.

Как и в Конструкторе форм, вы можете связать со свойством методы Access и Assign.
Введите в поле Name имя создаваемого свойства (lChange) и определите для него уровень видимости Public. Значение свойства по умолчанию оставьте без изменения. Нажмите кнопку Add для добавления свойства в класс и закройте окно.
В окне Свойств выберите строку InteractiveChange и, дважды щёлкнув по ней мышью, перейдите в режим редактирования этого метода. Введите в метод следующий код:

 
 this.lChange = .T.
 

Событие InteractiveChange происходит при каждом изменении значения поля объекта TextBox — вводите ли вы символ с клавиатуры или удаляете выделенный мышью фрагмент текста при помощи меню. Факт возникновения этого события и будет фиксироваться в свойстве lChange.
В метод GotFocus класса добавьте следующий код:

 
 this.lChange = .F.
 

Теперь при каждом очередном получении элементом фокуса ввода значение свойства будет сбрасываться, и, если пользователь ничего не введёт, то свойство так и сохранит значение «ложь».

Вот и всё. После размещения объекта — экземпляра класса MyTextBox на форме в его методе LostFocus напишите код проверки значения свойства lChange:

 
 IF this.lChange
    Выполняемый_код
 ENDIF
 

Класс Container

Если в Конструкторе форм вы могли использовать управляющий элемент Container только для «наведения красоты», то есть как обычный визуальный оформительский компонент. В Конструкторе классов вы можете создать на базе этого класса настоящий контейнер, напоминающий классы-контейнеры Command Group или Option Group, и разместить на нём различные управляющие элементы.
Добавьте в библиотеку классов новый класс с именем MyContainer и выберите для него базовый класс Container. На рис. 11.11 показано окно Конструктора классов с загруженным окном класса Container.

Рис.11.11. Редактирование класса MyContainer

Точно так же, как вы размещали управляющие элементы на форме в Конструкторе форм, разместите в окне mycontainer четыре кнопки, метку и один ComboBox. Придайте окну вид, показанный на рис. 11.12.

Рис. 11.12. Класс MyContainer с добавленными управляющими элементами

Получилось нечто похожее на панель инструментов, не так ли? Не хватает только пиктограмм на кнопках (вместо надписей). Теперь осталось разместить созданный компонент на форме и убедиться, что он действительно ведёт себя как контейнер.

Создайте проект и откройте в нём новую форму. В панели инструментов Form Controls нажмите кнопку New Classes (рис. 11.13).

Рис. 11.13. Подключение библиотеки классов в Конструкторе форм

В появившемся контекстном меню выберите пункт Add. Появится стандартное диалоговое окно для открытия файла, в котором вы должны будете найти и выбрать библиотеку классов, в которой находится класс MyContainer. Как только библиотека классов будет выбрана, панель инструментов Form Controls изменит свой вид, отображая классы из добавленной библиотеки (рис. 11.14).

Рис.11.14. Пользовательские классы в панели Form Controls

Если вы наведёте мышь на любую из иконок в панели инструментов Form Controls, Visual FoxPro выведет всплывающую подсказку с именем класса. Выберите класс mycontainer и положите его на форму. Увеличьте область формы для контейнера так, чтобы стали видны все размещенные на нём управляющие элементы. Подвигайте контейнер по форме, чтобы убедиться, что это — один объект. Наконец, в окне Свойств откройте список объектов формы. Вы увидите, что объект Mycontainer1 (а именно такое имя дал новому объекту Конструктор форм) содержит четыре кнопки, метку и ComboBox (рис. 11.15).

Рис. 11.15. Размещение контейнера на форме

Все методы и свойства вложенных в контейнер объектов доступны для программирования, как это и должно быть для любого объекта-контейнера.
Можно было бы на этом закончить описание класса Container, но мы, как обычно, усложним себе жизнь. Добавим в контейнер свойство Value, в котором будем запоминать номер нажатой кнопки, а так же будем вызывать метод Click контейнера при нажатии на любую из размещённых на нём кнопок.
При добавлении в контейнер свойства Value (а такого свойства в базовом классе Container нет) установите для него уровень видимости Public и значение по умолчанию, равное нулю.
Номера кнопкам присвойте в соответствии с порядком их расположения в контейнере: слева направо. В методе Click каждой кнопки напишите следующий код:

 
 this.Parent.value = номер_кнопки (1, 2 и т.д.)
 this.Parent.Click()
 

Псевдоним Parent позволяет объекту обращаться к свойствам и методам объекта-контейнера, которому этот объект принадлежит. Так, свойство Value принадлежит контейнеру, поэтому кнопки используют псевдоним Parent для доступа к этому свойству (а так же и к методу Click контейнера).
Теперь метод Click контейнера будет срабатывать при нажатии на любую из вложенных в него кнопок; вы сможете проверять в этом методе значение свойства Value, чтобы определить, какая кнопка была нажата.

Класс Control

В отличие от класса Container, который разрешает доступ ко всем вложенным в него объектам, класс Control, так же на самом деле являясь контейнером, инкапсулирует в себе все свойства и методы включенных в него управляющих элементов, делая их недоступными из вне класса. Таким образом, несмотря на свою контейнерную природу, объекты — экземпляры класса Control ведут себя как цельные компоненты, скрывая своё внутреннее строение.
Для демонстрации возможностей этого класса мы создадим управляющий элемент в виде окна с полосами прокрутки, в котором можно будет просматривать изображения. Создайте в библиотеке классов новый класс с именем ScrollImage, указав в качестве базового класс Control. В Конструкторе классов добавьте в созданный класс три управляющих элемента: Image и два ActiveX компонента Microsoft Flat ScrollBar (если вы не ещё знаете, как добавлять на форму ActiveX компоненты, то обратитесь к главе 18 «Компоненты ActiveX»). Эти компоненты реализуют полосы прокрутки, которые, к сожалению, отсутствуют в наборе базовых классов Visual FoxPro. Присвойте свойству Orientation одной из полос прокрутки нулевое значение (вертикальная ориентация). Установите толщину полос прокрутки в 18 пикселей, горизонтально расположенной полосе дайте имя ScrollX (свойство Name элемента), вертикально расположенную полосу назовите ScrollY. Элемент Image расположите таким образом, чтобы его верхний левый угол совпадал с левым верхним углом контейнера, то есть свойства Left и Top элемента должны иметь нулевые значения. У вас должно получиться примерно то, что показано на рис. 11.16.

Рис. 11.16. Класс ScrollImage в Конструкторе классов

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

 Листинг 11.3. Код метода Init класса ScrollImage

 
 WITH this.ScrollX
    .Left = 0
    .Width = this.Width – this.ScrollY.Width
    .Top = this.Height – .Height
 ENDWITH
 WITH this.ScrollY
    .Top = 0
    .Left = this.Width – this.ScrollX.Height
    .Height = this.Height
 ENDWITH
 this.Image1.Visible = .F.
 

Метод-обработчик события Init объекта-контейнера отрабатывает после того, как будут созданы все вложенные в него объекты. Таким образом, этот код располагает полосы прокрутки ScrollX и ScrollY соответственно по нижней и правой границам контейнера; а реальные размеры объекта-контейнера (и его границы) вы определите при конструировании формы.
Добавим в класс новый метод, который будет загружать изображение в Image. Назовём его ShowImage. Метод будет получать два параметра. Первый параметр, tcSource — это символьная строка, содержащая либо имя файла, либо имя переменной или поля таблицы, содержащий изображение. Второй параметр, tlTyp, который может быть опущен, определяет, что содержит первый параметр — имя файла (tlTyp=.F.) или двоичные данные (tlTyp=.T.). Код метода ShowImage показан в листинге 11.4.

 Листинг 11.4. Код метода ShowImage класса ScrollImage

 
 LPARAMETERS tcSource, tlTyp
 LOCAL lnWidth, lnHeight
 IF tlTyp                       && В tcSource переменная (поле таблицы)
    this.Image1.PictureVal = tcSource
 ELSE                           && В tcSource - имя файла
    this.Image1.Picture = (tcSource)
 ENDIF 
 lnWidth = this.Image1.Width    && Ширина изображения
 lnHeight = this.Image1.Height  && Высота изображения
 *
 * Настраиваем параметры полос прокрутки
 *
 this.ScrollX.Max = lnWidth - this.Width - this.ScrollY.Width
 this.ScrollY.Max = lnHeight - this.Height - this.ScrollX.Height
 this.Image1.Visible = .T.
 

Чтобы добавить этот метод в класс ScrollImage, выберите в меню Class пункт New Method. В появившемся окне New Method (рис. 11.17) в поле Name введите имя нового метода — в нашем случае это ShowImage. Уровень видимости метода определяется точно так же, как и уровень видимости свойства. Так как этот метод должен быть доступен из вне объекта, определите этот уровень как Public. Нажмите на кнопку Add, затем на кнопку Close. Откройте метод для редактирования и введите в него код из листинга 11.4.

Рис. 11.17. Окно New Method Конструктора классов

Управляющий элемент Microsoft Flat ScrollBar предлагает вам два метода, обрабатывающие события, возникающие при перемещении ползунка полосы прокрутки или при щелчке мышью по ее крайним кнопкам. Нам необходимо обрабатывать эти события для управления положением управляющего элемента Image внутри контейнера. Метод Change срабатывает, когда вы переместили ползунок полосы прокрутки в новое положение и отпустили кнопку мыши. Метод Scroll срабатывает в течение всего процесса перемещения ползунка, что обеспечит «плавность» выполнения операции. Выбор метода оставляю на ваше усмотрение.
Вот код метода Scroll (или Change) для компонента ScrollY:

 
 This.Parent.Image1.Top = -this.Value
 

Аналогичный код такого же метода для компонента ScrollX:

 
 This.Parent.Image1.Left = -this.Value 
 

Добавьте в проект форму, в Конструкторе форм разместите на ней объект — экземпляр класса ScrollImage. Добавьте на форму командную кнопку. В свойстве Caption напишите «Открыть», а в метод Click введите следующий код:

 
 LOCAL lcFile
 lcFile = GETFILE('JPG|GIF|PNG|BMP|TIF')
 IF !EMPTY(lcFile)
    thisform.Scrollimage1.ShowImage(lcFile)
 ENDIF 
 

Как добавить в панель инструментов Form Controls Конструктора форм библиотеку классов, подробно рассмотрено в предыдущем параграфе.
У вас должно получиться нечто, похожее на показанное на рис. 11.18.

Рис. 11.18. Окно формы с объектом ScrollImage1 в Конструкторе форм

Запустите форму на выполнение, нажмите на кнопку Открыть. В появившемся диалоговом окне Open выберите файл, содержащий изображение одного из допустимых графических форматов. Вы должны увидеть примерно то, что показано на рис. 11.19.

Рис. 11.19. Окно формы с объектом ScrollImage1 в процессе выполнения.

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

Последнее, что нам осталось сделать — это убедиться в том, что объект ScrollImage1 не является контейнером (конечно, только с точки зрения вашей программы). Откройте форму в Конструкторе форм, в окне Свойств откройте список объектов (рис. 11.20).

Рис. 11.20. Список объектов в окне Свойств

Как видите, в списке нет никакой информации об объектах Image и Microsoft Flat ScrollBar. А в списке методов объекта ScrollImage1 вы увидите метод ShowImage.

Класс ToolBar. Создание панели инструментов

Объекты — экземпляры этого класса представляют собой специализированные немодальные формы, на которых располагаются кнопки и (очень редко) другие управляющие элементы. В Конструкторе классов панель управления создаётся достаточно просто, хотя, на мой взгляд, визуальная среда для конструирования могла бы быть более удобной. Впрочем, вы всё оцените сами.

Добавить класс ToolBar в библиотеку классов так же просто, как и любой другой класс. В окне New Class (рис.11.1) в поле Class Name введите имя создаваемой панели инструментов, например, MyPanel. В списке Base On выберите класс ToolBar. Сохраните класс в библиотеке классов. В Конструкторе классов появится окно панели инструментов. Всё, что от вас требуется — это разместить в этом окне командные кнопки и иные управляющие элементы.
Первое, что вы обнаружите — это невозможность менять размеры окна панели инструментов в Конструкторе классов до тех пор, пока в нём не будет размещено несколько управляющих элементов. Второе неудобство — это невозможность произвольно размещать в этом окне добавляемые управляющие элементы; их взаимным расположением управляет Конструктор классов. И, тем не менее, приступим.

Добавьте в окно панели инструментов командную кнопку, для чего:

  • выберите в панели инструментов Form Controls командную кнопку
  • щелкните мышью в области окна создаваемого класса

Кнопка будет добавлена в создаваемую панель инструментов. Повторите операцию для размещения на панели нескольких кнопок. У вас должно получиться примерно то, что показано на рис. 11.21.

Рис. 11.21. Вид панели инструментов в Конструкторе классов

Обратите внимание на то, что размещённые на панели кнопки не имеют названий. А посмотрев окно Свойств, вы увидите, что свойство ShowTips панели инструментов установлено в «истину» — то есть по умолчанию разрешено использование всплывающих окон-подсказок при перемещении указателя мыши над элементами панели.
Разместите на кнопках изображения-пиктограммы, в свойства ToolTip Text каждой кнопки введите необходимый текст, а в методах Click напишите код, который будет выполняться при нажатии на кнопку. Обычно кнопки панелей инструментов связаны с пунктами меню, поэтому в методе Click вызывайте те же процедуры, которые вызываются из соответствующих пунктов меню (как создать своё меню, вы узнаете в следующей главе).

Ещё один элемент, предназначенный для использования в панелях инструментов — это Separator. Применяются сепараторы для увеличения расстояния между элементами панели управления (действительно, посмотрев в окно Свойств, вы увидите, что свойства Top и Left всех кнопок недоступны). На рис. 11.22 показано место и вид сепаратора в панели инструментов Form Controls.

Рис. 11.22. Инструмент Separator в панели инструментов Form Controls

Вставьте этот компонент между кнопками на создаваемой панели инструментов. Если вы всё сделаете правильно, то панель инструментов примет следующий вид (рис. 11.23):

Рис. 11.23. Применение разделителей в панели инструментов

Когда в панели инструментов присутствует более одного управляющего элемента, вы можете изменять её размеры, при этом элементы панели располагаются по горизонтали, вертикали или в виде таблицы.
Что ещё можно сделать? Например, установить для свойств SpecialEffect кнопок значение, равное 2 (Hot Tracking); тогда контур кнопки будет появляться только при наведении на неё указателя мыши.
Создание объекта — экземпляра класса ToolBar, как и любого другого объекта, выполняется функциями CREATEOBJECT() или NEWOBJECT(). Хороший стиль программирования — использование для хранения ссылки на объект свойства формы верхнего уровня, на которой этот объект будет размещён (если, конечно, вы не создаёте новую панель инструментов для главного окна Visual FoxPro).

Замечание
Если панель инструментов должна размещаться на форме верхнего уровня, то создавать ее нужно после того, как эта форма будет «нарисована» на экране, например, в методах — обработчиках события Activate или Paint, иначе панель может «перепрыгнуть» в главное окно Visual FoxPro.

Для того, чтобы панель инструментов стала видимой, необходимо вызвать ее метод Show (как показано в листинге 11.5).
Вы можете разместить созданную панель у границы окна, вызвав метод Dock. Вот его синтаксис:

 
 ToolBarObject.Dock(nLocation [, X, Y])
 

Параметр nLocation определяет положение панели инструментов в окне формы верхнего уровня (As Top Level Form) или главном окне Visual FoxPro. Его допустимые значения приведены в табл. 11.1.

Таблица 11.1. Значения параметра nLocation метода Dock()

nLocation Описание
-1  Панель инструментов не пристыковывается
0  Пристыковывается к верхнему горизонтальному краю окна
1  Пристыковывается к левому краю окна
2  Пристыковывается к правому краю окна
3  Пристыковывается к нижнему краю окна

Параметры X, Y определяют позицию левого верхнего угла панели инструментов, если параметр nLocation равен -1.

В листинге 11.5 показан код, в котором создается панель инструментов. Предполагается, что класс панели расположен в библиотеке MyClasses и имеет имя MyPanel.

 Листинг 11.5. Создание объекта панели инструментов

 
 PUBLIC oTool
 SET CLASSLIB TO myclasses
 oTool = CREATEOBJECT('MyPanel')
 oTool.Show()            && Панель запускается как немодальная форма
 oTool.Dock(0)           && и пристыковывается к верхней границе окна
 

Если главной формой вашего приложения является форма верхнего уровня, то присвойте свойству ShowWindow панели инструментов значение «1» (In Top Level Form) для того, чтобы панель инструментов пристыковалась к вашей главной форме, а не исчезла бесследно, если главное окно Visual FoxPro невидимо.

Редактирование объявлений свойств и методов класса

Как и Конструктор форм, Конструктор классов позволяет вам выполнять редактирование объявлений свойств и методов класса. Вы можете изменить имя свойства или метода, определить уровень видимости, либо удалить метод из класса. Для перехода в режим редактирования выберите в главном меню пункт Class, и в выпавшем меню — пункт Edit Property/Method. Другой способ заключается в использовании окна Свойств. Установите указатель на строку с именем метода или свойства и нажмите на правую кнопку мыши. В появившемся меню выберите пункт Edit Property/Method. В результате этих манипуляций Конструктор классов выведет на экран диалоговое окно для редактирования объявлений свойств и методов (рис. 11.24).

Рис. 11.24. Окно редактирования объявлений свойств и методов

Это окно отличается от аналогичного окна Конструктора форм только возможностью изменения значения уровня видимости в расположенном справа выпадающем списке Visibility. Поэтому не будем останавливаться на рассмотрении кнопок New Property, New Method и Remote, с назначением которых вы познакомились, изучая Конструктор форм в главе 4. Отмечу только, что вы можете установить уровень видимости для любого (в том числе и унаследованного от базового класса) свойства или метода.