Справочник по компонентам Delphi. Часть 1
Страница 20. Фокус ввода
Будучи окнами Windows, TWinControl и его потомки должны управлять фокусом ввода (состоянием, когда они получают и обрабатывают входные сообщения). Они имеют предназначенные для этого методы:
Поскольку оконные и неоконные элементы управления фактически находятся в разных списках, эти операции касаются только элементов соответствующего списка. Оконные элементы всегда имеют приоритет над неоконными: вы можете поместить первый над вторым, наоборот — никогда.
Показывает, имеет ли элемент в данный момент фокус ввода.
Возвращает True, если оконный элемент может получить фокус ввода (для этого он и все его родительские оконные элементы управления должны быть активными (Enabled) и видимыми).
Запрашивает у родительской формы получение фокуса ввода.
При получении и утере фокуса оконными компонентами происходят события:
(Р1э) property OnExit: TNotifyEvent;
TNotifyEvent — простейшее событие — извещение, не имеющее параметров. Свойство
показывает, есть ли на данном элементе табулостоп. Между элементами формы, у которых TabStop установлено в Тше, можно передвигаться (перемещать фокус ввода) нажатиями клавиш /+. Очередность перехода фокуса определяется специальным списком. Положение элемента управления в родительском списке табулостопов определяется при помощи свойства:
При разработке формы номера присваиваются последовательно в порядке добавления компонентов, начиная с 0. Нулевой компонент первым получит фокус при активизации. Программист может менять значение этого свойства, не заботясь об учете других элементов, т. к. перенумерация производится автоматически. При отсутствии табулостопа на элементе его свойство TabOrder равно -1.
Можно получить и весь список, содержащий иерархию дочерних элементов, имеющих табулостоп:
Этот метод добавляет в уже существующий список List все дочерние компоненты, имеющие табулостоп; каждый из них при добавлении делает то же самое. Таким образом, элементы списка имеют тип TWinControl.
Два метода предназначены для управления показом перекрывающихся дочерних элементов управления:
Метод BringToFront переносит элемент в конец родительского списка (визуализация начинается с первого) и показывает его поверх остальных. SendToBack, наоборот, переносит элемент в начало и таким образом сверху окажутся все перекрывающиеся с ним. При этом элемент теряет фокус ввода (если имел).
Класс инкапсулирует шрифт Windows. В Delphi допускаются только горизонтально расположенные шрифты. В конструкторе объекта по умолчанию принимается шрифт System цвета clWindowText размера 10 пунктов.
Беседа о компонентах для ввода-вывода текста и о свойствах, общих для многих компонентов
Показывает текст, присвоенный свойству Caption, но не позволяет его редактировать. Можно организовать многострочный показ, если присвоить св-ву WordWrap значение true (это можно сделать в инспекторе объектов), а св-ву AutoSize — false. Большинство свойств (как и у других компонентов) программист оставляет без внимания, надеясь что им присвоены подходящие значения по умолчанию. Чаще всего используется только Caption. Св-ву FocusControl можно присвоить объект, способный получать фокус ввода (например, класса TEdit или TMemo, TListBox ) и пользоваться горячими клавишами для передачи фокуса этим объектам. Например, разместим около окошка Edit2 надпись Label1, заполним Label1.Caption текстом: Ф&амилия а свойство Label1.FocusControl = Edit2 (выбор из списка в инспекторе). При работе откомпилированной программы буква a в слове Фамилия будет подчеркнутой, а если нажать Alt а, то курсор ввода перейдет на Edit2 и можно будет вводить фамилию.
Рассмотрим на примере Label те св-ва и обрабатываемые события, которые есть у многих компонентов.
Свойства (Properties)
- Charset — кодировка. рекомендуется RUSSIAN_CHARSET. По умолчанию: DEFAULT_CHARSET, это менее надежно.
- Color — цвет,
- Name — имя, например, Arial, Courier New и т п
- Size — размер шрифта в точках (обычный для windows: 10,12, и т п)
- Style:TFontStyles;
TFontStyle = (fsBold, fsItalic, fsUnderline, fsStrikeOut); т е жирный, наклонный, подчеркнуый, перечеркнутый
TFontStyles = set of TFontStyle;
События (Events), для которых программист может назначит процедуру обработки, т е задать какие-то действия, которые программа выполнит при наступлении этого события
Компонент Edit (класс TEdit)
Это небольшой текстовый редактор, окно которого применяется для ввода данных. Откроем окно справки для Edit. Щелкнув по ссылке Hierarchy, мы увидим всех предков этого компонента, но эти сведения не очень нужны. Далее можно щелкнуть ссылку Properties, увидеть список свойств (и ужаснуться: как их много !). В этом списке выделено: у какого предка впервые появляется свойство, но это для нас сейчас не важно. Количество св-в не должно нас пугать по двум причинам:
1. Большинство св-в начинающие могут не использовать.
2. Все свойства имеют значения по умолчанию. Эти значения можно не изменять, т е не обращать на них внимания.
Некоторые свойства компонента Edit
- property Text: TCaption; т е string — строка. Когда мы вписываем текст в окошко Edit, этот текст сохраняется св-вом Text.
- property ReadOnly: Boolean; если = true, текст в окошке нельзя редактировать, т е значение св-ва Text во время работы проекта пользователь не может изменить.
- property PasswordChar: Char; — если отлично от #0, то этим символом в окошке заменяются введенные символы. Обычно используется, чтобы скрыть пароль.
Некоторые события, на которые может реагировать Edit
- property OnChange: TNotifyEvent; — текст в окне Edit изменен пользователем. Можно использовать для контроля и коррекции внесенных пользователем изменений.
- property OnEnter: TNotifyEvent; — окошко Edit получило фокус ввода (и в нем появился текстовый курсор). — есть пример.
- property OnExit: TNotifyEvent; — фокус ввода ушел от Edit. — есть пример.
- property OnKeyDown: TKeyEvent; — при нажатии любой клавиши клавиатуры (и если этот Edit имеет фокус ввода) type TKeyEvent = procedure (Sender: TObject; var Key: Word; Shift: TShiftState) of object;
здесь Key — код нажатой клавиши. Проще всего эти коды получить если их показать внутри обработчика OnKeyDown, например: Например, код F5 = 116, PageUp=33, Alt = 18 и т д. TShiftState описан выше (TShiftState ). - property OnKeyPress: TKeyPressEvent;
type TKeyPressEvent = procedure (Sender: TObject; var Key: Char) of object;
Здесь Key: Char — символ нажатой клавиши (только для символьных клавиш). — есть пример.
- procedure SetFocus; virtual; — программно передает фокус этому Edit. Например, если при выполнении какой-то продпрограммы встретится оператор Edit2.SetFocus, то Edit2 получит фокус ввода. Используется для автоматической (программной) передачи фокуса нужным окошкам. — есть пример.
- procedure Hide; — делает это окошко невидимым. Например: Edit3.Hide — прячет окно Edit3.
- procedure Show; — делает это окошко видимым. Интересно, что Hide и Show просто изменяют значение свойства Visible
Компонент StaticText (класс TStaticText)
Похож на Label. Но не имеет св-ва WordWrap. Если AutoSize установить в false, то текст, выходящий за правую рамку окна, переносит на следующую строку. Имеет возможность настраивать внешний вид рамки изменением св-ва
property BorderStyle: TStaticBorderStyle; где:
type TStaticBorderStyle = (sbsNone, sbsSingle, sbsSunken);
где sbsSunken — утопленное окно.
Отображаемый текст хранится в свойстве Caption.
Многострочные компоненты (Memo, ListBox, ComboBox)
Класс TStrings
- Добавления строк (в конец списка или после указанной строки),
- Удаления строк (по заданному номеру),
- Перестановки строк,
- Доступа к строке, расположенной в заданной позиции,
- Чтения списка строк из и записи этого списка в файл или поток.
- Связывания объекта с каждой строкой списка,
- Представления строк в виде списка пар: имя — значение.
- property Count: Integer; — число строк в списке,
- property Strings[Index: Integer]: string; — отдельная строка. Индекс верхней строки = 0, а самой нижней = Count — 1,
- property Objects[Index: Integer]: TObject; — отдельный объект, присоединенный к строке № Index. Перед удалением строки или списка нужно удалять объект (т е строка не является владельцем (owner) объекта). Присоединять объект можно либо присвоением Objects[I] := либо методами InsertObject, AddObject
- property Text: string; — все строки списка в виде единой строки. Строки списка разделены символами #13#10,
- property Names[Index: Integer]: string; — если список представляет собой список пар Name Value, то Names[i] — (i+1)-е значение Name (счет с нуля). Иными словами, это часть (i+1)-й строки списка, расположенная левее .
- property Values[const Name: string]: string; — Values[i] — это правая часть (правее ) строки списка, левая часть которой есть Name.
- procedure Append(const S: string); — добавляет строку S в конец списка,
- procedure Clear; virtual; abstract; — очищает список строк и удаляет ссылки на присоединенные объекты,
- procedure Assign(Source: TPersistent); override; — заполняет список строк строками источника Source, присоединенные объекты копируются.
- procedure Delete(Index: Integer); virtual; abstract; — потомки используют Delete(Index) для удаления строки номер Index из списка (для первой строки Index=0). Ссылка на присоединенный объект тоже удаляется.
- procedure Exchange(Index1, Index2: Integer); virtual; — меняет местами строки № Index1 и Index2 (отсчет с нуля).
- procedure Insert(Index: Integer; const S: string); virtual; abstract; — потомки используют метод для вставки строки S на позицию № Index в списке (отсчет с нуля).
- procedure InsertObject(Index: Integer; const S: string; AObject: TObject) virtual; — вставляет объект AObject и строку S в список. Объект AObject должен быть создан ранее. Фактически AObject есть указатель. Index — порядковый номер вставленной строки в списке (отсчет с нуля).
- procedure LoadFromFile(const FileName: string); virtual; — загружает список строк из файла FileName.
- procedure SaveToFile(const FileName: string); virtual; — сохраняет список строк в файле FileName. Каждая строка списка сохраняется как строка текстового файла.
- procedure SetCapacity(NewCapacity: Integer); virtual; — потомки используют этот метод для изменения св-ва Capacity — т е емкости списка (количество строк, которые может хранить список). (Обычно емкость списка достаточна и SetCapacity не используется).
Компонент Memo (класс TMemo)
Компонент предназначен для хранения, редактирования, показа в окне, чтения из и записи в файл или поток многострочного длинного текста (в Win9* — не более 64 Кб). Может владеть полосами скроллинга (прокрутки): вертикальной и горизонтальной.
- property Lines: TStrings; — который описан выше.
- property WordWrap: Boolean; — если = true, то текст, выходящий за правую границу окошка, переносится на следующую строку. В этом случае должен отсутствовать горизонт. скроллинг. По умолчанию = true.
- property ReadOnly: Boolean; — если = true, то юзер не может редактировать текст в окошке. По умолчанию — false.
- property Text: TCaption; — все строки списка в виде единой строки.
- procedure Append(const Text: WideString); — добавляет строку Text в конец существующего текста. Обычно для этого используют Memo.Lines.Append(S);
- procedure Clear; virtual; — удаляет весь текст. ( Присваивает Memo.text := »;)
Компонент ListBox (класс TListBox)
Предназначен для хранения списка строк, выделения (выбора), удаления и добавления отдельной строки списка.
- property Columns: Integer; — количество колонок в окне списка.
- property Count: Integer; — количество строк (Items) в списке.
- property ItemIndex: Integer; — № выбранной (выделенной) строки (отсчет номеров с нуля).
- property Items: TStrings; — класс описан выше.
- property MultiSelect: Boolean; — если = true, то можно выделять несколько строк.
- property SelCount: Integer; — количество выделенных строк (если MultiSelect=true)
- property Selected[Index: Integer]: Boolean; — если Selected[I] = true, то строка с номером I выделена (отсчет номеров с нуля).
- property Sorted: Boolean; — если = true, то вставляемые и добавляемые строки ставятся по алфавиту. Если Listbox.style = lbVirtual или = lbVirtualOwnerDraw, сортировка не производится.
- property Style: TListBoxStyle; где
type TListBoxStyle = (lbStandard, lbOwnerDrawFixed, lbOwnerDrawVariable, lbVirtual, lbVirtualOwnerDraw); — уточняйте сами или напишите, если нужно.
- procedure AddItem(Item: String; AObject: TObject); — добавляет в конец списка строку Item и объект AObject.
- procedure Clear; — очищает список. Употреблять ListBox.Clear правильнее чем ListBox.Items.Clear.
- procedure ClearSelection; — отменяет выделение всех выделенных строк. При этом строка, выделенная последней получает фокус, хотя и становится невыделенной.
- procedure DeleteSelected; override; — удаляет выделенные строки.
- function ItemAtPos(Pos: TPoint; Existing: Boolean): Integer; — возвращает индекс (т е № ) строки, которой принадлежит заданная точка Pos. Если Existing=true, то функция возвращает -1 , когда для заданной точки нет строки (не существует). В противном случае — возвращает индекс последней строки + 1.
- function ItemRect(Item: Integer): TRect; — возвращает прямоугольник (TRect), который ограничивает заданую индексом строку.
Компонент ComboBox (класс TComboBox)
Сочетает в себе Edit и выпадающий список строк, в котором можно выбрать одну строку. Выбранная строка заносится в окошко редактора
Setfocus delphi что это
урок из цикла: Учебное пособие по программированию на языке Delphi
| предыдущий урок | содержание семинара | следующий урок |
9.3. Компоненты для ввода данных
Вы получили первое представление об окнах диалога, научились создавать и выполнять простейшие из них. Но вы еще не знаете, как организовать диалог для получения данных от пользователя. Эта задача решается с помощью компонентов для ввода данных, к изучению которых мы сейчас приступаем.
Использование компонентов для ввода данных рассмотрим на примере приложения Alarms. Эта полезная программа позволит создать список будильников для уведомления о предстоящих событиях. По сигналу будильника в заданные время и день появится окно с сообщением и прозвучит сигнал. Список будильников будет отображаться в главном окне программы, а установка их параметров будет выполняться в модальном окне диалога. В процессе разработки этого приложения вы познакомитесь с такими компонентами, как CheckBox , RadioButton , ComboBox , ListBox , GroupBox , Edit , MaskEdit и некоторыми другими. Итак, приступим.
Шаг 1. Сначала приготовьте новый проект с пустой формой, выбрав команду меню File | New Application . Дайте форме идентификатор MainForm , скорректируйте ее размеры и установите следующие значения свойств:
Сохраните модуль формы под именем MainUnit.pas , а проект — под именем Alarms.dpr .
Шаг 2. В форме MainForm будет отображаться список будильников. Для управления списком нужны кнопки: New, Edit и Delete. Для быстрого и удобного закрытия формы нужна еще кнопка Close. Поэтому поместите в форму соответствующее число компонентов Button (с идентификаторами NewButton , EditButton , DeleteButton , CloseButton ) и задайте для них надписи, размеры и положение как на рисунке 9.19.
Рисунок 9.19. Кнопки для управления списком будильников
Шаг 3. Установите в компоненте NewButton свойство Default в значение True , чтобы кнопка срабатывала при нажатии клавиши Enter.
Шаг 4. Для компонента CloseButton создайте следующий обработчик события OnClick :
Шаг 5. Необходимые подготовительные операции сделаны. Теперь перейдем к разработке окна диалога, предназначенного для ввода параметров будильника. Это окно будет вызываться при нажатии кнопок New и Edit. С этой целью добавьте в проект новую форму, дайте ей идентификатор AlarmDetailsForm , скорректируйте размеры и установите следующие значения свойств:
Теперь сохраните модуль формы под именем AlarmDetailsUnit.pas .
Шаг 6. Добавьте в форму кнопки OK и Cancel и установите их свойства так, как показано на рисунке 9.20.
Рисунок 9.20. Стандартные кнопки OK и Cancel и их свойства
Шаг 7. Теперь займемся размещением компонентов для ввода данных. Прежде всего подумаем, какие параметры должны устанавливаться в диалоге. К ним относятся: текстовое сообщение, которое появится по сигналу будильника, время сигнала с точностью до минуты, признак того, нужно ли проигрывать звуковой сигнал, периодичность выдачи сигналов (ежедневно, в заданный день недели или в конкретный день). Учли все? Вроде бы, да. Тогда разместите в форме компоненты, обеспечивающие ввод перечисленных параметров (рисунок 9.21).
Рисунок 9.21. Эскиз окна для установки параметров будильника
Эскиз окна диалога создан (с помощью выносок на рисунке пояснены названия компонентов). Окинув его взором, вы обнаружите, что знакомых вам компонентов немного — это Bevel , Label и Button . Зато новых — хоть отбавляй: CheckBox , RadioButton , Edit , MaskEdit , GroupBox , ComboBox , DateTimePicker . Однако не пугайтесь, мы обо всех расскажем, и вы убедитесь, что обращаться с ними вовсе не сложно.
9.3.1. Фокус ввода
Во время работы программы только один из компонентов принимает клавиатурный ввод в текущий момент времени. Принято говорить, что такой компонент обладает фокусом ввода или просто — активен. Передача фокуса ввода осуществляется щелчками компонентов или нажатием клавиш Tab и Shift+Tab на клавиатуре. При использовании клавиатуры фокус ввода передается последовательно от одного компонента другому, причем клавиша Tab обеспечивает перебор элементов в прямом порядке, а сочетание клавиш Shift+Tab — в обратном.
Очередность, в которой компонент получает фокус ввода, задается его свойством TabOrder . Свойство TabOrder действует относительно содержащего компонента, например очередность перебора компонентов MessageEdit и TimeMaskEdit задается относительно формы, а очередность перебора компонентов WeeklyComboBox и DatePicker — относительно компонента GroupBox .
Если нужно исключить компонент из очереди на фокус ввода, установите свойство TabStop в значение False . Однако в этом случае фокус ввода можно насильно передать компоненту с помощью мыши или "горячей" клавиши.
Изначально порядок перебора соответствует порядку добавления компонентов в форму, но его можно изменить, устанавливая значения свойства TabOrder в компонентах. Если компонентов в окне диалога очень много, то это занятие может стать довольно утомительным. В этом случае удобнее пользоваться окном Edit Tab Order , которое открывается по команде меню Edit | Tab Order. (рисунок 9.22).
Рисунок 9.22. В окне Edit Tab Order выставляется порядок перебора компонентов формы
Шаг 8. В этом окне задайте порядок перебора компонентов формы AlarmDetailsForm таким, как показан на рисунке.
Ну хорошо, скажете вы, допустим, порядок перебора задан. А как управлять передачей фокуса ввода программно? Очень просто. Чтобы передать фокус ввода требуемому компоненту, у него нужно вызвать метод SetFocus . Кстати при управлении фокусом ввода очень полезным может оказаться свойство формы ActiveControl , которое указывает активный компонент. Это свойство доступно в окне свойств и часто используется для указания компонента, который первым получит фокус ввода (в обход номера очереди). Если значение свойства не задано, то первым фокус ввода получает компонент, в котором значение свойства TabOrder равно нулю.
Шаг 9. Хотя окно диалога Alarm Details еще не готово, вам, наверное, не терпится его опробовать и убедиться, что перебор компонентов происходит в нужном порядке. Для этого нужно связать выполнение диалога с нажатием в главной форме кнопки New. . Поэтому подключите модуль AlarmDetails в модуле Main и определите следующий обработчик события OnClick для кнопки NewButton :
Шаг 10. Теперь выполните компиляцию и запустите программу. В окне Clock Alarms нажмите кнопку New. . Вашему взору предстанет окно диалога Alarm Settings (рисунок 9.23).
Рисунок 9.23. Рабочий прототип окна для установки параметров будильника
Диалог запускается, фокус ввода перемещается в нужном порядке, но в целом компоненты работают не так, как надо. Ничего удивительного, ведь мы ими почти не занимались. Поэтому дальше мы приступаем к детальному изучению различных типов компонентов. На этом пути полигоном для испытаний нам послужит окно диалога Alarm Details .
Переключатели (check boxes) используются для установки параметров, характеризуемых двумя значениями — "Да" и "Нет" (True и False). Переключатели создаются с помощью компонента CheckBox , расположенного в палитре компонентов на вкладке Standard (рисунок 9.24).
Рисунок 9.24. Компонент CheckBox
Характерные свойства этого компонента собраны в таблице 9.6.
|
Обычно переключатель имеет два состояния: включен или выключен. Текущее состояние определяется значением свойства Checked . Если оно равно значению True , то переключатель включен, иначе — выключен. Бывает, что переключатель имеет еще и третье состояние — неопределенное (grayed). В этом состоянии переключатель закрашивается серым цветом. Если переключатель имеет три состояния, то вместо свойства Checked используется свойство State , а в свойстве AllowGrayed (разрешает неопределенное состояние) устанавливается значение True .
Когда при работе программы пользователь щелкает переключатель, в нем изменяются значения свойств Checked и State , а также происходит событие OnClick . Обрабатывая это событие, можно установить любую зависимость между состоянием переключателя и состоянием других компонентов.
В нашем примере компонент CheckBox используется для установки параметра Play Sound , управляющего выдачей звукового сигнала (рисунок 9.25). Мы назвали его SoundCheckBox .
Рисунок 9.25. Переключатель Play Sound представлен компонентом CheckBox
Шаг 11. Чтобы при первом появлении окна диалога, режим Play Sound был включен, установите в компоненте SoundCheck свойство Checked в значение True .
9.3.3. Взаимоисключающие переключатели
Взаимоисключающие переключатели (radio buttons) служат для установки взаимоисключающих параметров. Они обычно объединяются в группы и позволяют пользователю выбрать одно значение из фиксированного (причем немногочисленного) набора вариантов. При включении одного такого переключателя остальные переключатели этой же группы выключаются.
Группа переключателей создается с помощью нескольких компонентов RadioButton . Компонент RadioButton находится в палитре компонентов на вкладке Standard (рисунок 9.26).
Рисунок 9.26. Компонент RadioButton
Характерные свойства компонента RadioButton описаны в таблице 9.7.
|
В форму всегда помещаются несколько компонентов RadioButton , соответствующих возможным значениям устанавливаемого параметра. Например, в форме AlarmDetailsForm содержится три таких компонента ( EverydayRadioButton , WeeklyRadioButton и DateRadioButton ), которые используются для выбора периодичности срабатываний будильника (рисунок 9.27).
Рисунок 9.27. Переключатели Everyday, Weekly и Date представлены компонентами RadioButton
Внимание! Выбор положения переключателя осуществляется с помощью клавиш со стрелками.
Шаг 12. Текущее состояние переключателя контролируется свойством Checked . Если в одном переключателе оно устанавливается в значение True , то во всех остальных переключателях этой же группы оно устанавливается в значение False . Установите в компоненте EverydayRadioBox свойство Checked в значение True — этот переключатель будет изначально включен.
Шаг 13. Когда пользователь щелкает переключатель, в соответствующем компоненте RadioButton свойство Checked получает значение True и происходит событие OnClick . Обрабатывая это событие, можно установить любую зависимость между состоянием переключателя и состоянием других компонентов формы. Например, когда включен режим Everyday , компоненты для ввода дня недели и даты должны быть недоступны. Когда включен режим Weekly on , должен быть доступен выбор дня недели, но недоступна установка даты. Наконец, когда включен режим Date , установка дня недели должна быть недоступна, а установка даты — доступна. Чтобы достигнуть такой согласованности в работе, определите для переключателей EverydayRadioButton , WeeklyRadioButton и DateRadioButton единый обработчик события OnClick :
Шаг 14. Разумеется, компоненты WeeklyComboBox и DatePicker первоначально должны быть недоступны. Поэтому, удерживая клавишу Shift, выберите названную группу компонентов и установите свойство Enabled в значение False .
Теперь запустите программу и проверьте правильность ее работы.
9.3.4. Группа взаимоисключающих переключателей
Для быстрой организации группы взаимоисключающих переключателей очень удобен компонент RadioGroup , расположенный в палитре компонентов на вкладке Standard (рисунок 9.28).
Рисунок 9.28. Компонент RadioGroup
Его характерные свойства кратко описаны в таблице 9.8.
|
Компонент RadioGroup удобен тем, что заменяет группу компонентов RadioButton . Расположение переключателей, которые он отображает, подбирается автоматически с учетом заданного в свойстве Columns количества колонок. Номер активного зависимого переключателя хранится в значении свойства ItemIndex . Следующий рисунок 9.29 не относится к приложению Alarms, а просто поясняет, что такое компонент RadioGroup :
Рисунок 9.29. Четырехпозиционный переключатель представлен компонентом RadioGroup
Компонент RadioGroup создает группу, состоящую исключительно из переключателей. Однако он не годится в тех случаях, когда в группе должны присутствовать другие компоненты, что как раз имеет место в нашем примере. В этой ситуации для группировки компонентов применяется компонент GroupBox .
9.3.5. Панель группы компонентов
Компонент GroupBox служит для группировки компонентов, он расположен в палитре компонентов на вкладке Standard (рисунок 9.30).
Рисунок 9.30. Компонент GroupBox
Компонент GroupBox выглядит как панель с заголовком (рисунок 9.31). Текст заголовка задается в свойстве Caption .
Рисунок 9.31. Панель с заголовком представлена компонентом GroupBox
Компонент GroupBox может содержать в себе другие компоненты. Это, например, означает, что установка его свойства Visible в значение False прячет группу со всеми расположенными внутри компонентами, а не только рамку с заголовком.
9.3.6. Поле ввода и редактор текста
Для ввода текста предназначены компоненты Edit и Memo . Они представляют собой соответственно поле ввода и редактор многострочного текста (кроме них существует еще компонент RichEdit , предназначенный для ввода и отображения форматированного текста, но о нем мы поговорим отдельно).
Поле ввода ( Edit ) служит для ввода различных слов, фраз и другого относительно короткого текста. Он не имеет полос прокрутки, но разрешает прокручивать текст по горизонтали клавишами перемещения курсора влево и вправо. Компонент Edit расположен в палитре компонентов на вкладке Standard (рисунок 9.32).
Рисунок 9.32. Компонент Edit
Характерные свойства компонента Edit описаны в таблице 9.9.
|
Редактируемый текст содержится в свойстве Text . Его максимальная длина определяется значением свойства MaxLength .
Иногда компонент Edit используется для отображения нередактируемого текста. Для этого свойство ReadOnly устанавливается в значение True . Вы спросите, чем он в таком состоянии лучше компонента Label? А тем, что может получать фокус ввода. Кроме того, текст в поле ввода можно выделить и поместить в Буфер Обмена.
Компонент Edit легко приспособить для ввода паролей. Для этого достаточно установить в свойстве PasswordChar вместо символа #0 какой-нибудь другой символ, обычно символ звездочки (*). Символ, заданный в свойстве PasswordChar отображается вместо реально вводимых символов, что мешает подсмотреть пароль посторонним.
Шаг 15. В форме SettingsForm компонент Edit применяется для ввода текстового сообщения будильника. Выберите его в окне свойств и в значении свойства Text впишите "Reminder !" (рисунок 9.33). Этот текст будет появляться в редакторе при появлении окна диалога.
Рисунок 9.33. Компонент Edit используется для ввода текстового сообщения будильника
Шаг 16. Изменение текста во время работы программы приводит к возникновению в компоненте Edit события OnChange . Обрабатывая это событие, можно, например, устроить работу окна диалога таким образом, что кнопка OK будет недоступна, если в редакторе нет текста. Чтобы реализовать такое поведение нашего диалога, определите для компонента MessageEdit следующий обработчик события OnChange :
Выполните компиляцию программы и проверьте ее работу.
Прежде чем продолжить обсуждение примера Alarms, сделаем несколько замечаний по поводу редактирования многострочного текста. Редактор многострочного текста представлен компонентом Memo (рисунок 9.34).
Рисунок 9.34. Компонент Memo
Характерные свойства компонента Memo описаны в таблице 9.10.
|
Компонент Memo похож на Edit , но в отличие от него хранит не одну строку текста, а множество строк. Доступ к строкам обеспечивает свойство Lines , представляющее собой объект класса TStrings (см. главу 3). С помощью свойства Lines строки можно добавлять, вставлять, удалять и т.д. Свойство Lines доступно в окне свойств, поэтому на стадии проектирования вы можете заполнить компонент Memo некоторым исходным текстом (рисунок 9.35). Этот текст увидит пользователь при появлении формы на экране. Ввод исходного текста осуществляется в специальном редакторе текста ( String list editor ), которое вызывается нажатием кнопки с многоточием в поле значения свойства Lines .
Рисунок 9.35. Окно для ввода многострочного текста, отображаемого компонентом Memo
Компонент Memo часто имеет одну или две полосы прокрутки (вертикальную и горизонтальную). Их появление зависит от значения свойства ScrollBars .
В нашем приложении Alarms компонент Memo не нужен, но вам он безусловно пригодится в других программах.
9.3.7. Редактор с шаблоном
Поскольку компонент Edit не проверяет, что вводит пользователь, он не удобен для ввода данных строго определенного формата, например телефонных номеров, времени и др. На этот случай разработчики среды Delphi предусмотрительно создали компонент MaskEdit . Он находится в палитре компонентов на вкладке Additional (рисунок 9.36).
Рисунок 9.36. Компонент MaskEdit
Компонент MaskEdit представляет собой поле ввода, которое вынуждает пользователя вводить данные в строго заданном формате. Во многом аналогичный компоненту Edit , он отличается от последнего тем, что имеет свойство EditMask и не имеет свойств HideSelection и OEMConvert .
Свойство EditMask задает шаблон (маску) для ввода символов текста. Шаблон имеет вид текстовой строки, его символы называются форматными и управляют тем, что вводит пользователь: буквы или цифры, в каком порядке, сколько и т.д. Мы не будем утомлять вас подробным описанием форматных символов, при необходимости обратитесь к справочному руководству. Нас интересует только шаблон для ввода времени с точностью до минуты.
Шаг 17. Выберите компонент TimeMaskEdit , затем в окне свойств перейдите к свойству EditMask и щелчком кнопки с многоточием откройте специальный редактор для этого свойства — Input Mask Editor (рисунок 9.37):
Рисунок 9.37. Выбор шаблона для компонента MaskEdit
В этом окне вы можете ввести шаблон и проверить его работу. Часто используемые шаблоны, например шаблоны телефонных номеров, даты, времени и некоторые другие, можно просто выбрать среди уже имеющихся образцов. Этой возможностью мы и воспользуемся. Выберите в списке Sample Masks пункт Short Time и щелкните на кнопке OK. Шаблон для ввода времени задан и имеет вид !90:00;1;_ . Обратите внимание, как при этом изменился компонент TimeMaskEdit (рисунок 9.38):
Рисунок 9.38. Компонент MaskEdit настроен для ввода времени
Шаг 18. Теперь давайте сделаем так, чтобы при появлении окна диалога поле ввода TimeMaskEdit не было пустым, а содержало текущее время. Для этого создайте у формы обработчик события OnCreate :
Готово. Запустите программу и убедитесь, что она работает, как вы того ожидаете.
9.3.8. Раскрывающийся список
Раскрывающийся список (combo box) позволяет пользователю выбрать значение из большого множества альтернатив. Он представляет собой поле ввода, к которому прикреплен раскрывающийся список значений. Редактор служит для ввода нового значения, а список — для выбора существующего значения. Количество элементов в списке может быть произвольным, причем элементы можно динамически добавлять, удалять, заменять и т.д. Элементами списка обычно служат текстовые строки, но могут быть и графические рисунки (в последнем случае их редактирование невозможно).
Раскрывающийся список представлен компонентом ComboBox , который находится в палитре компонентов на вкладке Standard (рисунок 9.39):
Рисунок 9.39. Компонент ComboBox
Характерные свойства компонента ComboBox собраны в таблице 9.11.
|
Раскрывающийся список умеет отображать себя по-разному в зависимости от значения свойства Style (см. таблицу 9.12).
|
В двух последних случаях в компоненте ComboBox происходит событие OnDrawItem . Вы можете его перехватить и рисовать каждый элемент выпадающего списка как вам вздумается. Если элементы списка имеют разную высоту (стиль csOwnerDrawVariable ), то компонент генерирует событие OnMeasureItem , чтобы узнать высоту каждого элемента. Стили csOwnerDrawFixed и csOwnerDrawVariable применяются в тех случаях, когда элементы списка должны быть рисунками.
Шаг 19. Раскрывающиеся списки пригодились нам в диалоге Alarm Details для выбора дня недели (компонент WeeklyComboBox ). Поскольку все дни недели заранее известны, выберите в свойстве Style значение csDropDownList (рисунок 9.40).
Рисунок 9.40. Для выбора дня недели применяется компонент ComboBox в стиле csDropDownList
Шаг 20. Теперь компонент WeeklyComboBox нужно заполнить списком исходных значений. Выберите его в форме, затем в окне свойств перейдите к свойству Items и нажмите кнопку с многоточием в поле значения. В появившемся окне введите список строк, как показано на рисунке 9.41.
Рисунок 9.41. В этом окне вводятся элементы списка — дни недели
Щелкните кнопку OK — список значений компонента WeeklyComboBox задан.
Шаг 21. Выбранный элемент раскрывающегося списка определяется значением свойства ItemIndex . Начальное значение свойства равно -1, что означает — ни один элемент не выбран. Однако в компоненте WeeklyComboBox должно быть выбрано то значение, которое соответствуют текущей дате. С этой целью нужно доработать у формы обработчик события OnCreate . В итоге он будет иметь следующий вид:
Реализация метода основана на том, что компонент DatePicker при создании формы сразу содержит текущую дату.
На этом с визуальной частью диалога Alarm Details покончено. Правда, мы ничего не сказали о компоненте DateTimePicker (рисунок 9.42).
Рисунок 9.42. Компонент DateTimePicker
Впрочем, он уже работает так, как требуется. В нем нет ничего сложного, и мы надеемся, что вы разберетесь с ним по таблице 9.13.
|
В очередной раз выполните компиляцию программы и запустите ее. Откройте окно диалога Alarm Details и хорошенько его потестируйте (рисунок 9.43).
Рисунок 9.43. Тестирование окна Alarm Details
Все компоненты работают правильно. Можете поздравить себя с очередным достижением. Вы создали важную часть приложения Alarms — окно диалога, а заодно разобрались с множеством новых компонентов.
9.3.9. Установка и получение данных
Окно диалога есть, но пользы от него пока нет. Все дело в том, что мы научились устанавливать параметры будильника, но не научились их принимать и хранить.
Шаг 22. Для хранения параметров будильника нам нужна новая структура данных, очевидно класс объектов. Немного поразмыслив, приходим к следующему описанию:
Поясним назначение полей и методов. Поле MsgText предназначено для хранения текстового сообщения. В поле DateTime записывается время и дата сигнала. Значение поля PlaySound показывает, требуется ли звуковое сопровождение сообщения. Поле Recurring определяет периодичность работы будильника и принимает следующие значения:
- 0 — ежедневно;
- 1..7 — в заданный день недели (1 — Пн, 2 — Вт, . 7 — Вс);
- 8 — однажды в заданный день.
В первых двух случаях поле DateTime хранит только время, а в последнем еще и дату. Такое ухищрение позволяет организовать компактное хранение данных. Флаг Handled , объявленный в секции private , является служебным и позволит избежать повторных срабатываний, когда будильник уже прозвенел. Метод GetAlarmStr мы определили для удобства. Он будет формировать строку сообщения, содержащую время и текст напоминания. Метод CheckTime проверит, пора ли выдать сигнал и если да, то сделает это.
Шаг 23. Поместите описание класса TAlarm в раздел interface модуля AlarmDetails . Затем в разделе implementation наберите текст методов GetAlarmStr и CheckTime :
Для правильной работы будильника метод CheckTime должен вызываться не реже одного раза в минуту. Чем чаще вызывается метод, тем меньше инерционность будильника, но тем больше пустых опросов, а значит выше загруженность операционной системы. Компромиссная частота — два раза в секунду. Так как в одну и ту же минуту метод CheckTime будет вызван несколько раз, то для избежания повторных срабатываний используется флаг Handled . Будильник выдает сообщение только в том случае, если текущее время совпадает с временем, на которое будильник установлен и при условии, что в данную минуту он еще не звенел.
Шаг 24. Давайте теперь позаботимся о передаче данных в окно диалога перед его запуском и о приеме данных после завершения. Удобнее всего, чтобы за это отвечало само окно диалога, т.е. форма AlarmDetailsForm . С этой целью определите в классе TAlarmDetilasForm два метода — GetData и SetData . Методы следует поместить в секцию public :
В разделе implementation наберите программный текст методов:
Метод GetData просто заполняет поля переданного в параметре объекта Alarm значениями, которые установлены в компонентах окна диалога. Метод SetData выполняет обратные действия, заполняя компоненты окна диалога значениями, которые содержатся в полях объекта Alarm .
На этом с разработкой модуля AlarmDetails покончено и окно диалога Alarm Details полностью готово к использованию. Дальше необходимо обеспечить формирование, редактирование и визуализацию списка будильников. Эта задача решается с помощью компонента ListBox .
Компонент ListBox отображает список элементов, которые пользователь может просматривать и выбирать, но не может непосредственно модифицировать. По умолчанию элементами списка являются строки, но могут быть и графические объекты. Элементы могут располагаться в одну или несколько колонок и автоматически сортироваться. При необходимости обеспечивается возможность прокрутки списка. Компонент ListBox находится в палитре компонентов на вкладке Standard (рисунок 9.44).
Рисунок 9.44. Компонент ListBox
Его характерные свойства собраны в таблице 9.14.
|
Особенности хранения и отображения элементов списка определяются свойством Style , возможные значения которого описаны в таблице 9.15.
|
Шаг 25. Давайте воспользуемся компонентом ListBox для организации списка будильников. Активизируйте форму MainForm , а затем опустите на нее компонент ListBox . Переименуйте компонент в AlarmListBox и скорректируйте его местоположение и размеры. Затем установите свойство TabOrder в значение 0, чтобы при отображении формы список первым получил фокус ввода (рисунок 9.45).
Рисунок 9.45. Компонент ListBox применяется для организации списка будильников
Решим теперь вопрос хранения будильников в компоненте AlarmListBox . Для хранения элементов служит свойство Items . Свойство Items — это объект класса TStrings , в нем свойство-массив Strings хранит отображаемые строки, а свойство-массив Objects — ассоциированные со строками объекты. В нашем примере массив Strings будет хранить выдаваемые по сигналу сообщения, а массив Objects — соответствующие им объекты класса TAlarm .
Теоретически все понятно, осталось реализовать все это практически. Создание, редактирование и удаление будильника осуществляется по щелчкам на кнопках NewButton , EditButton и DeleteButton соответственно. Поэтому в них требуется создать обработчики события OnClick .
Шаг 26. В кнопке New. обработчик события OnClick уже существует, но его необходимо доработать:
Метод NewButtonClick создает окно диалога Alarm Details и выполняет его в монопольном режиме. Если диалог завершается щелчком кнопки OK, создается новый объект будильника и в него переносятся данные из окна диалога. Затем этот объект добавляется в список AlarmList и его номер присваивается свойству списка ItemIndex . В результате новый элемент становится выделенным.
Вы, разумеется, хотите проверить работу новоиспеченного метода. Сейчас мы так и сделаем, но прежде нужно решить небольшой вопрос. Дело в том, что при уничтожении блока списка освобождаются только строки, но не освобождаются ассоциированные с ними объекты. Хотя память объектов так или иначе освобождается при завершении приложения, мы рекомендуем всегда освобождать память явно. Это считается "хорошим тоном" программирования и иногда позволяет выявить скрытые ошибки. Освобождение использованных в форме динамических данных осуществляется в обработчике события OnDestroy . Для формы MainForm он должен быть таким:
После того как вы написали этот обработчик, выполните компиляцию программы и запустите ее. Попытайтесь добавить в список несколько будильников. Если это у вас получилось, перейдем к следующему шагу — программированию реакции на нажатия кнопок Edit. и Delete .
Шаг 27. Создайте в компоненте EditButton обработчик события OnClick :
Этот метод создает окно диалога Alarm Details, инициализирует его компоненты данными из выбранного в списке объекта будильника, а затем выполняет диалог в монопольном режиме. Если диалог завершился щелчком на кнопке OK, то данные из окна диалога переносятся обратно в объект будильника и соответственно изменяется отображаемая в блоке списка строка. Так как в результате последнего действия в списке пропадает полоса выбора (свойство ItemIndex получает значение -1), номер выделенного элемента предварительно сохраняется в локальной переменной SavedIndex , а затем восстанавливается.
Шаг 28. Осталось создать обработчик события OnClick в компоненте DeleteButton :
Метод DeleteButtonClick удаляет объект будильника и соответствующую ему строку в списке.
Обработчики событий для всех кнопок заданы, однако не спешите запускать приложение. Необходимо позаботиться о том, чтобы кнопки Edit. и Delete были доступны или недоступны в зависимости от того, выделен в списке элемент или нет. Как бы это сделать попроще? Первое решение, которое напрашивается — это вставить необходимые проверки в обработчики событий кнопок. Это неплохое решение, но оно больше подходит тем, кто привык решать задачу в лоб. Мы пойдем другим путем, воспользовавшись событием OnIdle объекта Application .
В объекте Application происходит событие OnIdle в период простоя программы, например во время ожидания пользовательского ввода. Благодаря этому событию программа может выполнять некоторую фоновую работу, которая в нашем случае заключается в управлении состоянием кнопок.
Для создания обработчика события OnIdle объекта Application воспользуемся уже знакомым вам компонентом ApplicationEvents (см. главу 8).
Шаг 29. Поместите в форму компонент ApplicationEvents , дайте ему одноименный идентификатор и создайте обработчик события OnIdle :
В передаваемом по ссылке параметре Done метод возвращает результат своей работы. Значение True показывает, что метод нужно вызывать не постоянно в течение простоя приложения, а только по одному разу в начале каждого периода простоя.
А сейчас выполните компиляцию, запустите программу и тщательно протестируйте работу главной формы (рисунок 9.46).
Рисунок 9.46. В этом окне создается список будильников
Будильники можно создавать, добавлять, удалять. Нам осталось сделать последний шаг — заставить будильники "звонить". Для этого нужно периодически вызывать метод CheckTime у каждого помещенного в список объекта TAlarm . Периодические по времени действия выполняются с помощью таймера, о котором мы дальше и поговорим.
Смотрите также материалы по темам:
Обсуждение материала [ 21-03-2008 08:22 ] 8 сообщений
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.