|
Интерфейс присоединения Drag-and-Dock
Эта возможность появилась в Delphi
4. Она "подсмотрена" опять-таки у разработчиков
из Microsoft, внедривших плавающие панели инструментов
в MS Office, Internet Explorer и другие продукты (рис.
27.2).
Речь идет о том, что ряд элементов
управления (а конкретно — потомки класса xwinControl)
могут служить носителями (доками) для других элементов
управления с возможностью их динамического перемещения
из одного дока в другой при помощи мыши. Перетаскивать
можно практически все — от статического текста до форм
включительно. Пример использования техники Drag-and-Dock
дает сама среда разработки Delphi — с ее помощью можно
объединять на экране различные инструменты, такие как
Инспектор объектов и Менеджер проекта.
Как и в случае с технологией перетаскивания
Drag-and-Drop, возможны два варианта реализации техники
Drag-and-Dock: автоматический и ручной. В первом случае
дело сводится к установке нужных значений для нескольких
свойств, а остальную часть работы берет на себя код
VCL; во втором, как следует из названия, вся работа
возлагается на программиста.
Итак, что же нужно сделать для внедрения
Drag-and-Dock? В Инспекторе объектов необходимо изменить
значение свойства DragKind на
dkDock, a свойства
DragMode — на dmAutomatic.
Теперь этот элемент управления можно перетаскивать с
одного носителя-дока на другой.
Носителем других компонентов (доком)
может служить потомок TwinControl.
У него есть свойство Docksite,
установка которого в True разрешает
перенос на него других компонентов. Если при этом еще
и установить свойство AutoSize
в True, док будет автоматически
масштабироваться в зависимости от того, что на нем находится.
В принципе, этими тремя операциями исчерпывается минимальный
обязательный набор.
Рис. 27.2. Плавающие
панели инструментов
Естественно, для программиста предусмотрены
возможности контроля за этим процессом. Каждый переносимый
элемент управления имеет два события, возникающие в
моменты начала и конца переноса:
type TStartDockEvent
= procedure(Sender: TObject;
var DragObject: TDragDockObject)
of object;
TEndDragEvent = procedure(Sender,
Target: TObject; X, Y: Integer) of object;
В первом из методов
sender — это переносимый объект, a
DragObject — специальный объект, создаваемый
на время процесса переноса и содержащий его свойства.
Во втором sender — это также
переносимый объект, a Target
— объект-док.
Док тоже извещается о событиях во время
переноса:
type TGetSitelnfoEvent
= procedure(Sender: TObject; DockClient: TControl;
var InfluenceRect:
TRect; MousePos: TPoint;
var CanDock: Boolean)
of object;
TDockOverEvent =
procedure(Sender: TObject; Source: TDragDockObject;
X, Y: Integer; State:
TDragState; var Accept: Boolean) of object;
TDockDropEvent =
procedure(Sender: TObject;
Source: TDragDockObject;
X, Y: Integer) of
object;
TUnDockEvent = procedure(Sender:
TObject; Client: TControl; NewTarget:
TWinControl; var
Allow: Boolean) of object;
Как только пользователь нажал кнопку
мыши над переносимым компонентом и начал сдвигать его
с места, всем потенциальным докам (компонентам, свойство
которых Docksite установлено
в True) рассылается событие onGetsiteinfo.
С ним передаются параметры: кто хочет "приземлиться"
(параметр Dockclient) и где (MousePos).
В ответ док должен сообщить решение, принимает он компонент
(параметр CanDock) и предоставляемый
прямоугольник (infiuenceRect)
или нет. При помощи этого события можно принимать только
определенные элементы управления, как показано в примере:
procedure TForml.PanellGetSitelnfо(Sender:
TObject; DockClient: TControl; var InfiuenceRect:
TRect; MousePos: TPoint;
var CanDock: Boolean);
begin
if DockClient is
TBitBtn then CanDock := False;
end;
Два последующих события в точности
соответствуют своим аналогам из механизма переноса Drag-and-Drop).
Событие onDockOver происходит
при перемещении перетаскиваемого компонента над доком,
OnDockDrop — в момент его отпускания.
Наконец, onUnDock сигнализирует
об уходе компонента с дока и происходит в момент его
"приземления" в другом месте.
Между доком и содержащимися на нем
элементами управления есть двусторонняя связь. Все "припаркованные"
элементы управления содержатся в векторном свойстве
Dockclients, а их количество можно
узнать из свойства
DockClientCount:
s : = ' ' ;
for i := 0 to Panell.DockClientCount-1
do AppendStr(s,Panell.DockClients[i].Name+#$D#$A);
ShowMessage(s) ;
С другой стороны, если элемент управления
находится на доке, то ссылка на док располагается в
свойстве HostDocksite. С ее помощью
можно установить, где находится элемент, и даже поменять
свойства дока:
procedure TMyForm.ButtonlEndDock(Sender,
Target: TObject; X, Y: Integer); begin
(Sender as TControl).HostDockSite.SetTextBuf(pChar((Sender
as TControl).Name));
end;
Компоненты можно не только переносить
с одного дока на другой, но и отпускать в любом месте.
Хотя сам по себе компонент TControl
и его потомки не являются окнами Windows, но специально
для этого случая создается окно-носитель. Свойство FloatingDockSiteClass
как раз и определяет класс создаваемого окна. По умолчанию
для большинства компонентов значение этого свойства
равно TCustomDockForm. Это — форма,
которая обладает свойствами дока и создается в момент
отпускания элемента управления вне других доков. Внешне
она ничем не отличается от обычной стандартной формы.
Если вы хотите, чтобы ваша плавающая панель инструментов
выглядела по- особенному, нужно породить потомка от
класса TCustomDockForm и связать
свойство FloatingDockSiteCiass
с этим порожденным классом:
TMyCustomFloatingForm
= class(TCustomDockForm)
public
constructor Create(AOwner:
TComponent);
override;
end;
constructor TMyCustomFloatingForm.Create(AOwner:
TComponent};
begin
inherited Create(AOwner);
BorderStyle := bsNone;
end;
procedure TForml.FormCreate(Sender:
TObject);
begin
ToolBarl.FioatingDockSiteCiass
:= TMyCustomFloatingForm; end;
В этом примере решена типовая задача
— сделать так, чтобы несущее окно плавающей панели инструментов
не содержало заголовка. Внешний вид таких панелей приведен
на рис. 27.3.
Переносить компоненты можно не только
с помощью мыши, но и программно. Для этого есть пара
методов ManualDock и ManualFioat.
В приводимом ниже примере нажатие кнопки с именем
BitBtnl переносит форму custForm
на док MainForm.Paneil и размещает
ее по всей доступной площади (параметр выравнивания
alclient). Нажатие кнопки
BitBtn2 снимает эту форму с дока и выравнивает
ее по центру экрана. В свойствах UndockHeight
и undockwidth хранятся высота
и ширина элемента управления на момент, предшествующий
помещению на док:
procedure TMainForm.BitBtnlClick(Sender:
TObject);
begin
GustForm.ManualDock
(MainForm.Pane11,nil,alClient);
end;
procedure TMainForm.BitBtn2Click(Sender:
TObject);
begin
with CustForm do
begin ManualFloat(Rect((Screen.Width-UndockWidth)
div 2,
(Screen.Height-UndockHeight)
div 2, (Screen.Width+UndockWidth) div 2, (Screen.Height+UndockHeight)
div 2) );
end;
Рис. 27.3. Плавающие
панели инструментов без заголовка окна
Полное рассмотрение внутреннего устройства
механизмов Drag-and-Dock потребовало бы расширения объема
этой главы. Тем, кто хочет использовать их на все 100%,
рекомендуем обратиться к свойствам useDockManager
и DockManager. Последнее представляет
собой СОМ-интерфейс, позволяющий расширить возможности
дока, вплоть до записи его состояния в поток (класс
TStream).
|