Отправляет email-рассылки с помощью сервиса Sendsay

Borland C++ Builder - всякая всячина

  Все выпуски  

Borland C++ Builder - всякая всячина (№15 Связывание компонентов)


Служба Рассылок Subscribe.Ru

Приветствую всех получателей рассылки Borland C++ Builder - всякая всячина!

№15. Связывание компонентов

"...
- Ты как здесь оказался?
- Стреляли...
..."
(к/ф "Белое солнце пустыни")

 

Не так давно, когда деревья уже были маленькими, возникла у меня необходимость создать на форме два "едита", точнее, "спинедита", то есть, обычного поля для ввода, снабженного справа двумя стрелками "вверх" и "вниз".

В такое поле можно ввести только числа, причем, вводить их можно как с клавиатуры, так и перебором упомянутыми стрелками от минимально возможного до максимально возможного значения. Наиболее подходящим компонентом является TRxSpinEdit из библиотеки RxLib (очень, кстати, рекомендую иметь и активно пользоваться). Он имеет несколько дополнительных параметров, отличающих его от обычного TEdit, в частности, позволяет вводить целые, дробные, 16-ричные числа, может блокировать ввод с клавиатуры (только стрелками), позволяет задать минимальное и максимальное значение вводимого параметра и шаг перебора с помощью стрелок. Элитная вещь, в общем.

Так вот, о двух полях. Мне, по сценарию, нужно было предоставить пользователю возможность устанавливать минимальную и максимальную длину строки (например, минимум - 6 максимум - 11 символов). Соответственно, для этого мне пришлось ввести на форме два поля типа TRxSpinEdit, собственно, их было введено несколько пар, так как было несколько подобных параметров. После этого, необходимо было ввести связь между парными полями, так как значение, введенное в поле минимума, не должно было превышать значение в поле максимума. Для этого я отслеживал событие OnChange данного компонента, но в дальнейшем мне это событие потребовалось для других целей, причем оставить в коде обработчика события отслеживание связи между парными полями не представлялось возможным. Очень хорошо для этих целей подходила динамическая (читай - виртуальная) функция Change, но она была объявлена в секции protected:, то есть получить к ней доступ ("перекрыть" ее) я мог, только сотворив наследника данного класса, в котором каждый раз при изменении значения поля будет вызываться уже моя функция Change.

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

Наверное, в этом выпуске я только в общих чертах изложу свои соображения по свойствам создаваемого компонента, а конечной реализацией мы займемся в следующих выпусках, поскольку такая тема тянет на хорошую главу книги. Итак, постановка задачи: создать компонент с такими свойствами, чтобы при связывании его с другим компонентом идентичного типа и указании типа (минимум или максимум) производилась проверка корректности значений обоих компонентов.

Сформулировал, наверное, немного комкано, так что переведу "на русский": имеем два поля, связанные друг с другом. В одном хранится минимальное значение, в другом - максимальное. При изменении, допустим, минимального значения должна производиться проверка, не стало ли (вдруг) это значение больше чем в поле максимального значения. Также необходима проверка и в обратной ситуации. Итак, во-первых, компонент, несомненно, должен иметь следующее свойство:
TMySpinEdit *PairField
- указатель на объект того же типа. Данное свойство как раз и предназначено для создания "связки" двух полей. Очевидно, что поместить его следует в секции published: для того, чтобы пользователь мог прямо при разработке формы устанавливать нужные ему связи (подробнее об этом - в выпуске №12).

Кроме того, закономерно возникает вопрос об идентификации среди этой пары поля минимального и поля максимального значения. Можно конечно ввести логическое свойство (true - минимум, false - максимум), но мы легких путей не ищем, поэтому определим специальный тип TSpinEditType:
enum TSpinEditType { stMinSpinEdit, stMaxSpinEdit };
и соответствующее свойство:
TSpinEditType Type, которое однозначно, а самое главное - наглядно, будет определять принадлежность поля к тому или иному типу.

Из всего вышесказанного получаем еще одну задачку: а что делать в том случае, если значение в поле минимума стало больше значения в поле максимума или наоборот? Логически напрашивается один из двух вариантов: 1. Как только значение в поле минимума достигнет значения в поле максимума, остановить дальнейшее увеличение минимального значения (аналогично - для обратной ситуации). 2. При том же раскладе продолжаем увеличение минимального значения, но корректируем попутно значение поля максимума (по крайней мере, до тех пор, пока оно не "упрется" в значение свойства MaxValue для поля максимума). Ух!!!

Признаюсь, я долго не мог понять, принцип отключение свойств MinValue и MaxValue. При нулевом значении? А если оно мне нужно? В хелпе по RxLib я пояснения не нашел, поэтому пришлось обратиться к первоисточнику - файлу Units/RxSpin.pas, в котором "русским" языком поясняется в методе CheckValue, что если значения свойств MinValue и MaxValue совпадают, то их значения не учитываются и значение, вводимое в поле, ничем не ограничивается. Простенько, но элегантно...

Так вот, кто будет решать-то, какой из вариантов выбрать для реализации? Я предлагаю, как всегда, свалить решение на Пушкина, то есть на пользователя и реализовать в коде компонента оба варианта. Таким образом, мы вынуждены будем ввести еще один тип:
enum TCorrectPairType { ctStopThis, ctCorrectPair };
согласно которому будем определять реакцию компонента в случае разногласия в связке. При значении свойства TCorrectPairType CorrectType, равном ctStopThis, поле подстраивает свое новое значение под значение парного поля, если же CorrectType равно ctCorrectPair, то поле пытается в первую очередь осуществить "наезд" на значение парного ему поля, и корректирует свое значение только в том случае, если в парном поле коррекция невозможна из-за ограничений MinValue или MaxValue.

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

PS: Не много не по теме, но все же: выложил на сайте скрипт для работы с древовидными структурами. В качестве "базы данных" он использует xml-файл и предназначен для организации ссылок на сайты в интернете. Главное его достоинство в том, что он не имеет серверной части (в виде cgi-скрипта) и встраивается на любую страницу. Имеют место быть различные параметры для "тонкой" настройки отображения "дерева". Единственный крупный недостаток - работает все это удовольствие только в Internet Explorer версии 5.0 и више... В общем, кому интересно, загляните на сайт, там все подробно расписано - что, где, когда, кому, за что и сколько...



С уважением, Васильев Евгений...
Почта: vasco@homeline.ru
Сайт: http://www.homeline.ru/vasco


http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное