Delphi

КОМПЬЮТЕРНЫЕ КУРСЫ "ПОИСК"

[Главная страница] [Delphi] [Контакты]

Использование компонентов


Компонент TCheckBox

Компонент TCheckBox служит для представления пользователю элемента выбора — флажка, который можно отметить или снять с него отметку. Наиболее важным свойством компонента TCheckBox является свойство Checked, которое определяет, установлен ли флажок. Обработчик события OnClick наиболее всего подходит для помещения в него кода, который должен выполняться при изменении состояния флажка.

Сейчас мы посмотрим, каким образом можно использовать компонент TCheckBox, чтобы разрешить пользователю показывать/ скрывать и активизировать/блокировать все кнопки на форме.

comp1

Реализовать задуманное можно, по меньшей мере, тремя способами. Первый способ является самым простым, но менее совершенным, более подверженным ошибкам и более трудоемким. Он состоит в том, чтобы модифицировать свойства Enabled и Visible каждой кнопки на форме.

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  Button1.Visible := CheckBox1.Checked;
  Button2.Visible := CheckBox1.Checked;
  Button3.Visible := CheckBox1.Checked;
  Button4.Visible := CheckBox1.Checked;
  Button5.Visible := CheckBox1.Checked;
  Button6.Visible := CheckBox1.Checked;
  Button7.Visible := CheckBox1.Checked;
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
  Button1.Enabled := CheckBox2.Checked;
  Button2.Enabled := CheckBox2.Checked;
  Button3.Enabled := CheckBox2.Checked;
  Button4.Enabled := CheckBox2.Checked;
  Button5.Enabled := CheckBox2.Checked;
  Button6.Enabled := CheckBox2.Checked;
  Button7.Enabled := CheckBox2.Checked;
end;

Метод FindComponent

Второй, более подходящий, способ работы с большим количеством компонентов заключается в использовании имен компонентов, принятых по умолчанию, и метода FindComponent. Как правило, окно Designer Surface генерирует такие имена компонентов, которые будут понятны только ей, но не нам с вами; если вы хотите, чтобы ваш код был более понятным, эти имена следует изменить. Тем не менее, стиль именования компонентов, добавляемых в окно Designer Surface, который определяется как Имя_Компонента + Уникальный_Индекс, в данном случае окажется весьма полезным. Он позволяет без особого труда ссылаться на необходимые компоненты, вызывая метод FindComponent внутри цикла.

Объявление метода FindComponent выглядит следующим образом:

function FindComponent(const AName: string): TComponent;

Метод FindComponent использует параметр AName для поиска свойства Components и возврата компонента с совпавшим именем. Если компонент не будет найден, функция вернет nil. Свойство Components представляет список всех компонентов, принадлежащих конкретному компоненту.

На примере кода ниже показано, как можно узнать, что форме принадлежит компонент с именем MyButton.

procedure TForm1.Button1Click(Sender: TObject);
begin
  if FindComponent('MyButton') <> nil then
    ShowMessage('Компонент MyButton найден.');
end;

Чтобы показать/скрыть или активизировать/заблокировать все кнопки на форме, необходимо вызвать метод FindComponent в цикле и воспользоваться счетчиком цикла для генерации имени требуемого компонента. Поскольку метод FindComponent всегда возвращает тип TComponent, потребуется привести полученный компонент к типу TButton, прежде чем ссылаться на свойства Enabled и Disabled.

procedure TForm1.CheckBox1Click(Sender: TObject);
var
  Cnt: Integer;
  Comp: TComponent;
begin
  for Cnt := 1 to 7 do
  begin
    Comp := FindComponent('Button' + IntToStr(Cnt));
    TButton(Comp).Visible := CheckBox1.Checked;
  end;  // Завершение цикла Cnt
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
var
  Cnt: Integer;
  Comp: TComponent;
begin
  for Cnt := 1 to 7 do
  begin
    Comp := FindComponent('Button' + IntToStr(Cnt));
    TButton(Comp).Enabled := CheckBox2.Checked;
  end;
end;

Операция is в Delphi

Третий способ работы с большим количеством компонентов во время выполнения заключается в том, чтобы просматривать свойство Components вручную и выяснять, имеет ли компонент тип TButton или любой другой требуемый тип. Для выяснения типа компонента во время выполнения служит операция is. Синтаксис операции is показан ниже:

Объект is Класс

Операция is возвращает True, если объект является экземпляром типа Класс, или экземпляром одного из наследников класса. Например, следующая проверка в любом случае будет оценена как True, поскольку главная форма является наследником класса TForm.

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Self is TForm then
    ShowMessage('Главная форма действительно форма');
end;

Чтобы найти все кнопки на форме, потребуется просмотреть свойство Components формы. Свойство ComponentCount определяет количество компонентов в списке Components. Первый компонент из этого списка имеет индекс 0. а последний компонент — индекс ComponentCount-1.

procedure TForm1.CheckBox1Click(Sender: TObject);
var
  Cnt: Integer;
begin
  for Cnt := 0 to Pred(ComponentCount) do
  begin
    if Components[Cnt] is TButton then
      TButton(Components[Cnt]).Visible := CheckBox1.Checked;
  end;
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
var
  Cnt: Integer;
begin
  for Cnt := 0 to Pred(ComponentCount) do
  begin
    if Components[Cnt] is TButton then
      TButton(Components[Cnt]).Enabled := CheckBox2.Checked;
  end;
end;

Компонент TRadioButton

Компонент TRadioButton используется подобно компоненту TCheckBox. Свойство Checked определяет, установлен ли переключатель, а свойство OnClick позволяет выполнить код сразу после установки переключателя.

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

c1-2 c1-3 c1-4 c1-5

Создайте следующее диалоговое окно

c1-6

Тип окна сообщения определяется перечислением TMsgDlgType, которое объявлено в модуле Dialogs:

TMsgDlgType  = (mtWarning, mtError, mtInformation, mtConfirmation, mtCustom);

Изменить тип окна сообщения проще всего путем определения приватной переменной TMsgDlgType и присвоения ей соответствующего значения в событии OnClick каждого переключателя, как показано в листинге ниже.

unit Unit1;
interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TMainForm = class(TForm)
    GroupBox1: TGroupBox;
    WarningRadio: TRadioButton;
    ErrorRadio: TRadioButton;
    InformationRadio: TRadioButton;
    ConfirmationRadio: TRadioButton;
    DisplayButton: TButton;
    procedure WarningRadioClick(Sender: TObject);
    procedure ErrorRadioClick(Sender: TObject);
    procedure InformationRadioClick(Sender: TObject);
    procedure ConfirmationRadioClick(Sender: TObject);
    procedure DisplayButtonClick(Sender: TObject);
  private
    { Private declarations }
    FMessageType: TMsgDlgType;
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

procedure TMainForm.ConfirmationRadioClick(Sender: TObject);
begin
  FMessageType := mtConfirmation;
end;

procedure TMainForm.DisplayButtonClick(Sender: TObject);
begin
  MessageDlg('MessageDlg function', FMessageType, [mbOK], 0);
end;

procedure TMainForm.ErrorRadioClick(Sender: TObject);
begin
  FMessageType := mtError;
end;

procedure TMainForm.InformationRadioClick(Sender: TObject);
begin
  FMessageType := mtInformation;
end;

procedure TMainForm.WarningRadioClick(Sender: TObject);
begin
  FMessageType := mtWarning;
end;

end.

Параметр Sender

Изменить тип окна сообщения можно также путем объединения кода существующих обработчиков событий в одном обработчике события. В объединенном обработчике мы можем использовать параметр Sender для идентификации переключателя, вызвавшего обработчик события, и соответствующего изменения типа окна сообщения. Во-первых, удалите полностью обработчики события OnClick переключателей Error, Information и Confirmation и поместите следующий код в обработчик события OnClick переключателя Warning:

procedure TMainForm.WarningRadioClick(Sender: TObject);
begin
  if Sender = WarningRadio then
    FMessageType := mtWarning
  else if Sender = ErrorRadio then
    FMessageType := mtError
  else if Sender = InformationRadio then
    FMessageType := mtInformation
  else
    FMessageType := mtConfirmation;
end;

Теперь нам необходимо назначить этот обработчик событию OnClick каждого из четырех переключателей. Назначить обработчик одного события большому количеству компонентов быстрее всего можно, если сначала выбрать компоненты в окне Designer Surface, а затем в инспекторе объектов Object Inspector назначить обработчик соответствующему событию.

Свойство Tag

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

Наша задача заключается в том, чтобы присвоить свойству Tag переключателей целочисленное значение, которое будет совпадать с перечислимыми значениями констант mtWarning, mtError, mtInformation и mtConfirmation. Таким образом, мы можем оставить свойство Tag переключателя Warning неизмененным, поскольку значение Ord(mtWarning) равно 0, хотя нам потребуется модифицировать свойство Tag остальных трех переключателей. Итак, присвойте свойству Tag переключателя Error значение 1, свойству Tag переключателя Information значение 2. а свойству Tag переключателя Confirmation значение 3.

Теперь, когда свойство Tag всех четырех переключателей содержит соответствующий тип сообщения, нам не нужно использовать конструкцию if-then, чтобы определить тип окна сообщения. Мы должны всего лишь привести значение Tag компонента Sender к типу TMsgDlgType. На самом деле мы должны выполнить два приведения к типу. Во-первых, мы должны привести объект Sender к типу TComponent, поскольку свойство Tag определено в классе TComponent, после чего привести свойство Tag к типу TMsgDlgType.

procedure TMainForm.DisplayButtonClick(Sender: TObject);
begin
  MessageDlg('MessageDlg function', FMessageType, [mbOK], 0);
end;

procedure TMainForm.WarningRadioClick(Sender: TObject);
var
  SenderComp: TComponent;
begin
  SenderComp := TComponent(Sender);
  FMessageType := TMsgDlgType(SenderComp.Tag);
end;

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

procedure TMainForm.WarningRadioClick(Sender: TObject);
begin
  FMessageType := TMsgDlgType(TComponent(Sender).Tag);
end;

Компонент TListBox

Компонент TListBox отображает список элементов. Наиболее важным свойством этого компонента является свойство Items, которое представляет собой объект типа TStrings. Класс TStrings реализует список строк и позволяет манипулировать ними. Таким образом, если необходимо манипулировать элементами в окне списка, следует вызывать методы свойства Items. Например, чтобы добавить новый элемент в окно списка, вы должны вызвать метод Add свойства Items. Метод Add принимает единственный параметр — строковое значение, которое будет добавлено в конец списка.

c1-7

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListBox1.Items.Add(Edit1.Text);
end;

Метод Assign

В этом разделе мы будем использовать компонент TListBox для создания приложения, которое позволит просматривать все установленные шрифты на компьютере. Список установленных шрифтов предлагается еще одним глобальным объектом — объектом Screen. Список имен шрифтов содержится в свойстве Fonts, которое также объявлено как свойство типа TStrings.

c1-8

Для того чтобы отобразить перечень шрифтов в окне списка, мы должны скопировать все содержимое списка шрифтов в окно списка. Скопировать элементы из одного списка в другой можно и вручную, однако лучше всего использовать метод Assign. Этот метод практически везде присутствует в VCL и используется для копирования содержимого исходного объекта в требуемый объект. В случае со списком строк метод Assign применяется для копирования всех строк из исходного списка строк в список назначения.

procedure TForm1.FormCreate(Sender: TObject);
begin
  ListBox1.Items.Assign(Screen.Fonts);
end;

Чтобы пользователь мог просмотреть выбранный шрифт, вы должны сначала определить, какой из элементов был выбран. Выбранный элемент из списка строк определяется по свойству ItemIndex окна списка. Свойство ItemIndex является целочисленным свойством, содержащим значение -1, если не выбран ни один элемент, 0, если выбран первый элемент, и Items.Count-1, если выбран последний элемент в окне списка.

Чтобы предварительно просмотреть выбранный шрифт, необходимо предпринять следующие действия:

1. Добавить компонент TLabel в окно Designer Surface и присвоить ему имя PreviewLabel.
2. Добавить обработчик события OnClick компонента TListBox.

procedure TForm1.ListBox1Click(Sender: TObject);
var
  SelectedFont: string;
begin
  { Получение выбранного элемента }
  SelectedFont := ListBox1.Items[ListBox1.ItemIndex];
  { Изменение шрифта и заголовка }
  PreviewLabel.Font.Name := SelectedFont;
  PreviewLabel.Caption := SelectedFont;
end;

Выбор множества элементов

По умолчанию компонент TListBox позволяет выбрать только один элемент в списке. Если вы хотите выбрать множество элементов в окне списка, вы должны присвоить свойству MultiSelect значение True. Когда свойству MultiSelect присвоено значение True, вы не можете пользоваться свойством ItemIndex, чтобы узнать, какие элементы были выбраны. В случае с окном списка MultiSelect свойство ItemIndex идентифицирует только тот элемент, который находится в фокусе. Узнать, какие элементы из окна списка MultiSelect были выбраны, можно с помощью свойства Selected. Это свойство является индексированным свойством, которое позволяет определить, был ли выбран элемент с заданным индексом. Например, с помощью следующего кода можно выяснить, был ли выбран из окна списка первый элемент:

if ListBoxl.Selected[0] then
   Caption := 'The first item is selected.';

Если вы хотите работать со всеми выбранными элементами, то должны написать цикл, который будет проверять состояние каждого элемента — выбран он или нет.

Давайте создадим простое приложение, с помощью которого пользователь сможет выбирать множество элементов в одном списке и перемещать их в другой список. Добавьте в окно Designer Surface два компонента TListBox. Компонент ListBox1 будет исходным списком, а компонент ListBox2 —целевым.

Чтобы пользователь мог выбирать и перемещать множество компонентов из исходного списка в целевой, вы должны сначала присвоить свойству MultiSelect компонента ListBox1 значение True, а затем добавить в него несколько элементов. Чтобы добавить элементы в компонент TListBox на этапе проектирования, необходимо использовать редактор списка строк StringList Editor. Этот редактор отображается в окне Object Inspector в результате щелчка на кнопке (...), расположенной напротив свойства Items выбранного окна списка.

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  {Копирование выбранных элементов}
  for i := 0 to Pred(ListBox1.Items.Count) do
  begin
    if ListBox1.Selected[i] then
      ListBox2.Items.Add(ListBox1.Items[i]);
  end;

  {Удаление выбранных элементов}
  for i := Pred(ListBox1.Items.Count) downto 0 do
  begin
    if ListBox1.Selected[i] then
      ListBox1.Items.Delete(i);
  end;
end;

Скопировать элементы из исходного окна списка в целевое можно с помощью стандартного цикла for, поскольку содержимое исходного окна списка не изменяется. Однако чтобы удалить выбранные элементы из исходного окна списка, мы должны использовать цикл downto, поскольку метод Delphi изменяет содержимое (а также индексы) исходного окна списка.

Если требуется удалить только выбранные элементы, вы можете также использовать метод DeleteSelected.

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  {Копирование выбранных элементов}
  for i := 0 to Pred(ListBox1.Items.Count) do
  begin
    if ListBox1.Selected[i] then
      ListBox2.Items.Add(ListBox1.Items[i]);
  end;

  ListBox1.DeleteSelected;
end;

Методы BeginUpdate и EndUpdate

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

Метод BeginUpdate временно отключает перерисовку окна списка, а метод EndUpdate возобновляет ее. Метод BeginUpdate обычно вызывается перед циклом, модифицирующим содержимое окна списка, а метод EndUpdate — после завершения цикла для перерисовки окна списка и отображения изменений в содержимом окна списка.

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  {Отключене перерисовки}
  ListBox2.Items.BeginUpdate;

  for i := 0 to Pred(ListBox1.Items.Count) do
  begin
    if ListBox1.Selected[i] then
      ListBox2.Items.Add(ListBox1.Items[i]);
  end;
  {Перерисовка и обновление окна списка}
  ListBox2.Items.EndUpdate;
  {Отключение перерисовки после удаления}
  ListBox1.Items.BeginUpdate;
  ListBox1.DeleteSelected;
  ListBox1.Items.EndUpdate;
end;

Методы BeginUpdate и EndUpdate действительно позволяют ощутить разницу в скорости выполнения операций с окном списка, особенно если речь идет о больших циклах. Так, чтобы переместить 5000 выбранных элементов из одного окна списка в другое, потребуется около 2 секунд. Если же использовать методы BeginUpdate и EndUpdate, то на выполнение этого же цикла понадобится примерно 0,2 секунды.

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  Label1.Caption := FormatDateTime('dd.mm.yyyy hh:nn:ss.zzz', Now) + ' Start';
  ListBox2.Items.BeginUpdate;
  for i := 0 to 50000 do
    if ListBox1.Selected[i] then
      ListBox2.Items.Append(ListBox1.Items[i]);
  ListBox2.Items.EndUpdate;
  Label2.Caption := FormatDateTime('dd.mm.yyyy hh:nn:ss.zzz', Now) + ' done';
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to 50000 do
    ListBox1.Items.Append('Items ' + IntToStr(i));
  ListBox1.SelectAll;
end;

Метод IndexOf

Метод IndexOf позволяет находить строки в списке строк. Этот метод принимает единственный строковый параметр и возвращает индекс переданной строки, если таковая найдена. Если переданная строка в списке строк не существует, метод IndexOf возвращает -1.

Метод IndexOf может использоваться, например, чтобы дать пользователю возможность добавлять в окно списка только уникальные значения. В следующем примере демонстрируется не только применение метода IndexOf, но и функции MessageDlg для выдачи запроса пользователю. Функция MessageDlg служит для того, чтобы запросить у пользователя, желает ли он добавить значение в список, если такое значение уже существует.

procedure TForm1.Button1Click(Sender: TObject);
begin
  if ListBox1.Items.IndexOf(Edit1.Text) = -1 then
    ListBox1.Items.Add(Edit1.Text)
  else
  begin
    if MessageDlg('This item already exists. Add anyway?',
        mtConfirmation, mbYesNo, 0) = mrYes then
      ListBox1.Items.Add(Edit1.Text);
  end;
end;

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

procedure TForm1.Button1Click(Sender: TObject);
begin
  if (ListBox1.Items.IndexOf(Edit1.Text) = -1) or
     (MessageDlg('This item already exists. Add anyway?',
        mtConfirmation, mbYesNo, 0) = mrYes) then
        ListBox1.Items.Add(Edit1.Text);
end;

Свойства Names и Values

В классе TStrings определены еще два свойства, которые могут использоваться для доступа к строкам в списке строк. Свойства Names и Values являются индексированными свойствами, которые позволяют обращаться к части строки, содержащей пару имя-значение. По умолчанию, символом, разделяющим часть имени от части значения в строке, является знак равенства (=).

С помощью свойств Names и Values можно, например, без труда создать небольшой словарь. Сейчас мы создадим простые англо-русский и англо-украинский словари с помощью свойства Values.

c1-10

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

russian.txt

umbrella=зонт
rat=крыса

ukrain.txt

umbrella=парасолька
rat=щур

Хранить эти файлы данных лучше всего в каталоге приложения. Присвойте этим файлам имена russian.txt и ukrain.txt.

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

Если необходимо работать со списками строк в фоновом режиме, используйте класс TStringList. Использовать класс TString напрямую нельзя, поскольку это абстрактный класс. Абстрактный класс — это класс, который никогда не наследуется, поскольку как минимум один из его методов не имеет реализации, а только интерфейс, который должен быть реализован в классе-потомке. Одним из классов, который реализует абстрактные методы класса TStrings, является TStringList.

Первое, что нужно будет сделать в этом приложении — это динамически создать два объекта TStringList и использовать их для загрузки текстовых файлов russian.txt и ukrain.txt, которые находятся в каталоге приложения. Текстовый файл можно прочитать вручную и использовать метод TStringList.Add для добавления строк в список, однако лучше всего для загрузки текстового файла в список строк использовать метод TStringList.LoadFromFile.

procedure TForm1.FormCreate(Sender: TObject);
var
  AppPath: string;
begin
  {Получение корневого каталога}
  AppPath := ExtractFilePath(Application.ExeName);
  {Формирование списков}
  Russian := TStringList.Create;
  Ukrain := TStringList.Create;
  {загрузка файлов из каталога программы}
  Russian.LoadFromFile(AppPath + 'russian.txt');
  Ukrain.LoadFromFile(AppPath + 'ukrain.txt');
end;

Первая строка в обработчике события OnCreate определяет каталог приложения, извлекая части диска и каталога из свойства ExeName. Свойство ExeName глобального объекта Application всегда содержит абсолютный путь (диск, каталог, имя файла и расширение).

Обратите внимание на то, как объявляются объекты TStringList. Конструктор не принимает никаких параметров, что означает, что класс TStringList не происходит от класса TComponent, и что память для объектов TStringList не управляется компонентом Owner автоматически. Таким образом, мы должны вручную освободить все экземпляры класса TStringList после того, как работа с ними будет завершена. В данном случае мы должны освободить экземпляры TStringList Russian и Ukrain в событии OnDestroy главной формы в конце выполнения приложения.

Последнее, что мы должны сделать — написать код, который будет использовать свойство Values для перевода слова. Этот код будет находиться в событии OnClick кнопки Перевести.

procedure TForm1.Button1Click(Sender: TObject);
begin
  if RussianCheckBox.Checked then
    RuLabel.Caption := Russian.Values[Edit1.Text]
  else
    RuLabel.Caption := '';

  if UkrainCheckBox.Checked then
    UkrLabel.Caption := Ukrain.Values[Edit1.Text]
  else
    UkrLabel.Caption := '';
end;

Источник: Иван Хладни - Внутренний мир Borland Delphi 2006.