ЖУРНАЛ "Территория Delphi". Выпуск №2, 2008 г.
О журнале
•  Главная
•  Авторы
•  Полезные ссылки
Delphi
•  Шифр простой подстановки
•  Прозрачная форма и не прозрачные компоненты
•  Поиск e-mail адресов
•  Защита исходного кода программы
•  Текст под углом
Устройства (hardware)
•  iRiver S10. Меняем оформление
Софт

•  Настройка jabber в Миранде IM

Администрирование. Linux
•  GPRS соединение в Linux via bluetooth
Администрирование. Windows
•  Установка jabber-сервера OpenFire на Windows

 

Копирование материалов журнала без размещения ссылки-источника запрещено!

Прозрачная форма и не прозрачные компоненты

В интернете часто видел темки о прозрачности формы в ХР, но так чтобы были не прозрачны контролы или на оборот. Но единственное чем заканчивались подобные темы – «Не возможно в XP такое». Ну, как говорится «Если сильно хочется то можна». Темболее что этот эффект уже используется в нескольких программах (например фотошоп десятый).
Что мы зделаем? Создадим две формы и зделаем так чтобы они реагировали как одна.
Приступим.
Создадим новый модуль (В последствии его будем подключать к нашим формам).
Создим два типа: TChildForm (дочернее окно), TParentForm (родительское окно).

  TChildForm = class(TForm)
  private
  protected
    ParentForm: TParentForm;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE;
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  public
    constructor Create(AOwner: TComponent); override;
  end;

  TParentForm = class(TForm)
  private
  protected
    FChildForm:TChildForm;
    procedure WMWindowPosChanged(var MSG: TWMWindowPosChanged); message WM_WINDOWPOSCHANGED;
  public
    function GetRect:TRect;
  published
    property ChildForm:TChildForm read FChildForm write FChildForm;
  end;


Если Вы заметили то в каждом класе в нутри будет хранится дочерняя/родительская форма.
Теперь по порядку с обработчиками дочирной формы:
Кто создаст тот и родитель

constructor TChildForm.Create(AOwner: TComponent);
begin
  if AOwner<>nil then ParentForm:=TParentForm(AOwner);
  inherited;
end;


Ну и самое главное перекрыть CreateParams, так как нам нужно чтобы дочирняя форма всегда была над родительской.

procedure TChildForm.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do
  begin
    if ParentForm <> nil then WndParent := ParentForm.handle; 
    // вот после этой строки мы и будет она висеть сверху
    // но если форма главная то этот код делать не обязательно

    // SetWindowLong(ParentForm.Handle, GWL_STYLE, Style);
    // тут можна передать стиль дочерней формы в 
    Style := WS_POPUP; // делаем форму без бордюра меню и тд.
  end;
end;

 

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

procedure TChildForm.CMTextChanged(var Message: TMessage);
begin
  if ParentForm <> nil then
    ParentForm.Caption := Caption;
end;

 

поддержка авкивности бордюра, когда активна дочерняя форма

procedure TChildForm.WMActivate(var Message: TWMActivate);
begin
  if ParentForm <> nil then
    SendMessage(ParentForm.Handle, WM_NCACTIVATE, 1, 0);
end;

Теперь обработчики главной формы:
Обработка ресайза или перемещения формы

procedure TParentForm.WMWindowPosChanged(var MSG: TWMWindowPosChanged);
begin
   inherited;
   if FChildForm <> nil then FChildForm.BoundsRect := GetRect;
end;


Получение позиции для дочерней формы

function TParentForm.GetRect: TRect;
var
  iBorder,iFrame,iCaption:integer;
begin
  iBorder := GetSystemMetrics(SM_CXBORDER);
  iFrame := GetSystemMetrics(SM_CYDLGFRAME);
  iCaption := GetSystemMetrics(SM_CYCAPTION);
  
  result.Left := BoundsRect.Left + iBorder + iFrame;
  result.Right := BoundsRect.Right - iBorder - iFrame;
  result.Bottom := BoundsRect.Bottom - iBorder - iFrame;
  result.Top := BoundsRect.Top + iBorder + iFrame + iCaption;

// то что сверху и снизу бедут делать идентычну работу 
// я просто зделал по меньше вызовов процедуры GetSystemMetrics
{  result.Left:=BoundsRect.Left + GetSystemMetrics(SM_CXBORDER)
                               + GetSystemMetrics(SM_CYDLGFRAME);
  result.Right:=BoundsRect.Right - GetSystemMetrics(SM_CYBORDER)
                                 - GetSystemMetrics(SM_CYDLGFRAME);
  result.Bottom:=BoundsRect.Bottom - GetSystemMetrics(SM_CXBORDER)
                                   - GetSystemMetrics(SM_CYDLGFRAME);
  result.Top:=BoundsRect.Top + GetSystemMetrics(SM_CYBORDER)
                             + GetSystemMetrics(SM_CYDLGFRAME)
                             + GetSystemMetrics(SM_CYCAPTION);        }
end;

 

Теперь если вы создадите две формы. подключите этот модуль. В одной форме поменяете родительский клас на TParentForm а в дочерней на TChildForm и запустите на выполнения то не должно ничего показывать того что это две формы. При этом вы можете поменять параметры AlphaBlend.
Но когда вам захочется закрыть форму то тут они будут разноглавствовать.
Ну что ж… перекрываем в главной обработчик CloseQuery

function CloseQuery: Boolean; override; 
…
function TParentForm.CloseQuery: Boolean;
var
  CAction: TCloseAction;
begin
  result := true;
  FCloseFlag := true; // ставим флаг, что главная 
                      //занимается закритием дочерней формы
  if FChildForm <> nil then 
  with FChildForm do
  begin
    result := CloseQuery; // вызываем у дочерней обработчик CloseQuery 
                          //(вдруг пользователь чтото сохранить хочет)
    if result then
    begin
      CAction := caNone;
      DoClose(CAction); // вызываем обработчик Close
                       // (но нам побарабону что он там вернет ведь решает главная )
      free;                        // Уничтожаем
    end;
  end;
  FCloseFlag := not result;
end;

 

Теперь при закрытии главной формы будет закрыватся и дочерняя, при этом будут вызваны все пользовательские обработчики. Но что будет если закрытие поступит из дочерней? И эта проблема решается в поле public созадем процедуру close которая заменит оригинальную

procedure TChildForm.close;
begin
  if ParentForm <> nil then
    if not ParentForm.CloseFlag then ParentForm.Close;
    // проверяем. Может главная уже делает закритие дочерней
    // если нет то закрываем главную, а не дочернюю
end;

вот и все.
Теперь вы можете експерементировать дальше.
Например если к дочерней форме применить пример Rouse_ (он не снашего форума но авторство нужно сохранять))
то будут не прозрачны только контролы.

а если немгого помучатся то можно зделать чтото симпотишнее
(Это у форму я украшивал для одного проэкта на авторун)

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

C уважением, ViktorXP

Бесплатный хостинг от EOMY.NET