Delphi 1
FAQ 5 VCL (1 из 2)
Следующий код создает модальную форму для ввода пароля во время выполнения программы. Тип TPasswordForm является классом-наследником от TForm, определяемым или в текущем, или в отдельном модуле со ссылкой на него в списке uses.
with TPasswordForm.Create(Application) do
begin { например, TForm1, TPasswordForm и пр.. }
ShowModal; { Отображаем форму как модальное окно }
Free; { Освобождаем форму при закрытии }
end;
|
Для добавления компонента на форму во время выполнения программы необходимо выполнить несколько шагов:
- Объявите переменную экземпляра компонентного типа, который вы хотите создать {например, TButton }. Примечание: переменные экземпляра используются для указания на фактический экземпляр объекта. Сами они объектами не являются.
- Испрользуйте конструктор компонента Create для создания экземпляра объекта компонента и его назначения переменной экземпляра, объявленной в шаге 1. Конструктору Create любого компонента в качестве параметра необходимо передать ссылку на его владельца. За редким исключением в качестве параметра owner конструктора Create необходимо указывать форму.
- Назначьте "родителя" свойству компонента Parent (например, Form1, Panel1 и пр.). Родитель определяет где должен быть отображен компонент и осуществляет привязку его левого верхнего угла относительно его координат. Для того, чтобы поместить компонент в Groupbox, установите его свойство Parent в Groupbox. Чтобы компонент был видим, ему необходимо иметь родителя, это позволит ему быть отображенным в его области.
- Установите любые другие необходимые свойства (например, Width, Height).
- Наконец, заставьте компонент появиться на форме, сделав его видимым, т.е. установив его свойсто Visible в True.
- Если вы создали компонент и задали ему владельца (свойство owner), вам
нет необходимости уничтожать компонент самим, это сделает за вас его владелец в момент его уничтожения.
Если же при создании компонента владелец ему присвоен не был, то вся ответственность за уничтожение
ложится на вас, его нужно освободить когда он больше вам не нужен.
Следующий код показывает процесс добавления компонента TButton на текущую форму во время работы программы:
varTempButton : TButton; { Это только указатель на TButton }beginTempButton := TButton.Create(Self); { Назначаем владельца форму }TempButton.Parent := Self; { Должны назначить Parent (родителя) }TempButton.Caption := 'Время выполнения'; { Устанавливаем здесь свойства }TempButton.Visible := True; { Показываем кнопку }end;
Используйте свойство PopupComponent компонента PopupMenu для определения компонента, на котором была нажата правая клавиша мыши.
procedure TForm1.PopupItem1Click(Sender: TObject);
begin
Label1.Caption := PopupMenu1.PopupComponent.ClassName;
end;
|
Можно использовать свойство формы ActiveControl, но компонент, вызвавший контекстное меню, не обязательно может быть активным элементом управления.
Любой компонент, использующий TList, может хранить информацию размером до 16368 элементов. Для примера, TTabControl может содержать вплоть до 16368 закладок, а палитра компонентов Delphi до 16368 страниц палитры.
Многие стандартные компоненты Delphi являются оболочками стандартных элементов управления Windows. Windows 3.1 накладывают собственные ограничения на данные компоненты. Для примера: TComboBox и TListbox могут содержать до 5440 элементов, в TMemo или TEdit (и др. соответствующие компоненты) до 32кб текста.
Объем ресурсов Windows 3.1 ограничивает компонент TNoteBook и позволяет ему иметь максимум 570 страниц. (Также трудно получить более чем 500 оконных дескрипторов любому приложению Windows.)
Примечание 1: Превышение лимита возбуждает исключение или может сделать работу Windows неустойчивой.
Примечание 2: Многие ограничения, присущие 16-битной версии Windows существенно уменьшены в Windows NT и Windows 95. В будущих 32-битных версих Delphi эти ограничения практически исчезнут.
Для определения высоты и ширины строки в пикселах могут применяться два метода Canvas - TextHeigh и TextWidth. Не забудьте назначить шрифт объекту Canvas перед тем, как что-либо нарисовать или провести измерения.
Все визуальные компоненты имеют свойство Canvas, но по умолчанию оно защищено (protected) для того, чтобы доступ к нему имели только прямые потомки. Но, поскольку вы создаете свой код на основе наследников TForm, то у вас практически всегда имеется доступ к унаследованному свойству формы Canvas. Компонент TPaintBox имеет доступное (public) свойство Canvas для того, чтобы в обработчике события компонента OnPaint вы могли бы что-либо нарисовать, но можно им воспользоваться и для наших целей.
Если компонент не имеет свойство Canvas, то следующая функция поможет возвратить вам ширину текста, основанного на определенном шрифте:
function GetTextWidth(CanvasOwner: TForm; Text : String;
TextFont : TFont): Integer;
var
OldFont : TFont;
begin
OldFont := TFont.Create;
try
OldFont.Assign( CanvasOWner.Font );
CanvasOWner.Font.Assign( TextFont );
Result := CanvasOwner.Canvas.TextWidth(Text);
CanvasOWner.Font.Assign( OldFont );
finally
OldFont.Free;
end;
end;
|
Все наследники TCustomControl имеют свойство Canvas, тем не менее, необходимо иметь какой-то механизм защиты для того, чтобы другие "художники" не могли рисовать на компоненте. Наследники компонента всегда имеют доступ к защищенным свойствам, которые они наследуют от компонента (как, например, Canvas), но те же пользователи компонента к ним доступа не имеют.
type
TCanvasPanel = class(TPanel)
public
property Canvas;
end;
|
Если вы хотите рисовать на компоненте, не имеющим опубликованного свойства canvas, попробуйте использовать другой компонент, позволяющий рисовать на нем (TPaintBox), или компоненты-слои, позволяющие достигнуть того же результата (client-align у TPaintBox внутри TPanel позволяет получить окантуренную область с возможностью рисования).
Пошлите сообщение LB_SetHorizontalExtent оконному дескриптору компонента ListBox. Например, сообщение можен быть послано в обработчике события формы OnCreate:
procedure TForm1.FormCreate(Sender: TObject);
begin
SendMessage(Listbox1.Handle, LB_SetHorizontalExtent, 1000, Longint(0));
end;
|
Нет. Тем не менее, существуют библиотеки для работы с последовательными портами (и скоро должны появиться компоненты) для Delphi третьих фирм, как, например, TurboPower, SaxComm и других.
Для установки табулятора в компоненте многострочного редактирования (например, TMemo), пошлите ему сообщение EM_SetTabStops. Массив Tabs указывает на месторасположение табуляторов. Поскольку параметр WParam в SendMessage равен 1, то все табуляторы будут установлены в величину, передаваемую в массиве Tabs. Не забывайте для включения табуляторов устанавливать свойство WantTabs компонента TMemo в True.
procedure TForm1.FormCreate( Sender : TObject );
const
TabInc : LongInt = 10;
begin
SendMessage( Memo1.Handle, EM_SetTabStops, 1, Longint( @TabInc ) );
end;
|
Наилучшее место для показа окна с логотипом - в исходном коде проекта после первого Application.FormCreate и перед Application.Run. Этим мы осуществляем создание формы на лету и показ ее до момента фактического запуска приложения.
program Project1;
uses Forms, Unit1 in 'UNIT1.PAS' {Form1}, Splash;
{$R *.RES}
var
SplashScreen : TSplashScreen; {в модуле Splash}
begin
Application.CreateForm(TForm1, Form1);
SplashScreen := TSplashScreen.Create(Application);
try
SplashScreen.Show;
SplashScreen.Update; {Обрабатываем любые сообщения Windows, касающиеся отрисовки}
{
осуществите остальные CreatForms или другие
действия прежде чем приложение запустится. Если процедура запуска
имеет продолжительное время, то для того, чтобы окно реагировало
на системные сообщения, необходимо переодически давать команду
Application.ProcessMessages.
}
finally {Убедитесь что окно с логотипом освобождается}
SplashScreen.Free;
end;
Application.Run;
end.
|
SpeedButton в действительности никогда не получает фокуса, поэтому активный элемент управления его и не теряет, следовательно, у активного элемента управления события OnExit не происходит.
Имеется единственный способ вызвать событие OnExit у активного элемента управления - вызвать его явно при наступлении события OnClick у кнопки SpeedButton. Для примера:
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
If ActiveControl is TEdit then
(ActiveControl as TEdit).OnExit(ActiveControl);
end;
|
Так работают дочерние MDI окна. В этой ситуации VCL не перекрывает поведения Windows, такие правила диктует сама система.
Непроверенное предположение: В процедуре FormCreate попробуйте установить необходимые значения свойствам Top, Left, Width и Height. FormCreate дочерней MDI формы будет вызвано прежде, чем будет показано само окно.
Если имя используемого вами .RES-файла совпадает с именем .DPR-файла, Delphi перезапишет его, создав собственный .RES-файл с этим именем. Кроме того, проектный RES-файл предназначен только для менеджера Delphi-проекта, не редактируйте и не добавляйте к нему свои ресурсы.
Прокрутка формы осуществляется с помощью изменения свойства Position свойства формы VertScrollbar или HorzScrollbar. Следующий код показывает как это можно сделать:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
const
PageDelta = 10;
begin
With VertScrollbar do
if Key = VK_NEXT then Position := Position+PageDelta
else if Key = VK_PRIOR then Position := Position-PageDelta;
end;
|
Примечание: Это может не работать, если активный элемент управления (типа TMemo) также использует PgUp & PgDn.
Для заполнения сразу нескольких строк в компоненте TListbox или TMemo может использоваться метод SetText. Методу SetText передается строка с терминирующим нулем, где каждая строка сопровождается разделителем, символом возврата каретки - #13. Пояснительный пример:
Listbox1.Items.SetText('aaaaa'#13'bbbbb'#13'ccccc')
|
При этом ListBox отобразит следующий текст:
aaaaa bbbbb cccccПримечание: Предпочтительным методом заполнения ListBox или Memo является метод Add их соответствующих свойств Items и Lines.
Один из способов решения задачи состоит в присваивании полю Tag уникального числа, создание общего обработчика события для всех кнопок и проверки содержимого поля Tag передаваемого объекта Sender. Назначьте всем кнопкам группы один и тот же обработчик события OnClick. Обработчик события должен выглядеть приблизительно так:
procedure TForm1.Button1Click(Sender: TObject); var cap: string;
begin
case TButton(sender).Tag of
1: ShowMessage('Нажата первая кнопка');
2: ShowMessage('Нажата вторая кнопка');
2: ShowMessage('Нажата третья кнопка');
end;
end;
|
При добавлении компонента на страницу TabbedNotebook во время выполнения программы, ссылка на желаемую страницу должна быть назначена свойству нового компонента Parent прежде, чем она будет показана. Получить доступ к страницам TTabbedNotebook во время выполнения программы можно через элементы-объекты свойства-массива TabbedNotebook Pages. Другими словами, компоненты страницы сохраняются как объекты, "прикрепленные" к имени страницы в списке строк свойства Pages. Вот пример создания кнопки на второй странице компонента TabbedNotebook1:
var
NewButton : TButton;
begin
NewButton := TButton.Create(Self);
NewButton.Parent := TWinControl(TabbedNotebook1.Pages.Objects[1])
...
|
Вот как страница TNotebook может быть использована в качестве родителя при создании на ней нового компонента:
NewButton.Parent := TWinControl(Notebook1.Pages.Objects[1])
|
Вот как закладка TTabSet может быть использована в качестве родителя при создании на ней нового компонента:
NewButton.Parent := TWinControl(TabSet1.Tabs.Objects[1])
|
Такую характеристику поддерживает продукт фирмы TurboPower Orpheus. Для получения дополнительной информации посетите сервер компании TURBOPOWER.
Просто проверьте, имеет ли ActiveControl тип TEdit, и, если да, то выполняйте желаемую операцию: вырезайте, копируйте или вставляйте. Для примера:
if (ActiveControl is TEdit) then
TEdit(ActiveControl).CopyToClipboard;
|
События существуют, но они не опубликованы. Вы можете создать простой наследник TDBGrid и опубликовать их.
ModalForm1 := TModalForm1.Create(Self);
ModalForm1.ShowModal;
|
В отсутствие обработчика OnClose установите параметр Action в caFree, ваш код создает каждую новую форму вызовом TModalForm1.Create(Self), но предыдущий экземпляр формы не уничтожается. Все предыдущие экземпляры форм "ModalForm1" так и остаются "болтаться" в Windows.
Чтобы форма освобождала свои ресурсы, можно также использовать метод Free. Вот демонстрация этого метода:
try
ModalForm1.ShowModal;
{ здесь размещается необходимый код }
finally
ModalForm1.Free;
end;
|
Если вы собираетесь использовать RadioGroup, то логичным будет для создания RadioButton воспользоваться списком строк Items. При этом RadioButton не должны быть объединены в одну группу, эта причина того, почему к элементу RadioGroup нельзя обратиться как к отдельному компоненту RadioButton.
Перекройте метод CreateParams:
procedure TMyForm.CreateParams(var Params:TCreateParams);
begin
inherited CreateParams(Params);
Style := Style or CS_BYTEALIGNWINDOW;
end;
|
Примечание: Байтовое выравнивание практически не описано в документации по Windows. Имеет значение только для черно-белого, EGA и 16-цветного VGA видео-режима. Все режимы с более высоким разрешением всегда выравнивают байты.
При создании формы события наступают в следующем порядке: OnCreate, OnShow, OnPaint, OnActivate, OnResize и снова OnPaint.
Свойство FormStyle определяет стиль создаваемого окна и обычно устанавливается в обработчике события OnCreate, тем не менее, вы можете его изменить и после создания дескриптора окна, только не в обработчиках событий OnActivate, OnShow или OnHide. Ваша проблема заключается в том, что вы пытаетесь изменить стиль формы при возникновении событий OnShow и OnHide.
Для того, чтобы заставить выглядеть компонент чуть утопленным или приподнятым, разместите его на компоненте TBevel или TPanel, которые имеют свойства соответствующего назначения.
Исходный код VCL не содержит код "tab"-компонентов из-за юридических причин. Тем не менее, исходники интерфейса (interface source) расположены в каталоге DELPHI\DOC и имеют расширение INT.
Примечание: зарегистрированные владельцы исходного кода Delphi RTL могу запросить исходный код TTabSet и TTabbedNotebook у подразделения Borland Corporate Affairs. Инструкция находится в файле readme исходного кода RTL. [000892]