На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Rouse_, jack128, Krid
  
    > Прозрачная форма и НЕ прозрачные компоненты
      Тут у нас несколько раз подымались темки о прозрачности формы в ХР, но так чтобы были не прозрачны контролы или на оборот. Но единственное чем заканчивались подобные темы – «Не возможно в XP такое». Ну, как говорится «Если сильно хочется то можна». Темболее что этот эффект уже используется в нескольких программах (например фотошоп десятый).
      Что мы зделаем? Создадим две формы и зделаем так чтобы они реагировали как одна.
      Приступим.
      Создадим новый модуль (В последствии его будем подключать к нашим формам).
      Создим два типа: TChildForm (дочернее окно), TParentForm (родительское окно).
      ExpandedWrap disabled
          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;

      Если Вы заметили то в каждом класе в нутри будет хранится дочерняя/родительская форма.
      Теперь по порядку с обработчиками дочирной формы:
      Кто создаст тот и родитель :)
      ExpandedWrap disabled
        constructor TChildForm.Create(AOwner: TComponent);
        begin
          if AOwner<>nil then ParentForm:=TParentForm(AOwner);
          inherited;
        end;

      Ну и самое главное перекрыть CreateParams, так как нам нужно чтобы дочирняя форма всегда была над родительской.
      ExpandedWrap disabled
        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;

      Ну и дополнтеные, не столь важные обработчики.
      Отслежывание изминения заголовка
      ExpandedWrap disabled
        procedure TChildForm.CMTextChanged(var Message: TMessage);
        begin
          if ParentForm <> nil then
            ParentForm.Caption := Caption;
        end;

      поддержка авкивности бордюра, когда активна дочерняя форма
      ExpandedWrap disabled
        procedure TChildForm.WMActivate(var Message: TWMActivate);
        begin
          if ParentForm <> nil then
            SendMessage(ParentForm.Handle, WM_NCACTIVATE, 1, 0);
        end;

      Теперь обработчики главной формы:
      Обработка ресайза или перемещения формы
      ExpandedWrap disabled
        procedure TParentForm.WMWindowPosChanged(var MSG: TWMWindowPosChanged);
        begin
           inherited;
           if FChildForm <> nil then FChildForm.BoundsRect := GetRect;
        end;

      Получение позиции для дочерней формы
      ExpandedWrap disabled
        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
      ExpandedWrap disabled
        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 которая заменит оригинальную
      ExpandedWrap disabled
        procedure TChildForm.close;
        begin
          if ParentForm <> nil then
            if not ParentForm.CloseFlag then ParentForm.Close;
            // проверяем. Может главная уже делает закритие дочерней
            // если нет то закрываем главную, а не дочернюю
        end;

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

      Эта тема была разделена из темы "Прозрачная форма и НЕ прозрачные компоненты"
      Прикреплённый файлПрикреплённый файлAlphaForm.zip (22.4 Кбайт, скачиваний: 392)
      0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
      0 пользователей:


      Рейтинг@Mail.ru
      [ Script execution time: 0,0225 ]   [ 16 queries used ]   [ Generated: 28.03.24, 19:19 GMT ]