компонентов общего назначения библиотеки Delphi5

         

Диалоговое окно проектирования компонента F1Book

Правая быстрая кнопка на Рисунок 3.15 позволяет ввести на страницу диаграммы и графики. Чтобы задать диаграмму, надо сначала выделить курсором в таблице данные, которые должны отображаться в диаграмме, затем нажать кнопку ввода диаграммы, после этого указать курсором рамку, в которой должна отображаться диаграмма. В результате вы попадете в диалоговое окно, в котором сможете выбрать тип диаграммы и необходимые ее атрибуты.

Рассказывать подробно о работе с окном проектирования компонента F1Book невозможно из-за ограничения на объем данной книги. Те, кто знаком с Excel, без труда смогут в этом окне ориентироваться. К тому же в нем имеется встроенная справка, вызываемая командой меню Help или клавишей F1.

Щелкнув правой кнопкой мыши на компоненте F1Book, вы можете выбрать еще одну команду — Properties. В появившемся при этом диалоговом окне (Рисунок 3.16) вы можете, в частности, задать опции, определяющие, что будет видно или не видно в таблице при работе приложения: заголовки строк и столбцов (Row Heading и Column Heading), сетка (Gridlines), формулы вычислений (Formulas) и т.п.


Font — шрифт отображения текста в компонентах


Во всех компонентах ввода и отображения текстовой и цифровой информации шрифт текста, его размер, стиль (жирный, курсив и т.п.) определяются свойством Font. Это свойство в свою очередь является объектом типа TFont, который имеет множество подсвойств, устанавливаемых в процессе проектирования или программно во время выполнения приложения. Основные свойства шрифта следующие:

CharsetОпределяет набор символов шрифта.
ColorОпределяет цвет текста.
HeightХарактеризует высоту шрифта в пикселях.
NameВид (имя) шрифта.
PitchОпределяет способ установки ширины символов.
SizeРазмер шрифта в кеглях (пунктах).
StyleСтиль шрифта: полужирный — fsBold, курсив — fsItalic, подчеркнутый — fsUnderline, перечеркнутый — fsStrikeout.

Если система не может найти шрифта с заданной комбинацией свойств Name, Charset, Pitch и Size, Windows использует другой, близкий по характеристикам шрифт.

Основное свойство шрифта — Name. Если заданный именем Name шрифт недоступен в системе, Windows заменит его другим шрифтом. По умолчанию для всех компонентов Delphi, начиная с Delphi 2, задается имя шрифта MS Sans Serif и размер 8. Delphi 1 задает имя шрифта System и размер 10. Можно рекомендовать без особой нужды не изменять Name, так как заданные по умолчанию шрифты есть на любом компьютере с Windows, а другой шрифт может отсутствовать на компьютере пользователя вашей программы.

Свойства Size и Height определяют размер шрифта. Свойство Size определяет его в кеглях (пунктах, принятых в Windows), a свойство Height — в пикселях. Если значение Size задано отрицательным, то в размер входит верхний пиксель каждой строки. Если значение Size задано положительным, то этот пиксель не учитывается.

Значение Size связано со свойствами Height и PixelsPerInch (число пикселей на дюйм) соотношением: Font.Size = -Font.Height * 72 / Font.PixelsPerInch

Из соотношения, в частности, видно, что задание положительного значения Size ведет к отрицательному значению Height и наоборот.

Свойство Pitch обычно имеет значение fpDefault, при котором ширина устанавливается равной по умолчанию, т.е. описанной в шрифте заданного вида Name. Свойство может принимать также значения fpFixed — установка одинаковой ширины всех символов и fpVariable — установка различной ширины символов. Задание значения отличного от fpDefault заставляет Windows искать наилучший способ удовлетворить всем заданным характеристикам шрифта. Иногда это может привести к замене шрифта на шрифт другого, близкого вида, а иногда может вообще не повлиять на шрифт — все зависит от конкретного вида шрифта и даже от его версии.

Свойство Charset определяет набор символов шрифта. Каждый вид шрифта, определяемый его именем, поддерживает один или более наборов символов. Какие именно значения Charset поддерживает тот или иной шрифт можно установить из документации на него или экспериментальным путем, в частности, с помощью приведенного далее в этом разделе тестового приложения. Для шрифтов, поддерживающих несколько наборов символов, важно правильно задать Charset.

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

По умолчанию в объектах типа TFont задается значение Charset, равное 1 или DEFAULT_CHARSET. При этом шрифт выбирается только по его имени Name и размеру Size. Если описанный шрифт недоступен в системе, то Windows заменит его другим шрифтом. Для имен шрифтов, принятых в Delphi по умолчанию, это обычно нормальный вариант. Но в ряде случаев полезно для отображения русских текстов с другими шрифтами заменить это значение на RUSSIAN_CHARSET. Это позволит отобразить символы кириллицы для тех шрифтов, для которых при DEFAULT_CHARSET символы кириллицы не отображаются нормально.

Свойство Style, задающее стиль, представляет собой множество или пустое, или содержащее одно или более из возможных значений. Ниже приведены примеры операторов, устанавливающих стиль шрифта: Label1.Font.Style := [ ]; {Обычный стиль} Label1.Font.Style := [fsBold]; {Полужирный} Label1.Font.Style := [fsBold, fsItalic]; {Полужирный курсив}

Значения свойств объекта Font можно присваивать по отдельности, как это сделано в приведенных выше операторах для свойства Style. Но чаще они задаются все сразу методом Assign, который записывает значения всех свойств одного объекта в другой. Пусть, например, на форме имеется компонент Memo1 (см. ), в котором расположен некоторый текст, компонент FontDialog1 — диалог выбора шрифта (см. ), и меню с разделом выбора шрифта, названным MFont. Для того, чтобы пользователь мог выбрать имя и атрибуты шрифта текста, отображаемого в Memo1, в обработчик события OnClick раздела меню MFont надо вставить оператор: if (FontDialog1.Execute) then Memo1.Font.Assign(FontDialog1.Font);

Если пользователь сменил атрибуты в диалоговом окне выбора шрифта, то метод FontDialog1.Execute (см. ) возвращает true и атрибуты шрифта компонента Memo1 устанавливаются равными выбранным пользователем.

Для того, чтобы продемонстрировать доступные в системе шрифты и исследовать влияние на них свойств Pitch и Charset, можно построить тестовое приложение, показанное на Рисунок 3.1 В нем используются компоненты MainMenu, Button, ComboBox, SpinEdit и Memo, которые будут рассмотрены позднее в разделах , , , и . Поэтому те, кто не знаком с этими компонентами, могут пока пропустить данный пример и вернуться к нему позднее.



Компоненты отображения иерархических данных — TreeView, Outline, ListView


Компоненты TreeView и Outline служат для отображения иерархических данных в виде дерева (см. пример на Рисунок 3.18), в котором пользователь может выбрать нужный ему узел или узлы. Иерархическая информация может быть самой разной: структура некоторого предприятия, структура документации учреждения, структура отчета и т.п. С каждым узлом дерева могут быть связаны некоторые данные.

Возможности компонента TreeView несколько шире, чем компонента Outline. К тому же TreeView — 32-разрядный компонент, a Outline — 16-разрядный. Поэтому Outline целесообразно использовать только в приложениях, создаваемых с помощью Delphi 1.

Основным свойством TreeView, содержащим информацию об узлах дерева, является Items. Доступ к информации об отдельных узлах осуществляется через этот индексный список узлов. Например, TreeView1.Items[1] — это узел дерева с индексом 1 (второй узел дерева). Каждый узел является объектом типа TTreeNodes, обладающим своими свойствами и методами.

Во время проектирования формирование дерева осуществляется в окне редактора узлов дерева, представленном на Рисунок 3.20. Это окно вызывается двойным щелчком на компоненте TreeView или нажатием кнопки с многоточием около свойства Items в окне Инспектора Объектов.



Компоненты выбора из списков — ListBox, CheckListBox и ComboBox


Пример компонентов, рассмотренных в данном разделе и обеспечивающих выбор из списка, приведен на Рисунок 3.10.



Многострочные окна редактирования Memo и RichEdit


Компоненты Memo и RichEdit (см. пример на Рисунок 3.7) являются окнами редактирования многострочного текста. Они так же, как и окно Edit, снабжены многими функциями, свойственными большинству редакторов. В них предусмотрены типичные комбинации «горячих» клавиш: Ctrl-C — копирование выделенного текста в буфер обмена Clipboard (команда Copy), Ctrl-X — вырезание выделенного текста в буфер Clipboard (команда Cut), Ctrl-V — вставка текста из буфера Clipboard в позицию курсора (команда Paste), Ctrl-Z — отмена последней команды редактирования.



Обеспечение синтаксически правильного ввода текстовых и цифровых данных


Мы рассмотрели различные компоненты ввода информации. Теперь остановимся на проблеме сокращения числа возможных ошибок пользователя при вводе текстовых и числовых данных. Это очень серьезная проблема, особенно при построении приложений, рассчитанных на массового и не очень квалифицированного пользователя. Частично безошибочного ввода можно добиться за счет маскирования, описанного при рассмотрении компонента MaskEdit. Однако, и при маскированном вводе пользователь может ошибиться в синтаксисе, в результате чего будет генерироваться исключение. Еще лучше использовать, если возможно, выбор с помощью компонентов типа ListBox, ComboBox, StringGrid, DateTimePicker, SpinEdit и т.п. Это гарантирует, если не правильный в смысловом плане, то, по крайней мере, синтаксически правильный ввод. В качестве примера на Рисунок 3.17 приведены два варианта ввода информации о сотрудниках некоей организации. Слева ввод осуществляется с помощью компонентов Edit и пользователь может сделать любые ошибки.

Справа ввод осуществляется с помощью компонентов ComboBox, SpinEdit, MaskEdit и DateTimePicker. ComboBox со значением свойства Style равным csDropDownList не допускает редактирования и, значит, пользователь просто не может указать неправильный отдел. SpinEdit гарантирует синтаксически правильное указание стажа работы, а его свойства MinValue и MaxValue определяют реальные пределы вводимого числа (например, число лет от 1 до 50). Аналогично компонент MaskEdit гарантирует синтаксически правильный ввод номера телефона, а компонент DateTimePicker гарантирует (даже без использования выпадающего календаря) синтаксически правильный ввод даты рождения и ее допустимые пределы (например, от 1930 г. до 1980 г.).





Окна редактирования Edit и MaskEdit


На Рисунок 3.5 вы можете увидеть примеры окон редактирования. Внешнее оформление окон редактирования определяется свойством BorderStyle, влияние которого на вид компонента вы можете увидеть на том же рисунке.



Окно редактирования списков строк

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

Весь текст, представленный одной строкой типа String, внутри которой используются разделители типа символов возврата каретки и перевода строки, содержится в свойстве Text.

Доступ к отдельной строке текста вы можете получить с помощью свойства Strings[Index: Integer]. Индексы, как и везде в Delphi, начинаются с 0. Так что Memo1.Lines.Strings[0] — это текст первой строки. Учтите, что если окно редактирования изменяется в размерах при работе с приложением и свойство WordWrap = true, то индексы строк будут изменяться при переносах строк, так что в этих случаях индекс мало о чем говорит.

Свойство только для чтения Count указывает число строк в тексте.

Для очистки текста в окне надо выполнить процедуру Clear. Этот метод относится к самому окну, а не к его свойству Lines.

Для занесения новой строки в конец текста окна редактирования можно воспользоваться методами Add или Append свойства Lines. Для загрузки текста из файла применяется метод LoadFromFile. Сохранение текста в фале осуществляется методом SaveToFile.

Пусть, например, в вашем приложении имеется окно редактирования Edit1, в котором пользователь вводит имя сотрудника, и есть кнопка, при щелчке на которой в окно Memo1 должна занестись шапка характеристики этого сотрудника, после чего пользователь может заполнить текст характеристики.

Обработчик щелчка на кнопке может иметь вид: Memo1.Clear; Memo1.Lines.Add ('Х А Р А К Т Е Р И С Т И К А'); Memo1.Lines.Add('Сотрудник '+Edit1.Text) ;. Memo1.SetFocus;

Загрузка в окно Memo1 текста из файла (например, хранящейся в файле характеристики сотрудника) может осуществляться командой Memo1.Lines.LoadFromFile ('text.txt');

Сохранение текста в файле может осуществляться командой Memo1.Lines.SaveToFile('text.txt');

Свойство SelStart компонентов Memo и RichEdit указывает позицию курсора в тексте или начало выделенного пользователем текста. Свойство CaretPos указывает на запись, поле X которой содержит индекс символа в строке, перед которым расположен курсор, а поле Y — индекс строки, в которой находится курсор (встроенная справка Delphi утверждает другое — что свойство CaretPos содержит координаты курсора в пикселях; но, к счастью, это не так). Таким образом, учитывая, что индексы начинаются с 0, значения Memo1.CaretPos.Y+1 и Memо1.CaretPos.X+1 определяют соответственно номер строки и символа в ней, перед которым расположен курсор. В редакторе на Рисунок 3.8 именно эти значения (только не для Memo, а для RichEdit) использованы, чтобы отображать в строке состояния (см. ) позицию курсора.

Окно редактора масок с загруженными файлами стандартных масок: американским (а) и российским (6)

a)
b)

Кнопка Masks позволяет выбрать и загрузить какой-либо другой файл стандартных масок. К сожалению, среди файлов стандартных масок, поставляемых с Delphi, отсутствует маска, соответствующая российским стандартам. Но вы легко можете сами сделать себе такой файл стандартных масок. Он делается в обычном текстовом редакторе и должен сохраняться как «только текст» с расширением .dem. Чтобы редактор масок Delphi видел этот файл, его надо сохранить в каталоге Delphi BIN. Каждая строка файла состоит из трех частей, разделяемых символом вертикальной черты. Первая часть состоит из пояснительного текста, появляющегося в левой панели окна Sample Masks редактора масок. Вторая часть — пример, который появляется в правой панели окна Sample Masks редактора масок. А третья часть — сама маска. Например, я сделал себе файл с текстом, приведенным ниже, и сохранил его с именем ru.dem. Телефон | 5551212 | !000-00-00;0;_ Телефон с кодом страны | 0955551212 | !\(999\) 000-00-00;0;_ Почтовый индекс | 123456 | !000000;1;_ Паспорт| VII123456 | !L-LL 999999;0;_ Дата с указанием дня | 270694 | !99/99/00;1;_ Дата без указания дня | 0694 | !99/00;1;_ Время с секундами | 210515 | ! 90:00:00;1;_ Время без секунд | 1345 | !90:00;1;_

На Рисунок 3.6 б вы можете видеть его в работе, а на Рисунок 3.5 вы можете видеть ввод в окна с масками телефона и даты.

Рассмотрим примеры масок. В приведенном выше файле маска для ввода номера телефона имеет вид: !\(999\) 000-00-00;0;_ В этой маске символ 9 означает, что в соответствующей позиции может быть только цифра. Символ 0 означает, что в данной позиции должна быть цифра. Символ подчеркивания в конце маски будет заполнять пустые позиции. Таким образом, пользователю для ввода в окне будет отображен шаблон (см. Рисунок 3.5): (___)___-__-__

Поскольку второй раздел маски равен 0, то при чтении введенных пользователем значений свойства EditText и Text будут различаться. Свойство EditText для примера Рисунок 3.5 будет равно (095) 123-45-67, а свойство Text будет равно 0951234567. Если второй раздел маски сделать равным 1, то значения обоих свойств будут равны (095) 123-45-67.

Рассмотрим еще пример. Если с помощью EditMask надо ввести, например, целое число без знака, состоящее не более, чем из двух цифр, можно задать маску 99;0; . Если число обязательно должно быть двузначным, то маска должна иметь вид 00;0; .

Окно редактора списка объектов компонента ListView


Если вы хотите предоставить пользователю возможность изменять вид списка, сделайте следующее: введите в приложение разделы меню Крупные значки (пусть его имя будет MIcon), Мелкие значки (имя MSmallIcon), Список (имя MList) и Таблица (имя MReport) установите во всех этих разделах одинаковый отличный от нуля индекс GroupIndex и свойства RadioItem в true один из разделов пометьте как Checked и в свойстве списка ViewStyle установите значение, соответствующее этому разделу напишите следующие обработчики щелчков для этих разделов: procedure TForm1.MIconClick(Sender: TObject); begin ListView1.ViewStyle:=vsIcon; MIcon.Checked:=true; end; procedure TForm1.MSmallIconClick(Sender: TObject); begin ListView1.ViewStyle:=vsSmallIcon; MSmallIcon.Checked:=true; end; procedure TForm1.MListClick(Sender: TObject); begin ListView1.ViewStyle:=vsList; MList.Checked:=true; end; procedure TForm1.MReportClick(Sender: TObject); begin ListView1.ViewStyle:=vsReport; MReport.Checked:=true; end;

Основное свойство компонента, описывающее состав отображаемой информации — Items. Во время проектирования оно может быть установлено специальным редактором (Рисунок 3.21), вызываемом щелчком на кнопке с многоточием рядом с этим свойством в окне Инспектора Объектов. Оно похоже на окно, описанное для компонента TreeView (Рисунок 3.20). Точно так же в нем задаются новые узлы кнопкой New Item и дочерние узлы — кнопкой New SubItem. Только смысл дочерних узлов другой: это информация, которая появляется только в режиме vsReport — в виде таблицы.

Для каждого узла задается свойство Caption — надпись, появляющаяся около пиктограммы. Для дочерних узлов это свойство соответствует надписи, появляющейся, в ячейках таблицы в режиме vsReport.

Свойство Image Index определяет индекс пиктограммы. Индекс соответствует спискам изображений, хранящимся в отдельных компонентах ImageList (см. ). Указания на эти компоненты вы можете задать в свойствах LargeImages для режима vsIcon и SmallImages для режимов vsSmallIcon, vsList и vsReport. Индексы начинаются с 0. Если вы укажете индекс -1 (значение по умолчанию), пиктограммы изображаться не будут. Свойство State Index в панели Item Properties позволяет добавить вторую пиктограмму в данный объект. Подобная пиктограмма может просто служить дополнительной характеристикой объекта. Индекс, указываемый как State Index, соответствует списку изображений, хранящихся в отдельном компоненте ImageList, указанном в свойстве StateImages компонента ListView.

Свойство Columns определяет список заголовков таблицы в режиме vsReport при свойстве ShowColumnHeaders (показать заголовки), установленном в true. Свойство Columns можно задать в процессе проектирования специальным редактором заголовков, вызываемом двойным щелчком на компоненте ListView или щелчком на кнопке с многоточием рядом со свойством Columns в окне Инспектора Объектов. Редактор заголовков уже (см. Рисунок 3.19).

Свойство Checkboxes определяет отображение индикатора с флажком около каждого элемента списка. Индикаторы можно устанавливать программно или их может изменять пользователь во время выполнения. Тогда узнать программно, установлен ли индикатор в некотором элементе Items[i], можно проверкой его свойства Checked. Например: for i:=0 to ListView1.Items.Count-1 do if ListView1.Items[i].Checked then ...;

Свойства HotTrack и HotTrackStyles определяют появление выделения при перемещении курсора над элементом списка и стиль этого выделения. Свойство HoverTime (только в Delphi 5) задает в миллисекундах задержку появления такого выделения.

Свойство списка Selected определяет выделенный пользователем элемент списка.

Свойство DragMode определяет режим перетаскивания элементов списка. Если вы хотите разрешить пользователю перетаскивать пиктограммы по площади списка в режимах vsIcon и vsSmallIcon, вам надо сделать следующее: установить DragMode = dmAutomatic установить DragKind = dkDrag написать обработчик события OnDragOver списка: Accept := Source = ListView1; написать обработчик события OnDragDrop списка: (Source as TListView).Selected.Position:=Point(X,Y); если вы предоставили пользователю возможность выбирать вид отображения списка с помощью описанных ранее разделов меню, то в обработчиках щелчка на MIcon и MSmallIcon надо написать операторы ListView1.DragMode:=dmAutomatic; а в обработчиках щелчка на MList и МReport надо написать операторы ListView1.DragMode:=dmManual;

Метод Arrange: procedure Arrange(Code: TListArrangement); позволяет упорядочить пиктограммы в режимах vsIcon и vsSmallIcon. Параметр Code определяет способ упорядочивания:

arAlignBottomвыравнивание вдоль нижнего края области arAlignLeftвыравнивание вдоль левого края области arAlignRightвыравнивание вдоль правого края области arAlignTopвыравнивание вдоль верхнего края области arDefaultвыравнивание по умолчанию (вдоль верхнего края области) arSnapToGridразмещение каждой пиктограммы в ближайшем узле сетки

В Delphi 5 введено еще одно свойство ListViewWorkAreas.

Это свойство определяет рабочую область (прямоугольную рамку), в которой осуществляется выравнивание пиктограмм в режимах vsIcon и vsSmallIcon. Свойство WorkAreas представляет собой индексированный список, аналогичный Items, но совершенно независимый от него. Если WorkAreas — пустой список (ни одна область в него не добавлена), то упорядочивание пиктограмм производится в пределах всей клиентской области ListView. Добавление новой рабочей области осуществляется методом Add. Свойство рабочей области Rect типа TRect (см. ) определяет границы области. Свойство Color определяет цвет рамки, обрамляющей область. Свойство DisplayName определяет подпись под рамкой. И рамка, и подпись отображаются только в случае, если свойство списка ShowWorkAreas установлено в true.

Пример операторов, создающих в площади списка две рабочие области: ListView1.WorkAreas.Add; ListView1.WorkAreas[0].Rect := Rect(0,0, ListView1.ClientWidth div 4, ListView1.ClientHeight div 2); ListView1.WorkAreas.Items[0].DispiayName := 'Область 0'; ListView1.WorkAreas.Items[0].Color := clRed; ListView1.WorkAreas.Add; ListView1.WorkAreas[1].Rect := Rect(ListView1.ClientWidth div 2, 0, (ListView1.ClientWidth div 4)*3, ListView1.ClientHeight div 2); ListView1.WorkAreas.Items[1].DisplayName := 'Область 1';

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

Способ упорядочивания определяется соответствующим заданием свойства SortType, которое уже рассматривалось нами для компонента TreeView.

Окно редактора узлов дерева компонента TreeView


Кнопка New Item (новый узел) позволяет добавить в дерево новый узел. Он будет расположен на том же уровне, на котором расположен узел, выделенный курсором в момент щелчка на кнопке New Item.

Кнопка New SubItem (новый дочерний узел) позволяет добавить в дерево дочерний узел. Он будет расположен на уровень ниже уровня того узла, который выделен курсором в момент щелчка на кнопке New SubItem.

Кнопка Delete (удалить) удаляет выделенный узел дерева. Кнопка Load позволяет загрузить структуру дерева из файла. Файл, хранящий структуру дерева — это обычный текстовый файл, содержащий тексты узлов. Уровни узлов обозначаются отступами. Например, файл дерева, изображенного на Рисунок 3.18 и 3.20, может иметь вид: производство цех 1 цех 2 цех 3 управление администрация бухгалтерия

Для каждого нового узла дерева можно указать ряд свойств в панели Item Properties окна на Рисунок 3.20. Это прежде всего свойство Text — надпись, появляющаяся в дереве около данного узла. Свойства Image Index и Selected Index определяют индекс пиктограммы, отображаемой для узла, который соответственно не выделен и выделен пользователем в данный момент. Эти индексы соответствуют списку изображений, хранящихся в отдельном компоненте ImageList (см. ). Указание на этот компонент вы можете задать в свойстве Images компонента TreeView. Индексы начинаются с 0. Если вы укажете индекс -1 (значение по умолчанию), пиктограммы изображаться не будут. Последнее свойство — State Index в панели Item Properties позволяет добавить вторую пиктограмму в данный узел, не зависящую от состояния узла. Подобная пиктограмма может просто служить дополнителъной характеристикой узла. Индекс, указываемый как State Index, соответствует списку изображений, хранящихся в отдельном компоненте ImageList, указанном в свойстве StateImages компонента TreeView.

Мы рассмотрели формирование дерева в процессе проектирования. Однако, дерево можно формировать или перестраивать и во время выполнения приложения. Для этого служит ряд методов объектов типа TTreeNodes. Следующие методы позволяют вставлять в дерево новые узлы:

function Add(Node: TTreeNode; const S: string): TTreeNode;Добавляет новый узел с текстом S как последний узел уровня, на котором расположен Node. function AddFirst(Node: TTreeNode; const S: string): TTreeNode;Вставляет новый узел с текстом S как первый из узлов уровня, на котором находится Node. Индексы последующих узлов увеличиваются на 1. function Insert (Node: TTreeNode; const S: string): TTreeNode;Вставляет новый узел с текстом S сразу после узла Node на тот же уровень. Индексы последующих узлов увеличиваются на 1. function AddChild(Node: TTreeNode; const S: string): TTreeNode;Добавляет узел с текстом S как последний дочерний узла Node. function AddChildFirst(Node: TTreeNode; const S: string); TTreeNode;Вставляет новый узел с текстом S как первый из дочерних узлов узла Node. Индексы последующих узлов увеличиваются на 1.

Каждый из этих методов возвращает вставленный узел. Ниже в качестве примера приведен код, формирующий то же дерево, которое вы можете видеть на Рисунок 3.18 и 3.20. TreeView1.Items.Clear; // очистка списка // добавление корневого узла 'производство' (индекс 0) TreeView1.Items.Add(nil, 'производство'); {добавление дочерних узлов 'цех 1' — 'цех 3' (индексы 1 - 3)} TreeView1.Items.AddChild(TreeView1.Items.Item[0], 'цех 1'); TreeView1.Items.AddChild(TreeViewl.Items.Item[0], 'цех 2'); TreeView1.Items.AddChild(TreeView1.Items.Item[0], 'цех 3'); {добавление корневого узла 'управление' после узла 'производство' (индекс 4) } TreeView1.Items.Add(TreeView1.Items.Item[0], 'управление'); {добавление дочерних узлов 'администрация' и 'бухгалтерия' узла 'управление' } TreeView1.Items.AddChild(TreeView1.Items.Item[4], 'администрация'); TreeView1.Items.AddChild(TreeView1.Items.Item[4], 'бухгалтерия');

Дерево может быть сколь угодно разветвленным. Например, следующие операторы добавляют дочерние узлы «бригада 1» и «бригада 2» в сформированный ранее узел «цех 1»: TreeView1.Items.AddChild(TreeView1.Items.Item[1], 'бригада 1'); TreeView1.Items.AddChild(TreeView1.Items.Item[l], 'бригада 2');

Текст, связанный с некоторым узлом, можно найти с помощью его свойства Text. Например, TreeView1.Items.Item[1].Text — это надпись «цех 1».

С каждым узлом может быть связан некоторый объект. Добавление таких узлов осуществляется методами AddObject, AddObjectFirst, InsertObject, AddChildObject, AddChildObjectFirst, аналогичными приведенным выше, но содержащими в качестве параметра еще указатель на объект:

function AddObject(Node: TTreeNode; const S: string; Ptr: Pointer): TreeNode;Добавляет новый узел с текстом S и объектом Ptr как последний узел уровня, на котором расположен Node. function AddObjectFirst(Node: TTreeNode; const S: string; Ptr: Pointer): TTreeNode;Вставляет новый узел с текстом S и объектом Ptr как первый из узлов уровня, на котором находится Node. Индексы последующих узлов увеличиваются на 1. function InsertObject(Node: TTreeNode; const S: string; Ptr: Pointer): TTreeNode; Вставляет новый узел с текстом S и объектом Ptr сразу после узла Node на тот же уровень. Индексы последующих узлов увеличиваются на 1. function AddChildObject(Node: TTreeNode; const S: string; Ptr: Pointer): TTreeNode;Добавляет узел с текстом S и объектом Ptr как последний дочерний узла Node. function AddChildObjectFirst(Node: TTreeNode; const S: siring; Ptr: Pointer): TTreeNode;Вставляет новый узел с текстом S и объектом Ptr как первый из дочерних узлов узла Node. Индексы последующих узлов увеличиваются на 1.

Объект, связанный с некоторым узлом, можно найти с помощью его свойства Data. Например, TreeView1.Items.Item[1].Data.

Для удаления узлов имеется два метода: Clear, очищающий все дерево, и Delete(Node: TTreeNode), удаляющий указанный узел Node и все его узлы — потомки. Например, оператор TreeView1.Items.Clear; удалит в нашем примере все узлы, а оператор TreeView1.Items.Delete(TreeView1.Items.Item[1]); удалит узел «цех 1» и его дочерние узлы (если они имеются).

При удалении узлов, связанных с объектами, сами эти объекты не удаляются.

Реорганизация дерева, связанная с созданием или удалением многих узлов, может вызывать неприятное мерцание изображения. Избежать этого можно с помощью методов BeginUpdate и EndUpdate. Первый из них запрещает перерисовку дерева, а второй — разрешает. Таким образом, изменение структуры дерева может осуществляться по следующей схеме: TreeView1.Items.BeginUpdate; <операторы изменения дерева> TreeView1.Items.EndUpdate;

Если метод BeginUpdate применен подряд несколько раз, то перерисовка дерева произойдет только после того, как столько же раз будет применен метод EndUpdate.

Среди свойств узлов следует отметить Count — число узлов, управляемых данным, т.е. дочерних узлов, их дочерних узлов и т.п. Если значение Count узла равно нулю, значит у узла нет дочерних узлов, т.е. он является листом дерева.

Вернемся к свойствам компонента TreeView. Важным свойством компонента TreeView является Selected. Это свойство указывает узел, который выделен пользователем. Пользуясь этим свойством можно запрограммировать операции, которые надо выполнить для выбранного пользователем узла. Если ни один узел не выбран, значение Selected равно nil. При выделении пользователем нового узла происходят события OnChanging (перед изменением выделения). В обработчик события передаются параметры Node: TTreeNode — узел, который выделен в данный момент, и var AllowChange: Boolean — разрешение на перенос выделения. Если в обработчике задать AllowChange = false, то переключение выделения не произойдет.

У компонента TreeView имеется свойство RightClickSelect, разрешающее (при значении равном true) выделение узла щелчком как левой, так и правой кнопкой мыши.

Ряд событий компонента TreeView связан с развертыванием и свертыванием узлов. При развертывании узла происходят события OnExpanding (перед развертыванием) и OnExpanded (после развертывания). В обработчики обоих событий передается параметр Node: TTreeNode — развертываемый узел. Кроме того в обработчик OnExpanding передается параметр var AllowExpansion: Boolean, который можно задать равным false, если желательно запретить развертывание. При свертывании узла происходят события OnCollapsing (перед свертыванием) и OnCollapsed (после свертывания). Так же, как и в событиях, связанных с развертыванием, в обработчики передается параметр Node: TTreeNode — свертываемый узел, а в обработчик OnCollapsing дополнительно передается параметр var AllowCollapse: Boolean, разрешающий или запрещающий свертывание.

Свойство ReadOnly компонента TreeView позволяет запретить пользователю редактировать отображаемые данные. Если редактирование разрешено, то при редактировании возникают события OnEditing и OnEdited, аналогичные рассмотренным ранее (в обработчике OnEditing параметр var AllowEdit: Boolean позволяет запретить редактирование).

Ряд свойств компонента TreeView: ShowButtons, ShowLines, ShowRoot отвечают за изображение дерева и позволяют отображать или убирать из него кнопки, показывающие раскрытия узла, линии, связывающие узлы, и корневой узел. Поэкспериментируйте с этими свойствами и увидите, как они влияют на изображение.

Свойство SortType позволяет автоматически сортировать ветви и узлы дерева. По умолчанию это свойство равно stNone, что означает, что дерево не сортируется. Если установить SortType равным stText, то узлы будут автоматически сортироваться по алфавиту. Возможно также проводить сортировку по связанным с узлами объектам Data (значение SortType равно stData), одновременно по тексту и объектам Data (значение SortType равно stBoth) или любым иным способом. Для использования этих возможностей сортировки надо написать обработчик события OnСompare, в который передаются, в частности, параметры Node1 и Node2 — сравниваемые узлы, и по ссылке передается целый параметр Compare, в который надо заносить результат сравнения: отрицательное число, если узел Node1 должен располагаться ранее Node2, 0, если эти узлы считаются эквивалентными, и положительное число, если узел Node1 должен располагаться в дереве после Node2. Например, следующий оператор в обработчике события OnCompare обеспечивает обратный алфавитный порядок расположения узлов: Compare := - AnsiCompareText(Node1.Text, Node2.Text);

События OnCompare наступают после задания любого значения SortType, отличного от stNone, и при изменении пользователем свойств узла (например, при редактировании им надписи узла), если значение SortType не равно stNone. После сортировки первоначальная последовательность узлов в дереве теряется. Поэтому последующее задание SortType = stNone не восстанавливает начальное расположение узлов, но исключает дальнейшую генерацию событий OnCompare, т.е. автоматическую перестановку узлов, например, при редактировании их надписей. Если же требуется изменить характер сортировки или провести сортировку с учетом новых созданных узлов, то надо сначала задать значение SortType = stNone, а затем задать любое значение SortType, отличное от stNone. При этом будут сгенерированы новые обращения к обработчику событий OnCompare.

Имеются и другие возможности сортировки. Например, метод AlphaSort обеспечивает алфавитную последовательность узлов независимо от значения SortType, но при отсутствии обработчика событий OnCompare (если обработчик есть, то при выполнении метода AlphaSort происходит обращение к этому обработчику). Отличие метода AlphaSort от задания значения SortType = stText заключается в том, что изменение надписей узлов приводит к автоматической пересортировке дерева только при SortType = stText.

Мы рассмотрели основные возможности компонента TreeView. Компонент Outline похож на него. Структура дерева тоже содержится в свойстве Items и доступ к отдельным узлам также осуществляется через этот индексный список узлов. Но индексы начинаются с 1. Например, Outline1.Items[1] — это узел дерева с индексом 1 (первый узел дерева). Свойство Items имеет тип TOutlineNode. Его свойства и методы отличаются от свойств и методов типа узлов в TreeView. И заполняется структура дерева иначе: через свойство Lines типа TStrings. Редактор этого свойства можно вызвать, щелкнув на кнопке с многоточием около свойства Lines в окне Инспектора Объектов. Вы попадете в окно, в котором можете записать тексты всех узлов, делая отступы, чтобы выделить уровни узлов. Текст должен выглядеть так, как выше описывалось представление структуры в текстовом файле.

Пиктограммы, сопровождающие изображения узлов, задаются параметрами PictureOpen (пиктограмма развернутого узла), PictureClosed (пиктограмма свернутого узла), PictureMinus (пиктограмма символа «-» около развернутого узла, имеющего наследников), PicturePlus (пиктограмма символа «+» узла, имеющего наследников, но не развернутого), PictureLeaf (пиктограмма узла, не имеющего наследников — листа дерева). Основное отличие пиктограмм компонента Outline заключается в том, что они одинаковы для всех узлов одного типа, тогда как в TreeView можно задавать пиктограммы индивидуально для каждого узла.

Программно изменять структуру дерева можно с помощью методов Add, AddObject (добавление узла в дерево), Insert, InsertObject (вставка узла в заданную позицию), AddChild, AddChildObject (вставка дочернего узла), Delete (удаление узла).

Индекс выделенного пользователем узла можно определить через свойство SelectedItem. Если SelectedItem = 0, значит ни один узел не выделен. Текст выделенного узла определяется свойством Text: например, OutLine1.Items[Outline1.SelectedItem].Text

Впрочем, тот же самый текст даст и выражение OutLine1.Lines[Outline1.SelectedItem-1]

В заключение коротко рассмотрим компонент ListView. Он позволяет отображать в стиле Windows 95/98 данные в виде списков, таблиц, крупных и мелких пиктограмм. С подобным отображением все вы сталкиваетесь, раскрывая папки Windows.

Стиль отображения информации определяется свойством ViewStyle, которое может устанавливаться в процессе проектирования или программно во время выполнения. Свойство может принимать значения: vsIcon — крупные значки, vsSmallIcon — мелкие значки, vsList — список, vsReport — таблица. Что означает каждое из этих значений вы можете посмотреть в любой папке Windows на рабочем столе.

Окно редактора заголовков

После того, как вы добавили секцию и установили на ней курсор, в окне Инспектора Объектов появится множество свойств этого объекта. В свойстве Text вы можете задать текст заголовка. Свойства MinWidth и MaxWidth определяют соответственно минимальную и максимальную ширину секции в пикселях. Только в этих пределах пользователь может изменять ширину секции курсором мыши. Значение ширины по умолчанию задается значением свойства Width. При изменении ширины секции во время выполнения генерируется событие OnSectionResize. В обработчик этого события надо вставить операторы, синхронно изменяющие ширину того, заголовком чего является секция: это может быть столбец какой-то таблицы, какая-то панель и т.п.

Свойство AllowClick, равное по умолчанию true, определяет поведение секции как кнопки при щелчке пользователя на ней. В этом случае при щелчке генерируется событие OnSectionСlick компонента HeaderControl, в обработчик которого и надо вставить операторы, выполняющие необходимые действия.

Свойство Style может иметь значение hsText — в этом случае в заголовке отображается значение свойства Text, или hsOwnerDraw — в этом случае отображается то, что рисуется непосредственно на канве операторами, записанными в обработчике события OnDrawSection компонента HeaderControl.

Компонент Header обладает существенно меньшими возможностями, чем HeaderControl. В нем свойство Sections имеет тип TStrings и содержит только тексты заголовков, не позволяя регулировать пределы изменения ширины секций, их функционирование как кнопок и т.д. Таким образом, Header имеет смысл использовать только в Delphi 1.

Отображение текста в надписях компонентов Label, StaticText и Panel


Для отображения различных надписей на форме используются в основном компоненты Label, StaticText (появившийся только в Delphi 3) и Panel. Первые два из этих компонентов — метки, специально предназначенные для отображения текстов. Основное назначение панели Panel другое: компоновка компонентов в окне формы. Однако, панель можно использовать и для вывода текстов.

Примеры вывода текста в компоненты приведены на Рисунок 3.4.

Тексты, отображаемые в перечисленных компонентах, определяются значением их свойства Caption. Его можно устанавливать в процессе проектирования или задавать и изменять программно во время выполнения приложения. Например: Label1.Caption := 'Новый текст';

Если требуется отобразить числовую информацию, можно воспользоваться функциями FloatToStr и IntToStr, переводящими соответственно числа с плавающей запятой и целые в строку. Для формирования текста, состоящего из нескольких фрагментов, можно использовать операцию «+», которая для строк означает их склеивание (конкатенацию). Например, если в программе имеется целая переменная I, отображающая число сотрудников некоторой организации, то вывести в метку Label1 информацию об этом можно оператором: Label1.Caption := 'Число сотрудников: '+IntToStr(I);

Во всех компонентах цвет фона определяется свойством Color, а цвет надписи — подсвойством Color свойства Font. Например, в большинстве меток (кроме верхней) на Рисунок 3.4 а и в правых метках на Рисунок 3.4 б задан цвет фона равным clWhite — белый. Если цвет специально не задавать, то цвет фона обычно сливается с цветом контейнера, содержащего метку, так что фон просто не заметен.

Для метки Label цвет и шрифт — единственно доступные элементы оформления надписи. Компоненты StaticText и Panel имеют кроме того свойство BorderStyle, определяющее рамку текста — бордюр. На Рисунок 3.4 б вы можете видеть влияние бордюра на вид метки StaticText. При стиле sbsNone метка StaticText по виду не отличается от метки Label. Вероятно, если уж использовать бордюр, то наиболее приятный стиль sbsSunken.



Перечень компонентов


Ниже будут рассмотрены компоненты секционированного отображения текстов (заголовков) и компоненты отображения иерархических данных. Перечень этих компонентов дается в таблице 3.3.

Таблица 3.3. Компоненты отображения секционированных текстов и иерархических данных
Пикто-
грамма
КомпонентСтраницаОписание
HeaderControl
(заголовок)
Win32Создание составных перемещаемых заголовков в стиле Windows 95/98.
Header
(заголовок)
Win3.1Создание составных перемещаемых заголовков. 16-битный вариант компонента HeaderControl.
TreeView
(окно дерева данных)
Win32Просмотр структуры иерархических данных в стиле Windows 95/98.
ListView
(список данных в стиле Windows 95)
Win32Отображение в стиле Windows 95/98 списков в колонках или в виде пиктограмм.
Outline
(окно дерева данных)
Win3.1Просмотр структуры иерархических данных в стиле Windows 3.x.

На Рисунок 3.18 приведены примеры перечисленных в таблице компонентов.



Перечень компонентов ввода и отображения текстовой информации


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

Таблица 3.1. Компоненты ввода и отображения текстовой информации
Пикто-
грамма
КомпонентСтраницаОписание
Label
(метка)
StandardОтображение текста, который не изменяется пользователем. Никакого оформления текста не предусмотрено, кроме цвета метки и текста. Основное свойство — Caption.
StaticText
(метка с бордюром)
AdditionalПодобен компоненту Label, но обеспечивает возможность задания стиля бордюра. Основное свойство — Caption.
Panel
(панель)
StandardКомпонент является контейнером для группирования органов управления, но может использоваться и для отображения текста с возможностями объемного оформления. Основное свойство — Caption.
Edit
(окно редактирования)
StandardОтображение, ввод и редактирование однострочных текстов. Имеется возможность оформления объемного бордюра. Основное свойство — Text.
MaskEdit
(окно маскированного редактирования)
AdditionalИспользуется для форматирования данных или для ввода символов в соответствии с шаблоном. Основные свойства — Text и EditText.
Memo
(многострочное окно редактирования)
StandardОтображение, ввод и редактирование многострочных текстов. Имеется возможность оформления объемного бордюра. Основное свойство — Lines.
RichEdit
(многострочное окно редактирования в формате RTF)
Win32Компонент представляет собой окно редактирования в стиле Windows 95 в обогащенном формате RTF, позволяющее производить выбор атрибутов шрифта, поиск текста и многое другое. Основное свойство — Lines.
ListBox
(окно списка)
StandardОтображение стандартного окна списка Windows, позволяющего пользователю выбирать из него пункты. Основное свойство — Items.
CheckListBox
(список с индикаторами)
AdditionalКомпонент является комбинацией свойств списка ListBox и индикаторов CheckBox в одном компоненте.
ComboBox
(редактируемый список)
StandardОбъединяет функции ListBox и Edit. Пользователь может либо ввести текст, либо выбрать его из списка. Основное свойство — Items.
StringGrid
(таблица строк)
AdditionalОтображение текстовой информации в таблице из строк и столбцов с возможностью перемещаться по строкам и столбцам и осуществлять выбор. Основное свойство — Cells.

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



Перечень компонентов ввода и отображения чисел, дат и времени


В библиотеке визуальных компонентов Delphi существует ряд компонентов, позволяющих вводить, отображать и редактировать числа, даты и время. Конечно, с подобной информацией можно обращаться и просто как с текстовой, используя компоненты, описанные в разделе 3.3. Но это не удобно, так как не гарантирует от ошибок при вводе. В таблице 3.2 приведен перечень специализированных, компонентов ввода и отображения чисел, дат и времени с краткими характеристиками и указанием основных параметров, содержащих отображаемый или вводимый текст. В этой таблице не указаны аналогичные элементы отображения и редактирования текстов, содержащихся в базах данных, так как их рассмотрение выходит за рамки данной книги.

Таблица 3.2. Компоненты ввода и отображения чисел, дат и времени
Пикто-
грамма
КомпонентСтраницаОписание
UpDown
(кнопка-счетчик)
Win32Кнопка-счетчик в стиле Windows 95, в сочетании с компонентами Edit и другими позволяющая вводить цифровую информацию. Основное свойство — Position.
SpinEdit
(кнопка-счетчик с окном редактирования)
SamplesОкно редактирования в комбинации с кнопкой-счетчиком. Почти то же, что комбинация Edit и UpDown. Основное свойство — Value.
DateTimePicker
(окно ввода дат и времени)
Win32Ввод даты (с выпадающим календарем) и времени. Основные свойства — Date и Time.
MonthCalendar
(окно ввода дат)
Win32Ввод дат с выбором из календаря.
Calendar
(календарь на указанный месяц)
SamplesОтображение календаря на указанный месяц. Компонент DateTimePicker имеет больше возможностей по вводу дат, чем этот компонент. Основные свойства — Month и Day.
F1Book
(страницы Excel)
ActiveXКомпонент ввода и обработки числовой информации, аналогичный страницам Excel.



Приложение с компонентом F1Book

Перенесите на форму компонент F1Book и щелкните на нем правой кнопкой мыши. Выберите из всплывшего меню команду Workbook Designer. Перед вами появится диалоговое окно проектирования, представленное на Рисунок 3.15. Те, кто знаком с программой Excel, могут увидеть, что это окно является несколько упрощенным вариантом Excel. Проектирование таблицы производится фактически по тем же правилам, что и в Excel. Вы можете писать в ячейках необходимые надписи, задавая шрифт, его стиль, обрамление. Можете записывать формулы. Так на Рисунок 3.14 и 3.15 последний столбец представляет собой стоимость соответствующего товара, являющуюся произведением его количества на его цену. А ячейка внизу таблицы суммирует стоимость всех товаров.


Пример компонента StringGrid


Компонент StringGrid предназначен в первую очередь для отображения таблиц текстовой информации. Однако в поясняется, как этот компонент может отображать и графическую информацию.

Основные свойства компонента, определяющие отображаемый текст:

Cells[ACol, ARow: Integer]: stringСтрока, содержащаяся в ячейке с индексами столбца и строки ACol и ARow. Cols[Index: Integer]: TStringsСписок строк, содержащихся в столбце с индексом Index. Rows[Index: Integer]: TStringsСписок строк, содержащихся в строке с индексом Index. Objects [ACol, ARow: Integer]: TObject;Объект, связанный со строкой, содержащейся в ячейке с индексами столбца и строки ACol и ARow.

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

Свойства ColCount и RowCount определяют соответственно число столбцов и строк, свойства FixedCols и FixedRows — число фиксированных, не прокручиваемых столбцов и строк. Цвет фона фиксированных ячеек определяется свойством FixedColor. Свойства LeftCol и TopRow определяют соответственно индексы первого видимого на экране в данный момент прокручиваемого столбца и первой видимой прокручиваемой строки.

Свойство ScrollBars определяет наличие в таблице полос прокрутки. Причем полосы прокрутки появляются и исчезают автоматически в зависимости от того, помещается таблица в соответствующий размер, или нет.

Свойство Options является множеством, определяющим многие свойства таблицы: наличие разделительных вертикальных и горизонтальных линий в фиксированных (goFixedVertLine и goFixedHorzLine) и не фиксированных (goVertLine и goHorzLine) ячейках, возможность для пользователя изменять с помощью мыши размеры столбцов и строк (goColSizing и goRowSizing), перемещать столбцы и строки (goColMoving и goRowMoving) и многое другое. Важным элементом в свойстве Options является goEditing — возможность редактировать содержимое таблицы.

В основном компонент StringGrid используется для выбора пользователем каких-то значений, отображенных в ячейках. Свойства Col и Row показывают индексы столбца и колонки выделенной ячейки. Возможно также выделение пользователем множества ячеек, строк и столбцов.

Среди множества событий компонента StringGrid следует отметить событие OnSelectСell, возникающее в момент выбора пользователем ячейки. В обработчик этого события передаются целые параметры ACol и ARow — столбец и строка выделенной ячейки, и булев параметр CanSelect — допустимость выбора. Параметр CanSelect можно использовать для запрета выделения ячейки, задав его значение false. А параметры ACol и ARow могут использоваться для какой-то реакции программы на выделение пользователя. Например, оператор Label1.Caption:='Выбрана ячейка ' +IntToStr(ARow)+':'+IntToStr(ACol); выдаст в метку Label1 номер выбранной ячейки. А оператор Label1.Caption :=StringGrid1.Cells [ACol, ARow]; выведет в ту же метку текст выделенной ячейки. Конечно, в реальном приложения задача заключается не в том, чтобы вывести подобные тексты при выборе пользователем той или иной ячейки, а в том, чтобы сделать нечто более полезное.

Пример компонентов UpDown и SpinEdit

Компонент UpDown превращает Edit в компонент, в котором пользователь может выбирать целое число, изменяя его кнопками со стрелками. Если к тому же установить в true свойство окна ReadOnly, то пользователь просто не сможет ввести в окно какой-либо свой текст и вынужден будет ограничиться выбором числа. Компонент SpinEdit представляет собой сочетание Edit и UpDown, оформленное как отдельный тип компонента.

Основное свойство компонента UpDownAssociate, связывающее кнопки со стрелками с одним из оконных компонентов, обычно с Edit. Чтобы опробовать компонент UpDown, перенесите на форму его и окно редактирования Edit, расположив Edit там, где это требуется, а UpDown — в любом месте формы. Далее в выпадающем списке свойства Associate компонента UpDown выберите Edit1. Компонент UpDown немедленно переместится к Edit и как бы сольется с ним.

Свойство AlignButton компонента UpDown, которое может принимать значения udLeft или udRight, определяет, слева или справа от окна будут размещаться кнопки. Свойство Orientation, которое может принимать значения udHorizontal или udVertical, определяет, расположатся ли кнопки по вертикали (одна под другой — см. левый компонент на Рисунок 3.12) или по горизонтали (одна рядом с другой — см. правый компонент на Рисунок 3.12). Свойство ArrowKeys определяет, будут ли управлять компонентом клавиши клавиатуры со стрелками. Свойство Thousands определяет наличие или отсутствие разделительного пробела между каждыми тремя цифрами разрядов вводимого числа.

Свойства Min и Мах компонента UpDown задают соответственно минимальное и максимальное значения чисел, свойство Increment задает приращение числа при каждом нажатии на кнопку. Свойство Position определяет текущее значение числа. Это свойство можно читать, чтобы узнать, какое число задал пользователь. Его можно задать во время проектирования в диапазоне MinМах. Тогда это будет значение числа по умолчанию, отображаемое в окне в начале выполнения приложения.

Свойство Wrap определяет, как ведет себя компонент при достижении максимального или минимального значений. Если Wrap = false, то при увеличении или уменьшении числа до максимального или минимального значения это число фиксируется на предельном значении и нажатие кнопки, пытающейся увеличить максимальное число или уменьшить минимальное, ни к чему не приводит. Если же Wrap = true, то попытка превысить максимальное число приводит к его сбросу на минимальное значение. Аналогично, попытка уменьшить минимальное число приводит к его сбросу на максимальное значение. Т.е. изменение чисел «закольцовывается».

Если в компоненте Edit, связанном с UpDown, не задать ReadOnly равным true, то пользователь сможет редактировать число, не пользуясь кнопками со стрелками. Это удобно, если требуемое число далеко от указанного по умолчанию, а шаг приращения Increment в UpDown мал. Но тут проявляется серьезный недостаток компонента UpDown: ничто не мешает пользователю ввести по ошибке не цифры, а какие-то другие символы. Чтобы избавиться от этого недостатка, можно использовать прием, описанный в , который не дает возможность пользователю ввести в окно редактирования какие-то символы, кроме цифр. Но лучше для этих целей использовать компонент SpinEdit.

Свойства компонента SpinEdit похожи на рассмотренные, только имеют другие имена: свойства Min, Max, Position называются соответственно MinValue, MaxValue, Value. В целом компонент SpinEdit во многих отношениях удобнее простого сочетания UpDown и Edit. Так что, если не требуются какие-то из описанных выше дополнительных возможностей UpDown (нестандартное расположение кнопок, «закольцовывание» изменений и т.п.), то можно рекомендовать пользоваться компонентом SpinEdit.

Пример компонентов выбора из списков


Компоненты ListBox и ComboBox отображают списки строк. Они отличаются друг от друга прежде всего тем, что ListBox только отображает данные и позволяет пользователю выбрать из них то, что ему надо, a ComboBox позволяет также редактировать данные. Кроме того различается форма отображения списков. ListBox отображает список в раскрытом виде и автоматически добавляет в список полосы прокрутки, если все строки не помещаются в окне компонента. ComboBox позволяет отображать список как в развернутом виде, так и в виде выпадающего списка, что обычно удобнее, так как экономит площадь окна приложения .

Основное свойство обоих компонентов, содержащее список строк, — Items, имеющее рассмотренный тип TStrings. Заполнить его во время проектирования можно, нажав кнопку с многоточием около этого свойства в окне Инспектора Объектов. Во время выполнения работать с этим свойством можно, пользуясь свойствами и методами класса TStrings (см. ) — Clear, Add и другими.

В компоненте ListBox имеется свойство MultiSelect, разрешающее пользователю множественный выбор в списке (на Рисунок 3.10 это свойство установлено в true в среднем верхнем списке). Если MultiSelect = false (значение по умолчанию), то пользователь может выбрать только один элемент списка. В этом случае можно узнать индекс выбранной строки из свойства ItemIndex, доступного только во время выполнения. Если ни одна строка не выбрана, то ItemIndex = -1. Начальное значение ItemIndex невозможно задать во время проектирования. По умолчанию ItemIndex = -1. Это означает, что ни один элемент списка не выбран. Если вы хотите задать этому свойству какое-то другое значение, т.е. установить выбор по умолчанию, который будет показан в момент начала работы приложения, то сделать это можно, например, в обработчике события OnCreate формы, введя в него оператор вида ListBox1.ItemIndex:=0;

Если допускается множественный выбор (MultiSelect = true), то значение ItemIndex соответствует тому элементу списка, который находится в фокусе. При множественном выборе проверить, выбран ли данный элемент, можно проверив свойство Selected[Index: Integer] типа Boolean.

На способ множественного выбора при MultiSelect = true влияет еще свойство ExtendedSelect. Если ExtendedSelect = true, то пользователь может выделить интервал элементов, выделив один из них, затем нажав клавишу Shift и переведя курсор к другому элементу. Выделить не прилегающие друг к другу элементы пользователь может, если будет удерживать во время выбора нажатой клавишу Ctrl. Если же ExtendedSelect = false, то клавиши Shift и Ctrl при выборе не работают.

Свойство Columns определяет число столбцов, в которых будет отображаться список, если он не помещается целиком в окне компонента ListBox (в среднем верхнем списке на Рисунок 3.10 свойство Columns равно 2).

Свойство Sorted позволяет упорядочить список по алфавиту. При Sorted = true новые строки в список добавляются не в конец, а по алфавиту.

Свойство Style, установленное в lbStandard (значение по умолчанию) соответствует списку строк. Другие значения Style позволяют отображать в списке не только текст, но и изображения.

Имеется еще один компонент, очень похожий на ListBox — это список с индикаторами CheckListBox. Выглядит он так же, как ListBox (средний нижний список на Рисунок 3.10), но около каждой строки имеется индикатор, который пользователь может переключать. Индикаторы можно переключать и программно, если список используется для вывода данных и необходимо в нем отметить какую-то характеристику каждого объекта, например, наличие товара данного наименования на складе.

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

Рассмотрим теперь компонент ComboBox. Стиль изображения этого компонента определяется свойством Style, которое может принимать следующие основные значения:

csDropDownВыпадающий список со строками одинаковой высоты и с окном редактирования, позволяющим пользователю вводить или редактировать текст (правый список на Рисунок 3.10). csSimpleРазвернутый список со строками одинаковой высоты и с окном редактирования, позволяющим пользователю вводить или редактировать текст (левый нижний список на Рисунок 3.10). csDropDownListВыпадающий список со строками одинаковой высоты, не содержащий окна редактирования.

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

Если в окне проводилось редактирование данных, то ItemIndex = -1. По этому признаку можно определить, что редактирование проводилось.

Свойство MaxLength определяет максимальное число символов, которые пользователь может ввести в окно редактирования.

Если MaxLength = 0, то число вводимых символов не ограничено.

Как и в компоненте ListBox, свойство Sorted позволяет упорядочить список по алфавиту. При Sorted = true новые строки в список добавляются не в конец, а по алфавиту.

Пример редактора на основе компонента RichEdit

Основное свойство окон Memo и RichEditLines, содержащее текст окна в виде списка строк и имеющее тип TStrings. Начальное значение текста можно установить в процессе проектирования, нажав кнопку с многоточием около свойства Lines в окне Инспектора Объектов. Перед вами откроется окно редактирования списков строк, представленное на Рисунок 3.9. Вы можете редактировать или вводить текст непосредственно в этом окне, или нажать кнопку CodeEditor и работать в обычном окне Редактора Кода. В этом случае, завершив работу с текстом, выберите из контекстного меню, всплывающего при щелчке правой кнопкой мыши, команду Close Page и ответьте утвердительно на вопрос, хотите ли вы сохранить текст в соответствующем свойстве окна редактирования.

В Delphi 1 аналогичное окно имеет еще кнопки, позволяющие загрузить текст из файла или сохранить его в файле.


Примеры компонентов Memo и RichEdit


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

Компонент RichEdit работает с текстом в обогащенном формате RTF. При желании изменить атрибуты вновь вводимого фрагмента текста вы можете задать свойство SelAttributes. Это свойство типа TTextAttributes, которое в свою очередь имеет подсвойства: Color (цвет), Name (имя шрифта), Size (размер), Style (стиль) и ряд других. Например, введите на форму компонент RichEdit, диалог выбора шрифта FontDialog (см. ) и кнопку Button, которая позволит пользователю менять атрибуты текста. В обработчик щелчка кнопки можно было бы ввести текст: if FontDialog1.Execute then with RichEdit1.SelAttributes do begin Color:=FontDialog1.Font.Color; Name:=FontDialog1.Font.Name; Size:=FontDialog1.Font.Size; Style:=FontDialog1.Font.Style; end; RichEdit1.SetFocus;

В приведенном коде присваивается поочередно значение каждого свойства. Но этот текст можно кардинально сократить, воспользовавшись тем, что объекты SelAttributes и Font совместимы по типу. Поэтому можно присвоить сразу все свойства одного объекта другому: if FontDialog1.Execute then RichEdit1.SelAttributes.Assign(FontDialog1.Font); RichEdit1.SetFocus;

Запустите приложение и увидите, что вы можете менять атрибуты текста, выполняя отдельные фрагменты различными шрифтами, размерами, цветами, стилями. Устанавливаемые атрибуты влияют на выделенный текст или, если ничего не выделено, то на атрибуты нового текста, вводимого начиная с текущей позиции курсора (позиция курсора определяется свойством SelStart).

В компоненте имеется также свойство DefAttributes, содержащее атрибуты по умолчанию. Эти атрибуты действуют до того момента, когда изменяются атрибуты в свойстве SelAttributes.

Но значения атрибутов в DefAttributes сохраняются и в любой момент эти значения могут быть методом Assign присвоены атрибутам свойства SelAttributes, чтобы вернуться к прежнему стилю.

Свойство DefAttributes доступно только во время выполнения. Поэтому его атрибуты при необходимости можно задавать, например, в обработчике события OnCreate.

За выравнивание, отступы и т.д. в пределах текущего абзаца отвечает свойство Paragraph типа TParaAttributes. Этот тип в свою очередь имеет ряд свойств:

AlignmentОпределяет выравнивание текста. Может принимать значения taLeftJustify (влево), taCenter (по центру) или taRightJustify (вправо). FirstIndentЧисло пикселей отступа красной строки. NumberingУправляет вставкой маркеров, как в списках. Может принимать значения nsNone — отсутствие маркеров, nsBullet — маркеры ставятся. LeftIndentОтступ в пикселях от левого поля. RightIndentОтступ в пикселях от правого поля. TabCountКоличество позиций табуляции. TabЗначения позиций табуляции в пикселях.

Значения подсвойств свойства Paragraph можно задавать только в процессе выполнения приложения, например, в событии создания формы или при нажатии какой-нибудь кнопки. Значения подсвойств свойства Paragraph относятся к тому абзацу, в котором находится курсор. Например, каждый из следующих операторов осуществит соответственное выравнивание текущего абзаца: RichEdit1.Paragraph.Alignment:=taLeftJustify; // Влево RichEdit1.Paragraph.Alignment:=taCenter; // По центру RichEdit1.Paragraph.Alignment:=taRightJustify;// Вправо

Следующий оператор приведет к тому, что текущий абзац будет отображаться как список, т.е. с маркерами: RichEdit1.Paragraph.Numbering:=nsBullet;

Уничтожение списка в текущем абзаце осуществляется оператором RichEdit1.Paragraph.Numbering:=nsNone;

В целом, если с помощью компонента ActionList (см. ) определено некоторое действие ввода и уничтожения списка, названное ABullet, то операторы обработки соответствующего действия могут иметь вид: if (ABullet.Checked) then RichEdit1.Paragraph.Numbering:=nsNone else RichEdit1.Paragraph.Numbering :=nsBullet; ABullet.Checked:=not ABullet.Checked;

Они обеспечивают переключение соответствующей быстрой кнопки и раздела меню из нажатого состояния (отмеченного) в ненажатое с соответствующим изменением вида текущего абзаца.

Свойства TabCount и Tab имеют смысл при вводе текста только при значении свойства компонента WantTabs = true. Это свойство разрешает пользователю вводить в текст символ табуляции. Если WantTabs = false, то нажатие пользователем клавиши табуляции просто переключит фокус на очередной компонент и символ табуляции в текст не введется.

Мы рассмотрели основные отличия Memo и RichEdit. Теперь остановимся на общих свойствах этих окон редактирования.

Свойства Alignment и WordWrap имеют тот же смысл, что, например, в метках, и определяют выравнивание текста и допустимость переноса длинных строк. Установка свойства ReadOnly в true задает текст только для чтения. Свойство MaxLength определяет максимальную длину вводимого текста. Если MaxLength = 0, то длина текста не ограничена. Свойства WantReturns и WantTab определяют допустимость ввода пользователем в текст символов перевода строки и табуляции.

Свойство ScrollBars определяет наличие полос прокрутка текста в окне. По умолчанию ScrollBars = ssNone, что означает их отсутствие. Пользователь может в этом случае перемещаться по тексту только с помощью курсора. Можно задать свойству ScrollBars значения ssHorizontal, ssVertical или ssBoth, что будет соответственно означать наличие горизонтальной, вертикальной или обеих полос прокрутки.

В качестве примера на Рисунок 3.8 приведен пример текстового редактора, использующего описанные выше свойства компонента RichEdit. Текст в окне редактора частично поясняет атрибуты шрифта, использованные при его написании.

Примеры компонентов отображения дат и времени

Из этих компонентов наиболее удобным является DateTimePicker (на Рисунок 3.13, слева вверху показан этот компонент в режиме ввода времени, а ниже — в двух вариантах режима ввода даты). Компонент очень эффектен за счет появления выпадающего календаря (иногда даже слишком эффектен для строго оформленного приложения) и обеспечивает безошибочный с точки зрения синтаксиса ввод дат и времени. Его свойство Kind определяет режим работы компонента: dtkDate — ввод даты, dtkTime — ввод времени.

При вводе дат можно задать свойство DateMode равным dmComboBox — наличие выпадающего календаря, или равным dmUpDown — наличие кнопок увеличения и уменьшения (см. средний компонент DateTimePicker на Рисунок 3.13), напоминающих те, которые используются в описанных ранее компонентах UpDown и SpinEdit. Только в данном случае пользователь может независимо устанавливать с помощью кнопок число, месяц и год. Формат представления дат определяется свойством DateFormat, которое может принимать значения dfShort — краткий формат (например, 01.12.99), или dfLong — полный формат (например, 1 декабря 1999 г.).

Значение даты по умолчанию можно задать в Инспекторе Объектов через свойство Date. Это же свойство читается для определения заданной пользователем даты. При чтении Date надо учитывать тип этого свойства — TDateTime, представляющий собой число с плавающей запятой, целая часть которого содержит число дней, отсчитанное от некоторого начала календаря, а дробная часть равна части 24-часового дня, т.е. характеризует время и не относится к дате. Для 32-разрядных версий Delphi за начало календаря принята дата 12/30/1899 00 часов. В Delphi 1 за начало отсчета принят год 1, т.е. для перевода даты Delphi 1 в дату последующих версий Delphi надо вычесть из даты число 693594.

Для преобразования значения свойства Date в строку можно воспользоваться функцией DateToStr. Например, оператор Memol.Lines.Add('Дата: ' + DateToStr (DateTimePicker1.Date)); добавит в окно Memo1 строку вида «Дата: 01.12.98».

При вводе дат можно задать значения свойств MaxDate и MinDate, определяющих соответственно максимальную и минимальную дату, которую может задать пользователь.

В режиме ввода времени dtkTime введенное пользователем значение можно найти в свойстве Time, тип которого — тот же рассмотренный выше TDateTime. Преобразовать время в строку можно функцией TimeToStr.

Компонент MonthCalendar похож на компонент DateTimePicker, работающий в режиме ввода дат. Правда, в компоненте MonthCalendar предусмотрены некоторые дополнительные возможности: можно допустить множественный выбор дат в некотором диапазоне (свойство MultiSelect), можно указывать в календаре номера недель с начала года (свойство WeekNumbers), перестраивать календарь, задавая первый день каждой недели (свойство FirstDayOfWeek) и т.п. Для некоторых офисных приложений все это достаточно удобно.

Компонент Calendar представляет собой менее красочный и более обыденно оформленный календарь на один месяц. Вместо свойства Date в нем предусмотрены отдельные свойства Year -год, Month — месяц, Day — день. Все это целые числа, с которыми иногда удобнее иметь дело, чем с типом TDateTime. Перед отображением на экране или в процессе проектирования надо задать значения Month и Year, чтобы компонент отобразил календарь на указанный месяц указанного года. Впрочем, если вам надо иметь календарь на текущий месяц, надо установить в true значение свойства UseCurrentDate (установлено по умолчанию). В этом случае по умолчанию будет показан календарь на текущий месяц с выделенным в нем текущим днем. Свойство StartOfWeek задает день, с которого начинается неделя. По умолчанию задано 0 — воскресенье, как это принято в западных календарях. Но для нас все-таки как-то привычнее начинать неделю с рабочего дня — понедельника. Так что желательно задать StartOfWeek = 1.

Примеры окон редактирования


В компонентах Edit и MaskEdit вводимый и выводимый текст содержится в свойстве Text. Это свойство можно устанавливать в процессе проектирования или задавать программно. Выравнивание текста, как это имело место в метках и панелях, невозможно. Перенос строк тоже невозможен. Текст, не помещающийся по длине в окно, просто сдвигается и пользователь может перемещаться по нему с помощью курсора. Свойство AutoSize в окнах редактирования имеет смысл, отличный от смысла аналогичного свойства меток: автоматически подстраивается под размер текста только высота, но не ширина окна.

Окна редактирования снабжены многими функциями, свойственными большинству редакторов. Например, в них предусмотрены типичные комбинации «горячих» клавиш: Ctrl-C — копирование выделенного текста в буфер обмена Clipboard (команда Copy), Ctrl-X — вырезание выделенного текста в буфер Clipboard (команда Cut), Ctrl-V — вставка текста из буфера Clipboard в позицию курсора (команда Paste), Ctrl-Z — отмена последней команды редактирования. Правда, пользователи часто не догадываются об этих возможностях редактирования. Так что полезно напоминать им об этом соответствующими подсказками.

Свойство AutoSelect определяет, будет ли автоматически выделяться весь текст при передаче фокуса в окно редактирования. Его имеет смысл задавать равным true в случаях, когда при переключении в данное окно пользователь будет скорее заменять текущий текст, чем исправлять его. Имеются также свойства только времени выполнения SelLength, SelStart, SelText, определяющие соответственно длину выделенного текста, позицию перед первым символом выделенного текста и сам выделенный текст. Например, если в окне имеется текст «выделение текста» и в нем пользователь выделил слово «текста», то SelLength = 6, SelStart = 10 и SelText = 'текста'. Если выделенного текста нет, то свойство SelStart просто определяет текущее положение курсора.

Окна редактирования можно использовать и просто как компоненты отображения текста. Для этого надо установить в true их свойство ReadOnly и целесообразно установить AutoSelect в false. В этом случае пользователь не сможет изменять отображаемый текст и окно редактирования становится подобным меткам, рассмотренным в . Но имеются и определенные отличия. Во-первых, окна редактирования оформлены несколько иначе (сравните Рисунок 3.4 и 3.5.). А главное — окна редактирования могут вмещать текст, превышающий их длину. В этом случае пользователь может прокручивать этот текст, перемещая курсор в окне. Такими особенностями не обладает ни одна метка.

При использовании окон редактирования для вывода, ввода и редактирования чисел необходимо использовать функции взаимного преобразования строк и чисел. Для вывода это описанные при рассмотрении функции FloatToStr и IntToStr. При вводе это функции StrToFloat — преобразование строки в значение с плавающей запятой, и StrToInt — преобразование строки в целое значение. Если вводимый текст не соответствует числу (например, содержит недопустимые символы), то функции преобразования генерируют исключение EConvertError. Поэтому в программе необходимо предусмотреть обработку этого исключения. Например: var A: integer; try A := StrToInt(Edit1.Text); ...{операторы, использующие переменную А} except on EConvertError do ShowMessage('Вы ввели ошибочное число; повторите ввод');

Этот код обеспечивает сообщение пользователю об ошибке ввода и предотвращает ошибочные вычисления. Впрочем, это не лучший вариант предотвратить ошибочный ввод, поскольку пользователь узнает о своей ошибке только после того, как программа пытается использовать введенные данные. Лучше, если пользователь просто не сможет ввести неправильные символы. Например, если вы хотите, чтобы пользователь мог вводить в окно редактирования Edit только цифры и символ точки, вы можете в обработчик события OnKeyPress этого компонента вставить оператор: if not (Key in ['0'..'9', ',']) then Key := #0;

Этот оператор подменит все символы, кроме цифр и запятой, нулевым символом, который не занесется в текст окна Edit.

Свойство MaxLength определяет максимальную длину вводимого текста. Если MaxLength = 0, то длина текста не ограничена. В противном случае значение MaxLength указывает максимальное число символов, которое может ввести пользователь.

Свойство Modified, доступное только во время выполнения, показывает, проводилось ли редактирование текста в окне. Если вы хотите использовать это свойство, то в момент начала работы пользователя с текстом Modified надо установить в false. Тогда при последующем обращения к этому свойству можно по его значению (true или false) установить, было или не было произведено редактирование.

Свойство PasswordChar позволяет превращать окно редактирования в окно ввода пароля. По умолчанию значение PasswordChar равно #0 — нулевому символу. В этом случае это обычное окно редактирования. Но если в свойстве указать иной символ (например, символ звездочки «*»), то при вводе пользователем текста в окне будут появляться именно эти символы, а не те, которые вводит пользователь (см. Рисунок 3.5). Тем самым обеспечивается секретность ввода пароля.

Компонент MaskEdit отличается от Edit тем, что в нем можно задать строку маски в свойстве EditMask. Маска состоит из трех разделов, между которыми ставится точка с запятой (;). В первом разделе — шаблоне записываются специальным образом символы (см. таблицу 3.2), которые можно вводить в каждой позиции, и символы, добавляемые самой маской; во втором разделе записывается 1 или 0 в зависимости от того, надо или нет, чтобы символы, добавляемые маской, включались в свойство Text компонента; в третьем разделе указывается символ, используемый для обозначения позиций, в которых еще не осуществлен ввод. Прочитать результат ввода можно или в свойстве Text, которое в зависимости от вида второго раздела маски включает или не включает в себя символы маски, или в свойстве EditText, содержащем введенный текст вместе с символами маски.

Таблица 3.2. Символы шаблона маски
!Наличие символа «!» означает, что в EditText недостающие символы предваряются пробелами, а отсутствие символа «!» означает, что пробелы размещаются в конце. >Символ «>» означает, что все последующие за ним символы должны вводиться в верхнем регистре, пока не кончится маска или пока не встретится символ «<». <Символ «<» означает, что все последующие за ним символы должны вводиться в нижнем регистре, пока не кончится маска или пока не встретится символ «>». <>Символы «<>» означают, что анализ регистра не производится. \Символ «\» означает, что следующий за ним символ является буквенным, а не специальным, характерным для маски. Например, символ «>» после символа «\» воспримется как знак >, а не как символ, указывающий на верхний регистр. LСимвол «L» означает, что в данной позиции должна бытъ буква. lСимвол «l» означает, что в данной позиции может быть только буква или ничего. AСимвол «А» означает, что в данной позиции должна быть буква или цифра. aСимвол «а» означает, что в данной позиции может быть буква, или цифра, или ничего. CСимвол «С» означает, что в данной позиции должен быть любой символ. cСимвол «с» означает, что в данной позиции может быть любой символ или ничего. 0Символ «0» означает, что в данной позиции должна быть цифра. 9Символ «9» означает, что в данной позиции может быть цифра или ничего. #Символ «#» означает, что в данной позиции может быть цифра, знак «+», знак «-» или ничего. :Символ «:» используется для разделения часов, минут и секунд. /Символ «/» используется для разделения месяцев, дней и годов в датах. Символ « » означает автоматическую вставку в текст пробела.

Вводить маску можно непосредственно в свойство EditMask. Но удобнее пользоваться специальным редактором масок, вызываемым при нажатии кнопки с многоточием в строке свойства EditMask в Инспекторе Объектов. Окно редактора масок имеет вид, представленный на Рисунок 3.6.

В редакторе масок окно Sample Masks содержит наименования стандартных масок и примеры ввода с их помощью. В окно Input Mask надо ввести маску. Если вы выбираете одну из стандартных масок, то окно Input Mask автоматически заполняется и вы можете, если хотите, отредактировать эту маску.

Окно Character for Blanks определяет символ, используемый для обозначения позиций, в которых еще не осуществлен ввод (третий раздел маски). Индикатор Save Literal Characters определяет второй раздел маски: установлен, если второй раздел равен 1, и не установлен, если второй раздел равен 0.

Примеры вывода текста методом TextOut

Более изящный вывод обеспечивает метод TextRect. Следующий код рисует в заданном месте канвы формы с координатами (X1,Y1,X2,Y2) красный прямоугольник и внутри него в центре пишет методом TextRect текст, введенный в переменную s. Если текст оказывается длиннее ширины прямоугольника, то он усекается. В данном примере будет видна только середина длинного текста, так как текст выровнен по центру. var s : string; X1,Y1,X2,Y2:integer; s := ... X1:=100; Y1:=100; X2:=200; Y2:=150; with Canvas do begin Brush.Color:=clRed; TextRect(Rect(X1, Y1, X2, Y2), X1+(X2-X1-TextWidth(s)) div 2, Y1+(Y2-Y1-TextHeight(s)) div 2, s) end; end;

Если в приведенном примере заменить оператор TextRect на TextRect(Rect(X1-5, Y1-5, X1+TextWidth(s)+5, Y1+TextHeight(s)+5), X1, Y1, s); то текст будет выводится полностью в красной прямоугольной области, на 5 пикселей отступающей во все стороны от текста. Именно этим отступом, делающим надпись более красивой, этот оператор отличается от всех предыдущих более простых операторов. Примеры вывода текста методом TextRect показаны на Рисунок 3.3. Вверху относительно короткий текст выровнен по середине прямоугольной рамки, в которой он рисуется. Ниже в аналогичной по размерам рамке помещен более длинный текст: «Это очень длинный текст». Вы видите, что текст урезан по размерам рамки. Внизу вы видите вывод, сделанный оператором, аналогичным приведенному выше и обеспечивающим зазор в 5 пикселей во все стороны от надписи любой длины. Очевидно, что это наиболее удачный вариант.


Примеры вывода текста методом TextRect

В целом можно сказать, что прямой вывод текста на канву описанными методами имеет смысл использовать только в исключительных случаях. Таким исключительным случаем является вывод каких-то надписей в компонент Image (см. ). Этот компонент предназначен для отображения графики. Но в тех случаях, когда на графику (на какую-то картинку) требуется наложить текст, этот текст целесообразно выводить описанными методами. В остальных случаях это делать не имеет смысла, поскольку при прямом выводе текста на канву теряются преимущества визуального проектирования и приходится рассчитывать координаты размещения надписи.

Примеры вывода текста в компоненты Label (а), StaticText (б) и Panel (в)

а)
б)
в)

Компонент Panel кроме свойства BorderStyle имеет еще свойства BevelInner, BevelOuter, BevelWidth, BorderWidth, которые предоставляют богатые возможности оформления надписи, как вы можете видеть на Рисунок 3.4 в. Таким образом, с точки зрения оформления выводимого текста максимальные возможности дает Panel и минимальные — Label.

Размещение всех рассматриваемых компонентов на форме определяется, в частности, свойствами Тор (координата верхнего края), Left (координата левого края), Height (высота), Width (ширина). Имеются также свойства, определяющие изменение размера компонента при изменении пользователем во время выполнения приложения размеров окна. Это общие свойства всех оконных компонентов: Align (выравнивание компонента по всей верхней, левой, правой, нижней частям контейнера или по всей его клиентской области), Anchors (привязка сторон компонента к сторонам контейнера), Constraints (ограничения допустимых изменений размеров). Учтите, что использование в свойстве Anchors одновременной привязки компонента к противоположным сторонам контейнера приведет к растягиванию или сжатию компонента при изменении пользователем размеров окна. При этом в метках в ряде случаев наблюдаются неприятности, связанные с перемещением надписей (если они, например, выровнены по центру). Чтобы избежать этих неприятностей, надо в обработку события формы OnResize вставить операторы, перерисовывающие компоненты методом Repaint, например: StaticText1.Repaint;

Размер меток Label и StaticText определяется также свойством AutoSize. Если это свойство установлено в true, то вертикальный и горизонтальный размеры компонента определяются размером надписи. Если же AutoSize равно false, то выравнивание текста внутри компонента определяется свойством Alignment, которое позволяет выравнивать текст по левому краю, правому краю или центру клиентской области метки. В панели Panel также имеется свойство AutoSize, но оно не относится к размерам надписи Caption. Однако, свойство выравнивания Alignment работает и для панели.

В метке Label имеется свойство Wordwrap — допустимость переноса слов длинной надписи, превышающей длину компонента, на новую строчку. Чтобы такой перенос мог осуществляться, надо установить свойство WordWrap в true, свойство AutoSize в false (чтобы размер компонента не определялся размером надписи) и сделать высоту компонента такой, чтобы в нем могло поместиться несколько строк (см. пример правой нижней метки на Рисунок 3.4 а). Если WordWrap не установлено в true при AutoSize равном false, то длинный текст, не помещающийся в рамке метки, просто обрезается (см. пример левой нижней метки на Рисунок 3.4 а).

В метке StaticText перенос длинного текста осуществляется автоматически, если значение AutoSize установлено в false и размер компонента достаточен для размещения нескольких строк. Для того, чтобы в StaticText осуществлялся перенос при изменении пользователем размеров окна, надо осуществлять описанную выше перерисовку компонента методом Repaint в обработчике события формы OnResize.

В панели размещение надписи в нескольких строках невозможно.

Можно отметить еще одно свойство меток Label и StaticText, превращающее их в некоторое подобие управляющих элементов. Это свойство FocusControl — фокусируемый компонент. Если в свойстве метки Caption поместить перед одним из символов символ амперсант «&», то символ, перед которым поставлен амперсант, отображается в надписи метки подчеркнутым (сам амперсант вообще не отображается). Если после этого обратиться к свойству метки FocusControl, то из выпадающего списка можно выбрать элемент, на который будет переключаться фокус, если пользователь нажмет клавиши ускоренного доступа: клавишу Alt + подчеркнутый символ. Подобные клавиши ускоренного доступа предусмотрены в управляющих элементах: разделах меню (см. ) и кнопках (см. ). Благодаря свойству FocusControl метки могут обеспечить клавишами ускоренного доступа иные элементы, например, окна редактирования (см. ), в которых такие клавиши не предусмотрены. Только для того, чтобы клавиши ускоренного доступа в метках срабатывали, необходимо установить свойство ShowAccelChar этих меток в true.

Для отображения текстовой информации, и даже с дополнительной возможностью прокрутки длинных текстов, можно использовать также Edit и MaskEdit в режиме Readonly.



Секционированное отображение текстов — компоненты HeaderControl и Header


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

Основное свойство компонента HeaderControlSections. Оно является списком объектов типа THeaderSection, каждый из которых описывает одну секцию заголовка. Свойство Sections можно задать во время проектирования, нажав кнопку с многоточием рядом с этим свойством в Инспекторе Объектов или просто сделав двойной щелчок на компоненте HeaderControl. В обоих случаях перед вами откроется окно редактора заголовков, представленное на Рисунок 3.19. Левая быстрая кнопка позволяет добавить новую секцию в заголовок. Следующая быстрая кнопка позволяет удалить секцию. Кнопки со стрелкой позволяют изменять последовательность секций.



Страницы Excel — компонент F1Book


Очень интересным компонентом является F1Book на странице ActiveX. Этот компонент позволяет встроить в ваше приложение таблицы типа Excel (Рисунок 3.14), которые пользователь может заполнять соответствующими числами, а компонент будет производить по заданным формулам вычисления и тут же отображать их результаты в указанных ячейках. В таблицу можно встроить диаграммы и графики различных типов. И все изменения, вносимые пользователем в данные таблицы, немедленно будут отображаться в диаграммах. Таким образом вы можете включать в свое приложение различные бланки смет, счетов, ведомостей, с которыми будет работать пользователь, различные таблицы, производящие статистические или технические расчеты и т.п.



Таблица строк — компонент StringGrid


Компонент StringGrid (см. пример на Рисунок 3.11) представляет собой таблицу, содержащую строки. Данные таблицы могут быть только для чтения или редактируемыми. Таблица может иметь полосы прокрутки, причем заданное число первых строк и столбцов может быть фиксированным и не прокручиваться. Таким образом, можно задать заголовки столбцов и строк, постоянно присутствующие в окне компонента. Каждой ячейке таблицы может быть поставлен в соответствие некоторый объект.



Тестовое приложение свойств шрифта

Разместите на форме многострочное окно редактирования Memo (см. ), в который поместите какой-нибудь текст, например, тест латинских и русских символов, показанный на Рисунок 3.1. Перенесите на форму выпадающий список ComboBox (см. ), в который будут загружаться имена шрифтов, доступных системе на данном компьютере. Назовите этот компонент CBName. Разместите еще один компонент ComboBox, который будет содержать возможные значения свойства Pitch. Назовите его CBPitch и занесите в его свойство Items строки «fpDefault», «fpFixed» и «fpVariable». Разместите на форме также компонент SpinEdit (см. ), в котором можно будет задавать численные значения свойства Charset, и кнопку Button (см. ), нажатие которой будет передавать значение, введенное пользователем в SpinEdit, в свойство шрифта Charset. Разместите на форме компонент главного меню MainMenu (см. ) и введите в меню один раздел — Шрифт, при выборе которого пользователь сможет в диалоге выбирать атрибуты шрифта, в частности, его размеры и стиль. Чтобы обеспечить диалог выбора шрифта разместите на форме также компонент FontDialog (см. ).

Расположение всех компонентов может примерно соответствовать приведенному на Рисунок 3.1. Далее надо написать обработчики событий: события OnCreate при созданий формы (FormCreate), выбора раздела меню (MFontClick), изменений в списке CBName (CBNameClick) и в списке CBPitch (CBPitchChange) и щелчка на кнопке Button1 (Button1Click). Ниже приведен текст всех этих обработчиков. procedure TForm1.FormCreate(Sender: TObject); var i: integer; begin // Загрузка в CBName всех шрифтов системы for i := 0 to Screen.Fonts.Count - 1 do CBName.Items.Add(Screen.Fonts[i]); CBName.ItemIndex := 0; CBPitch.ItemIndex := 0; // Загрузка в Memo1 имени первого шрифта Memo1.Font.Name := CBName.Items[CBName.ItemIndex]; end; procedure TForm1.MFontClick(Sender: TObject); begin // Задание диалогу текущих атрибутов шрифта Memo1 FontDialog1.Font.Assign(Memo1.Font); if (FontDialog1.Execute) then begin // Задание атрибутов шрифта, выбранных в диалоге пользователем Memo1.Font.Assign(FontDialog1.Font); CBName.Text:=Memo1.Font.Name; SpinEdit1.Value:=FontDialog1.Font.CharSet; end end; procedure TForm1.CBNameChange(Sender: TObject); begin // Изменение свойства Name Memo1.Font.Name := CBName.Items[CBName.ItemIndex]; end; procedure TForm1.CBPitchChange(Sender: TObject); begin // Изменение свойства Pitch case CBPitch.ItemIndex of 0: Memo1.Font.Pitch := fpDefault; 1: Memo1.Font.Pitch := fpFixed; 2: Memo1.Font.Pitch := fpVariable; end; end; procedure TForm1.Button1Click(Sender: TObject); begin // Изменение свойства CharSet Memo1.Font.CharSet := SpinEdit1.Value; end;

Комментарии в тексте поясняют отдельные операции. Запустите приложение и исследуйте шрифты, зарегистрированные в системе, и влияние на них свойств Pitch и Charset.

Ввод и отображение целых чисел — компоненты UpDown и SpinEdit


В Delphi имеются специализированные компоненты, обеспечивающие ввод целых чисел — UpDown и SpinEdit (см. пример на Рисунок 3.12).



Ввод и отображение дат и времени – компоненты DateTimePicker, MonthCalendar, Calendar


Примеры компонентов ввода и отображение дат и времени приведены на Рисунок 3.13.



Вывод текста на канву Canvas


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

При выводе текста на канву фон надписи определяется свойством канвы Brush — кисть. Это свойство является в свою очередь объектом, который может хранить в своем свойстве Style некий шаблон заполняющей штриховки. Но по умолчанию этот шаблон соответствует сплошной закраске фона. А свойство кисти Color задает цвет фона. Атрибуты выводимого текста определяются рассмотренным в свойством канвы Font.

Вывод текста на канву может осуществляться методом TextOut, объявленным следующим образом: procedure TextOut(X, Y: Integer; const Text: string); Процедура TextOut пишет строку текста Text на канве, начиная с позиции с координатами (X, Y). Если цвет кисти Brush в момент вывода текста отличается от того, которым закрашена канва, то текст получится выведенным в цветной прямоугольной рамке. Но ее размеры будут точно равны размерам надписи. Если требуется более красивая рамка с отступом от текста, следует применять другой метод — TextRect. Этот метод определен следующим образом: procedure TextRect (Rect :TRect; X, Y: Integer; const Text: string);

Процедура TextRect пишет строку текста Text на канве, начиная с позиции с координатами (X, Y) — это левый верхний угол надписи. Параметр Rect типа TRect определяет прямоугольную рамку, в которую вписывается текст. Тип TRect определен следующим образом: TRect = record case Integer of 0: (Left, Top, Right, Bottom: Integer); 1: (TopLeft, BottomRight: TPoint) ; end;

Координаты задаются и как четыре целых числа, определяющих координаты в пикселях левой (Left), верхней (Тор), правой (Right) и нижней (Bottom) сторон прямоугольника, и как две точки типа TPoint, представляющие собой координаты левого верхнего и правого нижнего углов: type TPoint = record X: Longint; Y: Longint; end;

Началом координат обычно считается левый верхний угол экрана или окна.

При выводе текста методом TextRect часть текста, не помещающаяся в прямоугольную область Rect, усекается.

Надписи и в методе TextOut, и в методе TextRect делаются в соответствии с текущими установками шрифта Font. Пространство внутри области Rect в методе TextRect и фон надписи в методе TextOut закрашиваются текущей кистью Brush.

Для выравнивания позиции текста на канве и для задания красивой рамки в методе TextRect можно использовать методы, дающие высоту и длину выводимого текста в пикселях: методы TextWidth, TextHeight и TextExtent. Функция TextWidth: function TextWidth (const Text: string): Integer; возвращает длину в пикселях текста Text, который предполагается написать на канве текущим шрифтом. Функция TextHeight: function TextHeight(const Text: string): Integer; возвращает высоту в пикселях текста Text. Применение методов TextWidth и TextHeight позволяет перед выводом текста на канву определить размер надписи и расположить ее и другие элементы изображения наилучшим образом.

Имеется еще метод TextExtent, определенный следующим образом: type TSize = record сх: Longint; су: Longint; end; function TextExtent (const Text: string): TSize; Метод возвращает одновременно и высоту, и длину текста. Метод TextWidth возвращает то же, что TextExtent(Text).cx, а метод TextHeight возвращает то же, что TextExtent(Text).cy.

Рассмотрим примеры применения всего этого на практике. Оператор Form1.Canvas.TextOut(10, 10, s); выводит текст, хранящийся в строковой переменной s, на канву формы Form1, начиная с позиции (10, 10). Если форма Form1 является той, в обработчике которой написан этот оператор, то ссылку на Form1 можно не делать: Canvas.TextOut(10, 10, s) ; Оператор with Canvas do TextOut((ClientWidth - TextWidth(s)) div 2, TextHeight(s), s) ; выводит текст на канву текущей формы, выравнивая его при любом шрифте по середине ширины канвы (ширина определяется свойством ClientWidth) и отступив одну строчку сверху. То же самое делает и оператор with Canvas do TextOut((ClientWidth - TextExtent(s).cx) div 2, TextExtent(s).cy, s); который вместо методов TextWidth и TextHeight использует метод TextExtent.

Оператор with Canvas do TextOut((ClientWidth - TextWidth(s)) div 2, (ClientHeight - TextHeight(s)) div 2, s); выводит текст в середину формы и по высоте и по ширине.

Примеры вывода текста методом TextOut приведены на Рисунок 3.2. Основной недостаток такого вывода заключается в том, что рамка текста получается без зазоров. Такой вывод выглядит некрасиво. Вероятно, вывод этой функцией оправдан только в случае, если цвет фона (свойство Canvas.Brush.Color) совпадает с цветом поверхности компонента, на канву которого выводится текст. В этом случае он просто появится без рамки.