SNK Software
Web Studio Монополия Metaproducts Утилиты Игры
Монополию Web Studio Библиотека
Вебмастер Дельфи Работа на ПК Самоучитель
Для PHP Для Delphi
Веб-дизайн Программирование Компьютеры Девайсы Заметки
SNK Software Индустрия hardware Индустрия software
О студии Портфолио Сопровождение сайтов

Новые материалы

Девайсы:
Сравнительный обзор Nokia Lumia 920 и HTC 8X
Девайсы:
Обзор Nokia Lumia 820 – смартфона на WP8
Вебмастеру:
Настройка Apache, PHP и MySQL для Linux-VPS
Вебмастеру:
VPS на домашнем ПК: настройка сети в VM VirtualBox и Debian
Вебмастеру:
VPS на домашнем ПК: устанавливаем Linux Debian 6
Вебмастеру:
VPS на домашнем ПК: установка VM VirtualBox
Работа на компьютере:
Иные возможности текстового процессора Word
Работа на компьютере:
Вставка объектов
Работа на компьютере:
Таблицы в Word
Работа на компьютере:
Печать и сохранение документов
Работа на компьютере:
Сноски, колонтитулы, оглавление и указатели в Word

Стандартные компоненты Delphi

От форм, являющихся основой приложений, перейдем к деталям, т.е. к тому, что на этих формах располагается. Начнем с компонент, расположенных на закладке Standard – наиболее часто используемых в Windows-приложениях. Это текстовые надписи, кнопки, переключатели, текстовые поля, панели и иные повсеместно используемые элементы пользовательского интерфейса.

Кнопки

Пожалуй, самым важным элементом управления в любой программе является кнопка, ведь, фактически, без нажатия на кнопку не начинается ни одно действие в Windows-приложениях. Для создания этого элемента управления в VCL предусмотрено несколько компонент, но наиболее востребованным является Button (кнопка). Он находится на закладке Standard палитры компонентов и выглядит как маленькая кнопка с надписью «ОК».

Компонент Button достаточно простой, и в дополнение к унаследованным от TWinControl свойствам и методам, имеет лишь 5 собственных свойств. Помимо свойства Caption, определяющего отображаемый на кнопке текст, и WordWrap, отвечающего за возможность переноса слов в случае, если надпись не помещается в одну строку, у компонента Button имеются такие специфические свойства, как Cancel и Default. Их смысл заключается в следующем:

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

Наконец, последнее свойство – ModalResult, имеет смысл использовать в том случае, если кнопка помещена на модальную диалоговую форму. В таком случае, если кнопке присвоено значение ModalResult, отличное от mrNone, то нажатие на такую кнопку приведет к закрытию диалогового окна и возвращению вызвавшей его процедуре значения данной кнопки.

Для примера создадим проект, состоящий из главной формы, на которую следует поместить кнопку. После этого добавим к проекту еще одну форму (File ? New ? Form), на которую, в свою очередь, поместим уже 2 кнопки. Левую сделаем кнопкой по умолчанию, возвращающую результат подтверждения. Для этого надо выбрать эту кнопку на форме и произвести в инспекторе объектов следующие действия:

  1. В свойстве Caption написать строку «ОК»;
  2. Свойство Default установить в true;
  3. Для свойства ModalResult выбрать значение mrOk.

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

  1. В Caption написать «Отмена»;
  2. Свойство Cancel установить в true (свойство Default оставить false);
  3. Для свойства ModalResult выбрать значение mrCancel

Теперь можно щелкнуть по самой форме, и в инспекторе объектов выбрать для ее свойства Position значение poMainFormCenter, поскольку для модельных диалоговых окон характерно появление как раз по центру главного окна приложения. Так же не помешает установить свойство BorderStyle в bsDialog. Наконец, размеры формы желательно сделать не очень большими, поскольку все равно кроме этих 2 кнопок не ней ничего не будет (рис. 12.1), а в качестве заголовка можно написать «Модальное окно». На этом работу над этой формой можно считать завершенной.

Форма модального диалогового окна в Delphi
Рис. 12.1. Форма модального диалогового окна

Сохраним проект, согласившись с предложенными по умолчанию именами (Unit2, Unit1 и Project1) в какой-либо папке на жестком диске и вернемся к первой, главной форме программы. На ней уже имеется кнопка, так что теперь следует написать код для обработчика события щелчка мышью. Для этого щелкните по кнопке мышкой и выберите на закладке Events инспектора объектов событие onClick и дважды щелкните по полю напротив, чтобы Delphi подготовила необходимый программный код.

СОВЕТ
На самом деле, для того, чтобы создать обработчик события onClick для кнопки достаточно дважды щелкнуть по самой кнопке. Двойной щелчок по визуальному компоненту, помещенному на форму, создает обработчик для наиболее характерного события, связанного с данным элементом управления. Раузметтся, для кнопки это как раз и будет onClick.

В результате вы получите заготовку для обработчика события onClick этой кнопки:

procedure TForm1.Button1Click(Sender: TObject); begin end;

В него нам надо поместить код, который будет показывать вторую форму как модальное диалоговое окно. Но прежде, чем обратиться к ней, следует позаботиться о том, чтобы модуль второй формы был доступен в модуле первой. этого чуть выше созданного обработчика событий, на непосредственно после строки с ключевым словом «implementation», следует написать:

uses unit2;

Здесь следует отметить тот момент, что хотя в данном модуле уже имеется часть uses, помещенная в самом начале, вслед за ключевым словом interface, включать другие формы программы туда не рекомендуется во избежание возникновения перекрестных связей. Они могут возникнуть, например, если не только первая форма обращается ко второй, но и вторая – к первой.

Теперь все готово к написанию обработчика события onClick. Прежде всего, он должен показывать диалоговую форму в модальном режиме. Для этого достаточно написать такую строку кода:

Form2.ShowModal;

Вслед за ним разместим код, который будет выводить в заголовок этого окна результат, полученный от вызванного диалога:

if Form2.ModalResult = mrOk then Form1.Caption:='OK'; if Form2.ModalResult = mrCancel then Form1.Caption:='Cancel';

Отметим, что после обращения к методу ShowModal управление будет передано вызванной таким образом форме. Соответственно, пока пользователь не закроет тем или иным способом модальное окно, следующий оператор выполнен не будет. Пример можно посмотреть в папке Demo\Part3\Button.

Надписи

Надписи, или текстовые метки (labels), часто используются в программах для вывода пояснительной информации. В VCL для этих целей используется компонент TLabel. На палитре компонентов он расположен 4-м слева, в виде кнопки с буквой «А».

ПРИМЕЧАНИЕ
Самой первой на любой закладке палитры компонент является кнопка со стрелкой, которая является не компонентой, а инструментом IDE. Ее следует использовать в том случае, если вы выберите компонент, но передумаете размещать его на форме. В таком случае щелчок по этой кнопке сбросит выбранный компонент.

Текст, помещенный на форму при помощи меток, пользователю нельзя редактировать. Кроме того, такой элемент не может даже получить фокус ввода. Это объясняется тем, что класс TLabel происходит не от оконных элементов интерфейса (TWinControl), а от более легких графических (TGraphicControl). От этого предка классу TLabel достается свойство Canvas. Что касается остальных свойств метки, то помимо всех унаследованных, включая самое важное для метки свойство – Caption, отвечающее за собственно надпись, она имеет несколько специфических свойств, отвечающих за выравнивание и расположение. Все эти свойства приведены в таблице 12.1.

Таблица 12.1. Свойства TLabel
СвойствоТип значенияОписание
AlignmentTAlignmentОпределяет выравнивание текста по горизонтали в области метки. Может принимать значения taLeftJustify, taRightJustify и taCenter
AutoSizeBooleanОпределяет, должна ли метка изменять свои размеры в зависимости от текста
FocusControlTWinControlУказывает на элемент управления, который может быть ассоциирован с меткой
LayoutTTextLayoutОпределяет выравнивание текста по вертикали. Может принимать значения tlTop, tlCenter и tlBottom
ShowAccelCharBooleanОпределяет, должен ли символ & обозначать подчеркнутую букву. Если да, то для вывода самого символа & его надо будет указать дважды (&&)
TransparentBooleanОпределяет, должен ли фон метки быть прозрачным
WordWrapBooleanОпределяет, должен ли текст, не помещающийся по ширине, переноситься на следующие строки

При установке свойств выравнивания следует учитывать, что такие свойства, как Alignment и Layout имеют смысл лишь в том случае, если свойство AutoSize не установлено в истину, поскольку в противном случае границы надписи всегда будут определяться лишь текстовым содержимым. А свойство ShowAccelChar следует использовать лишь в паре с FocusControl, поскольку, по правилам интерфейса Windows, подчеркнутая буква означает, что при нажатии ее на клавиатуре совместно с клавишей Alt, ассоциированный с надписью элемент управления получит фокус ввода.

Вместе с тем, в Delphi имеется и другой аналогичный по своему назначению компонент – StaticText, расположенный на закладке Additional палитры компонентов. Его отличие от Label состоит в том, что он является потомком класса TWinControl, со всеми вытекающими отсюда последствиями, а именно – наличия собственного дескриптора оконного элемента (Handle), возможности быть заключенным в рамку (свойство BorderStyle) и т.д. Но в типичном случае все-таки предпочтительнее использовать менее ресурсоемкий элемент Label.

Поля ввода текста

Вслед за меткой на палитре компонент располагается другой часто используемый в интерфейсе Windows-приложений элемент управления, Edit – строка ввода текста. Этот компонент, в отличие от метки, является полноценным оконным элементом управления, происходящим от TWinControl, и может не только получать фокус ввода, но и использоваться для правки однострочного текста пользователем. При этом поддерживаются такие операции, как перемещение по строке при помощи клавиш управления курсором, удаление символов, выделение текста, в том числе при помощи мышки, а так же взаимодействие с буфером обмена Windows (clipboard).

Компонента Edit имеет ряд свойств и методов, специфических для элементов редактирования текста. Все они инкапсулированы в классе TCustomEdit, потомками которого, помимо TEdit, являются и другие элементы интерфейса, связанные с вводом текста. Что касается его свойств, то они приведены в таблице 12.2.

Таблица 12.2. Свойства TCustomEdit
СвойствоТип значенияОписание
AutoSelectBooleanОпределяет, должен ли быть выделен весь текст при получении фокуса ввода
AutoSizeBooleanОпределяет, должна ли автоматически изменяться высота элемента при изменении размера шрифта
BorderStyleTBorderStyleОпределяет, должен быть компонент обрамлен рамкой (bsSingle), или нет (bsNone)
CanUndoBooleanУказывает, может ли в данный момент быть применен метод Undo
CharCaseTEditCharCaseОпределяет, должен ли вводимый текст преобразовываться в символы верхнего или нижнего регистра. Допустимые значения: ecNormal, ecUpperCase и ecLowerCase
HideSelectionBooleanОпределяет, должно ли сохраняться визуальное выделение текста при потере фокуса ввода
MaxLengthIntegerОпределяет максимально допустимое количество символов в строке
ModifiedBooleanУказывает, был ли текст изменен пользователем
PasswordCharCharОпределяет символ, который должен отображаться вместо вводимых символов
ReadOnlyBooleanОпределяет, может или нет пользователь редактировать текст
SelLengthIntegerУказывает на длину выделенного фрагмента текста
SelStartIntegerУказывает на позицию первого выделенного символа
SelTextStringСодержит строку c выделенным фрагментом текста

Из свойств, влияющих на внешнее оформление компоненты, отметим AutoSize и BorderStyle. Первое, в отличие от одноименных свойств метки, в данном случае изменяет размеры компоненты только по высоте. А второе, на сей раз – в отличие от такого же свойства у формы, может принимать только 2 значения, которые сводятся к тому, будет рамка вообще или нет.

Все остальные свойства, так или иначе, связаны непосредственно с текстовым содержимым. Например, если установить PasswordChar в значение, отличное от нулевого символа (#0), что принято по умолчанию, то мы получим элемент управления, предназначенный для ввода паролей. Как правило, в этом случае для замены используют символ «звездочка». Разумеется, при этом вводимые символы не будут в действительности заменяться, а останутся теми, что были введены в действительности.

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

Свойство MaxLength, при значении, большим нуля, ограничивает длину текста. А свойство ReadOnly, будучи установленным в истину, вообще запретит правку текста пользователем. Если же правка возможна, то при помощи свойства Modified можно узнать, изменял ли пользователь текст: оно автоматически устанавливается в истину при любом изменении содержимого, кроме тех, что были произведены программными методами. Ну а если какая-либо правка была произведена, то возможен и возврат к предыдущему состоянию – за этим «следит» свойство CanUndo.

Все оставшиеся свойства связаны с выделением текста. Как известно, в Windows текст выделяется либо клавиатурой (перемещением с нажатой клавишей Shift), либо мышкой. Разумеется, компоненты VCL, являясь, по большей части, оболочкой для системных средств ОС, поддерживают оба этих метода и предоставляют разработчику все необходимое для работы с выделенным фрагментом. В частности, первый выделенный символ можно определить по свойству SelStart. Если же ничего не выделено, то это свойство будет ссылаться на текущую позицию каретки в строке. Но если текст все-таки выделен, то длину выделенного фрагмента можно узнать по текущему значению свойства SelLength. Просуммировав оба этих значения, при желании, можно определить и последний выделенный символ:

SelEnd := Edit1.SelStart + Edit1.SelLength;

Оба этих свойства можно менять программно, выделяя нужную часть текста. Сам же выделенный фрагмент текста можно получить, обратившись к свойству SelText.

Установив свойство AutoSelect в ложь, можно сделать так, что при получении фокуса ввода текст в поле ввода не станет выделенным автоматически (это не актуально, если пользователь устанавливает фокус ввода, пользуясь мышкой). А установив свойства HideSelection в ложь, можно получить такой эффект,, что даже после потери фокуса ввода выделенный фрагмент текста не потеряет выделения.

Наглядную иллюстрацию этих свойств можно получить, экспериментируя с настройками этой компоненты. Ряд вариантов приведен в примере editprops, находящемся в каталоге Demo\Part3\Edit.

Разобравшись со свойствами, перейдем к методам. Все они также являются унаследованными от класса TCustomEdit, и предназначены для работы с выделенным текстом, включая взаимодействие с буфером обмена. Так же есть методы для работы с содержимым в целом. Так, для удаления всего текста используют метод Clear, для выделения всего содержимого – метод SelectAll, а для сброса выделения – метод ClearSelection.

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

if Edit1.CanUndo then begin Edit1.Undo; Edit1.ClearUndo; end;

Оставшиеся методы – CopyToClipboard, CutToClipboard и PasteFromClipboard используются для таких стандартных операций с буфером обмена, как копирование, вырезание и вставка. При этом копирование и вырезание возможно лишь в том случае, если имеется выделенный текст. Таким образом, перед обращением к этим методам следует проверять, есть ли выделенный фрагмент текста. Делать это можно, проверяя значение свойства SelLength:

if Edit1.SelSength > 0 then ...

Что касается операции вставки, то она, разумеется, возможна только в том случае, если в буфере обмена находится текст. Если находящийся в буфере текст состоит более чем из одной строки (т.е. разделен символами «новая строка»), то в поле редактирования будет вставлена лишь первая строка текста.

Многострочный редактор и строки

Для работы с многострочным текстом используется другой наследник класса TCustomEdit – компонент Memo, или многострочный редактор. На палитре компонентов его значок расположен сразу после однострочного редактора. Класс TMemo имеет все свойства однострочного редактора, а так же ряд собственных свойств, необходимых учитывающих специфику многострочного редактирования. Прежде всего, это свойство WordWrap, отвечающее за автоматический перенос не умещающихся по ширине окна строк текста. А свойство Alignment отвечает за выравнивание текста по левому (taLeftJustify) или правому (taRightJustify) краям, или по центру (taCenter).

Для работы с множеством строк могут понадобиться полосы прокрутки. За их наличие и расположение отвечает свойство ScrollBars, которое может принимать одно за 4 значений: ssNone – без полос прокрутки (это значение принято по умолчанию), ssHorizontal – полоса для горизонтальной прокрутки, ssVertical – полоса для вертикальной прокрутки и ssBoth – с обеими полосами прокрутки. При этом отсутствие полос не ограничивает размер вводимого текста, хотя и влияет на его ввод.

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

Еще 2 свойства отвечают за обработку отдельных клавиш на клавиатуре. Это WantTabs и WantReturns. Первое отвечает за обработку нажатий клавиши табуляции, а второе – клавиши ввода. При этом значение истины для обоих свойств означает, что эти клавиши будут обрабатываться самим многострочным редактором. Т.е. нажатие на Tab будет вставлять символ табуляции, а нажатие на Enter – к началу новой строки. Если же значение этих свойств будет ложью, то нажатие на Tab приведет к перемещению фокуса ввода к следующему элементу управления, а обработка нажатия клавиши Enter будет передана форме. По умолчанию свойство WantTabs установлено в false, а WantReturns – в true.

Для того чтобы определить, где в данный момент находится каретка, обращаются к свойству CaretPos. Оно возвращает координаты (X, Y) точки по отношению к верхнему левому углу окна редактора. Если же необходимо определить смещение не в пикселях от угла компоненты, а в символах от начала строки, то следует использовать свойство SelStart.

Наконец, рассмотрим свойства, относящиеся собственно к текстовому содержимому многострочного редактора. Разумеется, у него есть свойство Text, через которое можно получить доступ к всему содержимому сразу. Но если вы поместите элемент Memo на форму и посмотрите на инспектор объекта, то не найдете в нем этого свойства. Дело в том, что оно не является опубликованным для класса TMemo, и доступно лишь программно. Зато у многострочного редактора имеется другое, более подходящее свойство – Lines, являющееся опубликованным.

Если в инспекторе объекта щелкнуть по кнопке с многоточием напротив этого свойства, то откроется окно редактирования, в котором можно ввести начальный текст (рис. 12.2).

Текстовый редактор для многострочных компонент в Delphi IDE
Рис. 12.2. Текстовый редактор для многострочных компонент в Delphi IDE

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

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

Таблица 12.3. Свойства TStrings
СвойствоТип данныхОписание
CommaTextStringПредставляет весь список одной строкой, разделенной запятыми. При этом строки с пробелами заключаются в двойные кавычки
CountIntegerУказывает на количество строк в списке
DelimitedTextStringПредставляет весь список одной строкой в соответствии со значениями свойств Delimeter и QuoteChar
DelimiterCharОпределяет разделитель для свойства DelimitedText
Names[Index: Integer]: stringПредставляет собой массив имен для строк формата имя-значение
NameValueSeparatorCharОпределяет символ, по которому будут разделены имя и значение
Objects[Index: Integer]: TObjectПредставляет собой массив объектов, ассоциированных со строками
QuoteCharCharОпределяет символ кавычек для свойства DelimitedText
Strings[Index: Integer]: stringПредставляет список в качестве массива строк
TextStringСписок строк одной строкой, включая символы «возврат каретки» и «новая строка»
ValueFromIndex[Index: Integer]: stringПредставляет собой массив значений для строк формата имя-значение
Values[const Name: string]: stringПозволяет получить значение по его имени для строк формата имя-значение

Все свойства этого класса можно разделить на 2 категории: те, что предназначены для работы со строками списка по отдельности, и те, что позволяют взаимодействовать со всем текстом в целом. К первой группе относятся свойства Count, Strings, Names и Values. Причем последние 2 свойства используются при работе со списком, состоящим из строк типа имя значение, например, «город=Москва». К этой группе можно причислить свойства NameValueSeparator и ValueFromIndex. Для примера рассмотрим список, состоящий из строк «город=Москва» и «страна=Россия». Чтобы можно было рассматривать этот список как состоящий из пар имя-значение, следует назначить свойству NameValueSeparator значение «=». После этого можно обращаться к свойствам Names, Values и ValueFromIndex. Например, применительно к строкам, содержащимся в многострочном редакторе (пусть он называется Memo1), мы можем использовать подобный код (см. также пример в Demo\Part3\Memo):

var s: string; ... s := Memo1.Lines.Names[0]; // s получит «Москва» Memo1.Lines.ValueFromIndex[0]:='Подольск'; s := Memo1.Lines.Values['город']; // s получит «Подольск» s := Memo1.Lines.Values['страна']; // s получит «Россия»

Если же предстоит работать с обычными строками, то можно использовать свойство Strings. Так, для обращения к первой строке списка достаточно написать:

s := Memo1.Lines.Strings[0]; Memo1.Lines.Strings[1]:='Вторая строка';

Несколько особняком стоит свойство Objects. Дело в том, что список строк позволяет ассоциировать какой-либо объект с каждой строкой. В ряде случаев это оказывается очень полезным дополнением.

Что касается свойств, предназначенных для работы со списком как с единой строкой текста, то это, прежде всего, свойство Text, представляющее все содержимое списка в качестве одной строки. При этом в тех местах, где заканчиваются реальные строки списка, добавляются символы новой строки и возврата каретки (#10 и #13).

ПРИМЕЧАНИЕ
Применительно к компоненту Memo, его собственное свойство Text содержит точно те же данные, что и Lines.Text.

Другое свойство, CommaText, также представляет весь список одной строкой, но использует для этого формат SDF, когда каждая строка перечисляется через запятую. При этом если исходная строка не содержит ни запятых, ни пробельных символов, то она остается как есть, в противном случае – заключается в кавычки. Например, список, состоящий из строк «Borland Delphi» и «Forever», преобразуется в строку «"Borland Delphi",Forever».

Еще одно свойство, DelimetedText, является во многом аналогичным CommaText, за тем исключением, что можно выбирать тип кавычек и разделителей, которые, в свою очередь, определяются свойствами QuoteChar и Delimiter. Таким образом, если эти свойства установить в «"» и «,», то значение DelimetedText будет полностью соответствовать значению CommaText.

Что касается методов класса TStrings, то среди них можно выделить Add, AddObject, AddStrings, Append, Assign, Clear, Delete, IndexOf, Insert, LoadFromFile и SaveToFile. Пожалуй, самыми интересными являются последние 2 метода, позволяющие без каких-либо дополнительных действий загрузить из файла или сохранить в файл сразу все содержимое текстового редактора. Более подробно все эти методы будут рассмотрены в рамках класса TStringList.

Класс TStringList

Хотя в качестве свойств ряда компонент в VCL выступают объекты типа TStrings, использовать объекты этого класса сами по себе нельзя, поскольку этот класс является абстрактным. Соответственно, для работы непосредственно со списками строк в программах надо либо создавать классы, основанные на TStrings, либо использовать его наследника, «готового к употреблению» – класс TStringList.

Помимо того, что класс TStringList не является виртуальным, он добавляет функциональность к своему предшественнику, а именно – возможность поиска и сортировки строк в списке. В частности, он имеет такие методы, как CustomSort, Find и Sort, а также связанные с сортировкой свойства:

Если свойства CaseSensitive и Sorted могут принимать всего по 2 значения – ложь или истина, то для свойства Duplicates предусмотрено 3 варианта, определяющих поведение списка при добавлении новых строк, совпадающих с уже присутствующими в списке. Так, если для него установлено принятое по умолчанию значение dupAccept, то одинаковые строки будут добавляться, а если установлено dupIgnore – то не будут. Если же установить его в dupError, то попытка добавить к списку повторяющуюся строку будет вызывать исключение типа EStringListError.

Собственно для добавления новых строк к списку используют методы Add, Append или AddObject, а если требуется добавить сразу группу строк, т.е. другой список – то AddStrings. Эти, а так же другие методы классов TStrings и TStringList представлены в таблице 12.4.

Таблица 12.4. Методы списков строк
МетодПараметрыОписание
Addconst S: stringДобавляет новую строку к списку
AddObjectconst S: string; AObject: TObjectДобавляет строку к списку и ассоциирует с ней объект
AddStringsStrings: TStringsДобавляет группу строк к списку
Appendconst S: stringДобавляет строку к списку, но в отличие от Add не возвращает результат операции
AssignSource: TPersistentПрисваивает строки, и, по возможности, объекты, из другого списка к данному
Clear-Удаляет все строки списка
CustomSortCompare: TStringListSortCompareСортирует строки в списке используя правила, определенные в указанной функции
DeleteIndex: IntegerУдаляет из списка строку с указанным индексом
EqualsStrings: TStringsСравнивает 2 списка и возвращает результат сравнения
ExchangeIndex1, Index2: IntegerМеняет между собой расположение 2 строк в списке
Findconst S: string; var Index: IntegerНаходит строку в отсортированном списке и возвращает ее индекс
IndexOfconst S: stringАналогично Find, но подходит и для несортированных списков
IndexOfNameconst Name: stringВозвращает индекс первого найденного совпадения имени для списков типа имя-значение
IndexOfObjectAObject: TObjectВозвращает индекс первой строки, ассоциированной с указанным объектом
InsertIndex: Integer; const S: stringВставляет строку в указанную позицию списка
InsertObjectIndex: Integer; const S: string AObject: TObjectВставляет строку и объект в указанную позицию списка
LoadFromFileconst FileName: stringЗаполняет список строками текста из указанного текстового файла
MoveCurIndex, NewIndex: IntegerПеремещает строку в списке
SaveToFileconst FileName: stringСохраняет строки списка в указанный файл
Sort-Производит сортировку строк списка

Наиболее часто используемым методом, безусловно, является Add, при помощи которого как раз и создаются списки. При необходимости вставить строку в какое-либо определенное место списка, вместо него используют Insert. Для управления отдельными элементами списков пригодятся Delete, Move и Exchange, а для операций над списком в целом – Clear, SaveToFile и LoadFromFile.

Пример, наглядно демонстрирующий работу целого ряда методов списков строк применительно к свойству Lines многострочного редактора можно посмотреть в каталоге Demo\Part3\StringList.

Что касается методов, предназначенных для поиска и сортировки, то к их использованию следует подходить с некоторой осторожностью. Прежде всего, время, необходимое для сортировки списков, возрастает вместе с его размерами не линейно, а в геометрической прогрессии. Соответственно, если сортировка списка из сотни-другой элементов происходит почти моментально, то время выполнения сортировки для больших списков, содержащих многие тысячи строк, может оказаться весьма продолжительным. В то же время, если список является отсортированным изначально (т.е. свойство Sorted установлено в истину), то в процессе добавления новых строк они сразу же будут размещаться согласно порядку сортировки. Это следует учитывать при написании программ, работающих с объемными списками.

Списки

Помимо многострочного редактора, в Delphi, на той же закладке Standard палитры компонентов, располагаются еще 2 компонента, использующих списки строк для хранения своих значений. Это ListBox и ComboBox.

Простой список, представленный компонентом ListBox, представляет собой прямоугольную область, в которой располагаются его элементы – строки. Если строк в списке больше, чем может поместиться в отведенной области, то автоматически появляется полоса прокрутки.

Класс TListBox является наследником класса TWinControl и имеет собственные свойства, представленные в таблице 12.5.

Таблица 12.5. Основные свойства ListBox
СвойствоТипОписание
AutoCompleteBooleanОпределяет, должен ли список реагировать на нажатие клавиш таким образом, чтобы находить и выделить совпадающий элемент
BorderStyleTBorderStyleОпределяет, должна или нет быть рамка вокруг списка. Допустимые значения: bsNone, bsSingle
ColumnsIntegerОпределяет количество колонок, видимых без горизонтальной прокрутки
CountIntegerУказывает на количество элементов списка
ItemIndexIntegerОпределяет порядковый номер выбранного элемента, начиная с 0. Если не выбрано ни одного, то устанавливается в -1
ItemsTStringsСодержит строки списка
MultiSelectBooleanОпределяет, допустимо или нет производить множественный выбор
SelCountIntegerУказывает на количество выбранных элементов
Selectedarray of BooleanОпределяет, выбран или нет тот или иной элемент списка
SortedBooleanОпределяет, должен ли список быть отсортирован
TopIndexIntegerОпределяет порядковый номер элемента, который является самым верхним в видимой части списка

Отдельное пояснение следует дать для свойства Columns. Дело в том, что если оно имеет значение, отличное от принятого по умолчанию нуля, то список становится не простым вертикальным, а многоколоночным, с горизонтальной прокруткой по колонкам для случая, если все элементы не умещаются на отведенной для списка области. Поэтому, в зависимости от того, какое значение имеет параметр Columns, один и тот же список может выглядеть совершенно по-разному (рис. 12.3).

Влияние значения свойства Columns на внешний вид списка
Рис. 12.3. Влияние значения свойства Columns на внешний вид списка

ПРИМЕЧАНИЕ
Следует отметить, что многоколоночные списки используются довольно-таки редко. Пожалуй, едва ли не единственное их применение – это проводник Windows в режиме списка. При этом в нем используется совершенно другой компонент, аналогом которого в VCL является ListView.

Рассмотрим также свойство MultiSelect, которое оказывает непосредственное влияние на ряд других свойств. Так, если оно установлено в истину, то свойство ItemIndex всегда будет равно нулю, а если в ложь, то свойство SelCount всегда будет иметь значение -1. Что касается его непосредственного влияния на список, то оно позволяет выделять сразу несколько элементов с использованием мышки и клавиш Shift и Ctrl.

Если рассматривать методы списка, то основная их часть предназначена для выполнения тех или иных манипуляций над выбранными элементами:

Еще 2 метода выполняют работу, характерную для списков вообще. Так, метод Clear удаляет все элементы списка, а метод AddItem добавляет новый элемент, и, при необходимости, ассоциирует с ним объект:

List1.AddItem('Строка – новый элемент списка',nil);

В данном случае вместо ссылки на объект был использован указатель nil, т.е. никакого объекта не было ассоциировано.

ПРИМЕЧАНИЕ
Следует учитывать, что при работе с визуальными компонентами, представляющими списки, в случаях, когда одна и та же задача решается как методами свойства Items, так и собственными методами компонента, желательно использовать методы самих компонент. Т.е. List1.Clear предпочтительнее, чем List1.Items.Clear.

Теперь рассмотрим другой вариант списков, представленный компонентом ComboBox. Этот компонент расположен на палитре инструментов непосредственно за ListBox. Он интересен тем, что как бы объединяет в себе сразу 2 компонента – строку редактирования (Edit) и список (ListBox).

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

Очевидно, что ниспадающий список имеет ряд свойств, характерных как для однострочного редактора (SelText, SelStart, SelLength, MaxLength и CharCase), так и для обычного списка (Sorted, Items, ItemIndex и AutoComplete). Вместе с тем, предусмотрен и ряд уникальных свойств, в частности, необходимых для настройки его ниспадающей части. К ним относятся следующие свойства:

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

Чтобы нагляднее представить себе разницу между этими режимами, достаточно сделать простейшее приложение, использующее компонент ComboBox во всех возможных режимах, включая оба случая для csSimple – с видимой и скрытой частью списка. Пример можно найти в каталоге Demo\Part3\ComboBox.

Что касается методов комбинированного списка, то все они уже были нами рассмотрены в рамках обычного списка. Это AddItem, Clear, ClearSelection, CopySelection, DeleteSelected и SelectAll.

Переключатели

Переключатели являются еще одним видом основных, часто используемых элементов управления. Переключателями они называбтся потому, что могут находиться в 2 состояниях – в выбранном или невыбранном.

Переключатели бывают 2 типов – зависимыми (собственно переключатель, известный так же как «радиокнопка») и независимыми (флажки). Разница между ними заключается в том, что в группе зависимых переключателей может быть выбран только один, а независимые никак не связаны между собой. Визуально зависимые переключатели выглядят как кружки, а независимые – как квадратики. При щелчке по переключателю он меняет свое состояние, т.е. если был включенным (отмеченным), то становится выключенным, и наоборот.

Начнем с независимых переключателей – флажков. В VCL флажок представлен компонентом CheckBox. Он выглядит как небольшой прямоугольник с текстовым заголовком, расположенным справа. Если же вдруг появится острая необходимость «развернуть» флажок таким образом, чтобы текст находился слева, то можно установить свойство Alignment в taLeftJustify.

Но самым важным свойством флажка, пожалуй, является Checked. Именно оно определяет его состояние. Так, если флажок включен (что визуально проявляется как наличие галочки на квадратике), то это свойство имеет значение истины, а если выключен – лжи. Этим свойством можно управлять программно, визуально это будет проявляться как появление или исчезновение галочки.

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

Все состояния флажка Checkbox
Рис. 12.4. Все состояния флажка Checkbox

Поскольку состояний может быть не 2, а 3, то булевского значения в таких случаях оказывается недостаточно, чтобы представить все варианты. В таком случае для контроля или назначения состояния флажка используют свойство State. Оно может принимать следующие 3 значения типа TCheckBoxState:

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

Второй вид переключателей – зависимые – представлен в Delphi компонентом RadioButton (отсюда и его жаргонное название «радиокнопка»). Как уже было отмечено, его основным отличием от флажка является то, что изменение состояния одного такого переключателя влияет на состояние других. Иначе говоря, только один зависимый переключатель в группе может быть отмечен. Поэтому такие переключатели обычно используют для указания взаимоисключающих опций. Соответственно, щелчком мышки его можно только включить. Для отключения же потребуется включить другой зависимый переключатель из этой же группы. Примерно так работают кнопки на старых радиоприемниках, что объясняет название этого компонента.

Поскольку состояний у такой кнопки может быть только 2 – включено или выключено, то и свойств остается только 2 – Checked и Alignment.

Рассмотрим поведение флажков и радиокнопок на примере. Для этого создадим новое приложение, на главную форму которого поместим 2 столбика переключателей: независимые – слева, а зависимые – справа. Для одного из флажков, скажем, последнего, установим свойство AllowGrayed в истину. Затем внизу формы расположим обычную кнопку, а для ее свойства Caption укажем «Сброс» (рис. 12.5).

Переключатели - флажки и радиокнопки в Delphi
Рис. 12.5. Переключатели - флажки и радиокнопки

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

Реализовать сброс всех флажков можно последовательно, банальным перечислением каждого элемента и выставления свойства Checked в ложь:

CheckBox1.Checked:=false; CheckBox2.Checked:=false; ... RadioButton3.Cgecked:=false;

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

procedure TForm1.Button1Click(Sender: TObject); var i: integer; begin for i:=0 to Form1.ControlCount-1 do begin if Form1.Controls[i] is TCheckBox then (Form1.Controls[i] as TCheckBox).Checked:=false; if Form1.Controls[i] is TRadioButton then (Form1.Controls[i] as TRadioButton).Checked:=false; end; end;

Прежде всего, здесь организован цикл, обходящий все дочерние компоненты формы. В теле цикла сначала проверяется, принадлежит ли текущий компонент классу TCheckBox. Если да, то он явно приводится к типу TCheckBox при помощи оператора as, после чего с ним можно поступать так же, как если бы это было явное указание на объект этого класса, т.е. идет обращение к свойству Checked, которому присваивается новое значение. Затем то же самое проделывается для случая, когда компонент оказывается принадлежащим классу TRadioButton.

Такой подход, с использованием обязательной проверки на принадлежность к типу (с применением оператора is) исключает возможные ошибки времени выполнения. Например, если даже все переключатели были бы одного типа, скажем, флажками, нельзя упускать из виду того, что на форме кроме них могут находиться и другие компоненты. Даже в рассматриваемом нами случае такой компонент имеется - это та же кнопка «Сброс», которую, разумеется, не получилось бы привести от типа TButton к типу TCheckBox.

Работающий пример вы найдете в каталоге Demo\Part3\Checks.

Панели и группы

При рассмотрении радиокнопок неоднократно отмечалось, что они взаимодействуют в рамках группы. Очевидно, что в приведенных примерах группу образовавали все компоненты типа RadioButton, находящиеся на форме. Но это не означает, что на форме может быть только одна группа таких кнопок. Дело в том, что принадлежность компоненты к группе определяется на основании того, какому компоненту она принадлежит. Во всех рассмотренных ранее примерах таковым являлась сама форма. Но помимо формы имеются и другие компоненты, которые могут иметь дочерние объекты. Одним из наиболее широко применяемых элементов такого типа является панель – Panel. На палитре компонентов она расположена предпоследней на закладке Standard и выглядит как пустой серый квадратик. Поместив этот компонент на форму, вы получите прямоугольную область, ограниченную выпуклой рамкой.

Панели используются не только для логической группировки элементов управления, но и для визуального оформления приложений. Благодаря последнему обстоятельству, панель имеет целый ряд свойств, ответственных за внешний вид панели, вернее, ее рамки. Всего таковых имеется 5 штук, включая уже хорошо знакомо по другим элементам, например, текстовым редакторам, свойство BorderStyle. Точно так же, как и для них, для панели можно либо включить рамку (bsSingle), либо оставить ее выключенной (bsNone). Да, ошибки здесь нет: хотя рамка по умолчанию выключена, панель все равно имеет визуальные границы. А дело в том, что помимо собственно рамки, панель имеет еще и скосы (bevels), причем их 2 – внешние и внутренние. И именно внешний скос мы и видим при стандартных настройках панели. Соответственно, оставшиеся 4 свойства как раз скосами и управляют:

Для свойств, отвечающих за вид скосов – BevelInner и BevelOuter предусмотрено по несколько значений:

Таким образом, мы получаем весьма широкие просторы для манипулирования внешним видом границ панели – можно как отключать границы панелей вообще, установив свойства BevelInner и BevelOuter в bvNone, так и заключать панели в объемные рамки самого разнообразного вида (рис. 12.6).

Различные комбинации откосов панелей
Рис. 12.6. Различные комбинации откосов панелей

Чтобы убедиться в том, что каждая панель образует группу компонент, попробуем использовать их для группировки радиокнопок. Для этого поместим на форму 2 панели, немного увеличим их размеры в высоту, и поместим на каждую по 2 компонента RadioButton. Если теперь запустить программу и попробовать изменить состояние переключателей на одной из панелей, то это никак не отразится на состоянии переключателей, расположенных на другой панели.

Следует отметить, что если панель используется не в декоративно-пояснительных целях (например, как подзаголовок окна), а именно как группирующий элемент, то ее свойству Caption присваивают пустую строку, а пояснительный текст размещают в верхнем правом углу при помощи компонента Label. При этом, как правило, скосы не используются (оба отвечающих за их вид свойства устанавливают в bvNone), а если необходимо визуально подчеркнуть, что размещенные на панели компоненты относятся к одной логической группе, используют обычную рамку (свойство BorderStyle).

Вместе с тем, в Delphi имеется компонент, специально предназначенный для группировки элементов – GroupBox, или контейнер группы. В отличие от панели, он не имеет откосов, но всегда заключен в рамку. При этом его заголовок (Caption) изначально расположен как раз там, где надо – в верхнем левом углу, причем накладывается поверх образующей рамку линии. В целом можно отметить, что класс TGroupBox происходит от TWinControl и не имеет каких-либо дополнительных свойств и методов.

Контейнер группы используется для объединения ряда различных компонент в один логически связанный блок. При этом компоненты могут быть использованы самые разные – переключатели, поля редактирования, кнопки и т.д. Если же в группе требуется разместить исключительно радиокнопки, то можно использовать другой компонент – RadioGroup. Его можно назвать контейнером группы зависимых переключателей. Этот специализированный компонент является наследником контейнера группы, предназначенным исключительно для радиокнопок. Причем непосредственно помещать на него компоненты RadioButton нет надобности, вместо этого следует использовать его собственное свойство Items. Каждый элемент, указанный в списке Items, является надписью с переключателю. Соответственно, задав, скажем, 4 строки в списке Items, мы получим готовую группу из 4 радиокнопок, являющуюся одним компонентом. Это очень удобно, поскольку вместо проверки состояния каждого из переключателей достаточно узнать свойство ItemIndex компонента RadioGroup. Для примера рассмотрим оба варианта: один – с обычной группой и 4 компонентами RadioButton, и другой – с компонентом RadioGroup и 4 строками, заданными в списке Items. В первом случае нам понадобится написать 4 строки кода:

if RadioButton1.Checked then Label1.Caption:='Вариант 1'; ... if RadioButton4.Checked then Label1.Caption:='Вариант 4';

Во втором же будет достаточно всего одной строки:

Label2.Caption:='Вариант '+IntToStr(RadioGroup1.ItemIndex+1);

Этот пример можно посмотреть в каталоге Demo\Part3\Groups.

Кроме свойств Items с надписями к переключателям, параллельно определяющим их количество, и ItemIndex, указывающего на выбранный элемент (если не выбран ни один вариант, то ItemIndex имеет значение -1), компонент RadioGroup имеет еще одно свойство – Columns. Оно отвечает за количество столбцов, по которым будет разделен список.

Избранное

SNK GSCP
SNK GSCP - новая библиотека для PHP 5!
Web Studio
Web Studio и Visual Workshop
Библиотека:
Стандарты на web-технологии
Монополия
Монополия Android
Загрузки:
скачать программы
Продукция:
программы и книги
Техподдержка / Связаться с нами
Copyright © 1999-2020 SNK. Все права защищены.
При использовании материалов с сайта ссылка на источник обязательна.
Рейтинг@Mail.ru