При выводе прозрачного окна, окна или элементы управления, расположенные под
ним, также видны. При перемещении невидимого окна, при условии, что оно не
скрывается/выводится вновь, оно сохраняет "снимок" графической области, которая
была расположена под ним в момент вывода (а именно: окна или видимые
компоненты).
Взгляните на модуль, приведенный ниже, в нем предлагается решение проблемы
невидимого окна.
{ Начните с нового проекта.
Разместите на форме 4 кнопки и 1 компонент CheckBox.
Создайте обработчик события OnClick как показано ниже
Во время выполнения программы, если вы нажимаете на Button3,
щелчок по Button1 будет перехватываться InvWin; если вы
нажимаете на Button4, щелчок по Button2 будет перехватываться
InvWin. Поскольку "невидимое" окно первоначально представляет
собой простой дескриптор, элемент управления, расположенный
под ним, должен быть перерисован. Из-за этого существует
проблема мерцания, происходящая по сценарию как, будто вы
щелкнули по Button3 и Button4. При щелчке на CheckBox1,
InvWin.Invisible устанавливается в True. Это позволяет окну
не перерисовываться. Поскольку окно у нас теперь истинно
невидимое, то для устранения мерцания мы целенаправленно
посылаем необходимым окнам сообщение WM_SETREDRAW. }unit Invwin1;
interfaceuses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TInvWin = class(TWinControl)
private
fOnControl: TControl;
fInvisible: Boolean;
procedure WMPaint(varMessage: TWMPaint); message WM_PAINT;
protectedprocedure CreateParams(var Params: TCreateParams); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure SetOnControl(Value: TControl); virtual;
publicconstructor Create(aOwner: TComponent);
property OnControl: TControl read fOnControl write SetOnControl;
property Invisible: Boolean read fInvisible write fInvisible;
end;
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
CheckBox1: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure CheckBox1Click(Sender: TObject);
private{ Private declarations }public{ Public declarations }
InvWin: TInvWin;
end;
var
Form1: TForm1;
implementation{$R *.DFM}constructor TInvWin.Create(aOwner: TComponent);
begininherited Create(aOwner);
ControlStyle := ControlStyle + [csOpaque];
end;
procedure TInvWin.CreateParams(var Params: TCreateParams);
begininherited CreateParams(Params);
Params.ExStyle := Params.ExStyle or WS_EX_TRANSPARENT;
end;
procedure TInvWin.WMPaint(varMessage: TWMPaint);
var
DC: THandle;
PS: TPaintStruct;
beginifnot Invisible thenbeginifMessage.DC = 0 then
DC := BeginPaint(Handle, PS)
else
DC := Message.DC;
PatBlt(DC, 0, 0, 5, 5, BLACKNESS);
PatBlt(DC, Width - 6, 0, 5, 5, BLACKNESS);
PatBlt(DC, 0, Height - 6, 5, 5, BLACKNESS);
PatBlt(DC, Width - 6, Height - 6, 5, 5, BLACKNESS);
ifMessage.DC = 0 then
EndPaint(Handle, PS);
end;
end;
procedure TInvWin.MouseDown(Button: TMouseButton; Shift:
TShiftState; X, Y
: Integer);
begin
ShowMessage('MouseDown над невидимым окном');
end;
procedure TInvWin.SetOnControl(Value: TControl);
var
Rect: TRect;
beginif Value <> fOnControl thenbegin{ Используйте только WM_SETREDRAW, если окно полностью невидимо }if Invisible and (Parent <> nil) then
Parent.Perform(WM_SETREDRAW, 0, 0);
if fOnControl <> nilthen
Visible := False;
if Value <> nilthenbegin
Rect := Value.BoundsRect;
InflateRect(Rect, 2, 2);
BoundsRect := Rect;
end;
fOnControl := Value;
if fOnControl <> nilthen
Visible := True;
{ Используйте только WM_SETREDRAW, если окно полностью невидимо }if Invisible and (Parent <> nil) then
Parent.Perform(WM_SETREDRAW, 1, 0);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
InvWin := TInvWin.Create(Self);
InvWin.Visible := False;
InvWin.Parent := Self;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('MouseClick над Button1');
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage('MouseClick над Button2');
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
InvWin.OnControl := Button1;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
InvWin.OnControl := Button2;
end;
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
InvWin.OnControl := nil;
InvWin.Invisible := CheckBox1.Checked;
end;
end.
Перевод контента на русский язык:
Это реализация компонента прозрачного окна в Delphi, который позволяет пользователю создавать прозрачное окно, которое может перехватывать клики мыши над другими контролами ниже него.
Класс TInvWin - это пользовательский контроль, наследующийся от TWinControl. Он имеет несколько свойств и методов:
Invisible: булевое свойство, указывающее, должен ли быть окно невидимым или нет.
OnControl: свойство, которое specifies which control should receive mouse clicks when the transparent window is clicked.
MouseDown: override standard MouseDown method, which displays a message box when the user clicks on the transparent window.
WMPaint: override standard WMPaint method, which paints a black rectangle around the edges of the window to create a transparent effect.
CreateParams: override standard CreateParams method, which sets the extended style of the window to include transparency.
SetOnControl: метод, который sets the OnControl property and adjusts the visibility of the window accordingly.
Класс TForm1 - это форма, содержащая несколько кнопок и чекбокс. Когда пользователь кликнет на одну из кнопок, она установит свойство OnControl прозрачного окна в эту кнопку. Когда пользователь включит или отключит чекбокс, он будет переключать видимость окна.
Некоторые предложения по улучшению кода:
Вместо использования функции PatBlt для рисования черного прямоугольника вокруг краев окна, вы могли бы использовать более эффективный метод,such as drawing a border around the window.
Метод WMPaint вызывается только когда окно нужно перерисовать. Вы можете оптимизировать этот метод, рисуя только необходимые части окна.
Метод SetOnControl является quite complex и выполняет несколько задач одновременно. Вам может быть полезно разбить его на отдельные методы, которые выполняют конкретные задачи, such as setting the OnControl property and adjusting the visibility of the window.
Код мог бы быть улучшен с помощью использования более описательных имен переменных и комментариев для объяснения того, что каждый часть кода делает.
Альтернативное решение:
Вместо создания пользовательского контрола, который перехватывает клики мыши над другими контролами, вы могли бы использовать прозрачный панель с таймером. Когда пользователь кликнет на панель, таймер будет запущен, который затем установит свойство OnControl в желаемый контроль.
Пример кода:
unitTransparentPanel;interfaceusesWindows,Messages,Controls,Forms,Graphics,StdCtrls;typeTTransparentPanel=class(TPanel)privateFTimer:TTimer;FOnControl:TControl;publicconstructorCreate(AOwner:TComponent);override;procedureSetOnControl(Value:TControl);end;varTransparentPanel:TTransparentPanel;implementationconstructorTTransparentPanel.Create(AOwner:TComponent);begininheritedCreate(AOwner);TimerInterval:=100;// adjust the timer interval as neededend;procedureTTransparentPanel.SetOnControl(Value:TControl);beginFOnControl:=Value;ifAssigned(FOnControl)thenFTimer.Enabled:=TrueelseFTimer.Enabled:=False;end;procedureTTransparentPanel.TimerTick(Sender:TObject);beginifAssigned(FOnControl)thenFOnControl.Perform(WM_LBUTTONDOWN,0,0);end;
В этом коде класс TTransparentPanel - это пользовательский панель с таймером. Когда пользователь кликнет на панель, таймер будет запущен, который затем установит свойство OnControl в желаемый контроль и симулирует событие нажатия левой кнопки мыши на этом контроле.
Обратите внимание, что это код использует сообщение WM_LBUTTONDOWN для симуляции клика мыши над целевым контролом. Это может не работать правильно, если целевой контроль имеет custom mouse handler или не виден на экране.
В статье описано решение проблемы мерцания в Delphi, вызванное невидимым окном с обработчиком события OnClick, которое перехватывает события с других элементов управления на форме. Для решения этой проблемы автор предложил модуль TInvWin, который позволяе
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.