Как сделать одно и то же отверстие в двух формах на удаленном экране (на стороне клиента), основываясь на области, нарисованной на стороне сервера?
У меня есть следующий код и я хочу нарисовать одну и ту же дыру в двух формах на удаленном экране (на стороне клиента), основываясь на области, нарисованной на стороне сервера.
У меня одна и та же форма (Form3) с обеих сторон (сервер и клиент), которая является "зеркалом", где я рисую область, которая должна оставаться внутри этой же формы на стороне клиента.
У Form3 на стороне сервера 50% от макс.
AlphaBlend
значение, это необходимо, чтобы увидеть удаленный экран за Form3.
Прежде всего, я хочу сказать, что я получаю удаленный экран на стороне сервера, и положение щелчка мыши работает, как ожидалось.
Тогда это моя проблема:
Следующий код выдает результат, показанный на изображении выше. Я думаю, что этот код прав, но отсутствует, выровняйте эту дыру с Form3.
Кто-то может помочь с этим? извините, если это плохой вопрос, но это все мои настоящие проблемы, и я попытался выразить все в этом вопросе о лучшем способе, который я смог.
Это весь соответствующий код:
Сторона сервера:
Форма 2 (где я вижу удаленный экран):
unit Unit2;
interface
uses
Unit1;
type
TForm2 = class(TForm)
Panel1: TPanel;
CheckBox1: TCheckBox;
ScrollBox1: TScrollBox;
Image1: TImage;
PaintBox1: TPaintBox;
procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
procedure PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PaintBox1Paint(Sender: TObject);
private
{ Private declarations }
FSelecting: Boolean;
FSelection: TRect;
pos1, pos2, pos3, pos4: Integer;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if CheckBox1.Checked then
begin
FSelection.Left := X;
FSelection.Top := Y;
FSelecting := true;
end;
end;
procedure TForm2.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
begin
if FSelecting then
begin
FSelection.Right := X;
FSelection.Bottom := Y;
pbRec.Invalidate;
end;
end;
procedure TForm2.PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if CheckBox1.Checked then
begin
FSelecting := false;
FSelection.Right := X;
FSelection.Bottom := Y;
PaintBox1.Invalidate;
FSelection.NormalizeRect;
if FSelection.IsEmpty then
begin
// None selection was made on PaintBox
end
else
begin
pos1 := FSelection.Left;
pos2 := FSelection.Top;
pos3 := X;
pos4 := Y;
end;
end;
end;
procedure TForm2.PaintBox1Paint(Sender: TObject);
begin
if CheckBox1.Checked then
begin
PaintBox1.Canvas.Brush.Style := bsClear;
PaintBox1.Canvas.Pen.Style := psSolid;
PaintBox1.Canvas.Pen.Color := clRed;
PaintBox1.Canvas.Rectangle(FSelection);
end;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
Socket: TCustomWinSocket;
begin
Socket := TCustomWinSocket(Form1.LV1.Selected.SubItems.Objects[0]);
if CheckBox1.Checked then
begin
Socket.SendText(intToStr(pos1) + ';' + intToStr(pos2) + ';' +
intToStr(pos3) + ';' + intToStr(pos4));
end;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
Form3 := TForm3.Create(Self);
Form3.Show;
end;
Форма 2.DFM:
object Panel1: TPanel
Left = -1
Top = 0
Width = 773
Height = 89
Anchors = [akTop]
BevelEdges = [beLeft, beRight]
ParentDoubleBuffered = False
TabOrder = 0
end
object ScrollBox1: TScrollBox
Left = 0
Top = 0
Width = 765
Height = 472
HorzScrollBar.Smooth = True
HorzScrollBar.Tracking = True
VertScrollBar.Smooth = True
VertScrollBar.Tracking = True
Align = alClient
TabOrder = 1
object Image1: TImage
Left = 0
Top = 0
Width = 1362
Height = 621
AutoSize = True
end
object PaintBox1: TPaintBox
Left = 0
Top = 0
Width = 1362
Height = 621
Align = alClient
OnMouseDown = PaintBox1MouseDown
OnMouseMove = PaintBox1MouseMove
OnMouseUp = PaintBox1MouseUp
OnPaint = PaintBox1Paint
ExplicitWidth = 1364
ExplicitHeight = 622
end
Form3 ("зеркальная" форма, которая также одинакова на стороне клиента), эта форма централизована в соответствии с разрешением удаленного экрана:
unit Unit3;
interface
uses
...
type
TForm3 = class(TForm)
Panel1: TPanel;
Image1: TImage;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure CreateParams(var pr: TCreateParams); override;
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
uses
Unit1;
{$R *.dfm}
procedure TForm3.FormCreate(Sender: TObject);
var
MyString: String;
Splitted: TArray<String>;
begin
MyString := Form1.LV1.Selected.SubItems[6]; // Resolution of remote screen
Splitted := MyString.Split(['x']);
Self.Left := (Integer(Splitted[0]) - Self.Width) div 2;
Self.Top := (Integer(Splitted[1]) - Self.Height) div 2;
end;
procedure TForm3.CreateParams(var pr: TCreateParams);
begin
inherited;
pr.WndParent := Form2.Handle;
pr.ExStyle := pr.ExStyle or WS_EX_TOPMOST or WS_EX_TRANSPARENT;
pr.ExStyle := WS_EX_TRANSPARENT or WS_EX_TOPMOST;
end;
Форма 3 .DFM:
object Form3: TForm3
Left = 328
Top = 143
BorderStyle = bsNone
ClientHeight = 567
ClientWidth = 526
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
Position = poScreenCenter
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Panel1: TPanel
Left = 0
Top = 0
Width = 801
Height = 569
TabOrder = 0
object Image1: TImage
Left = 1
Top = 1
Width = 799
Height = 567
Align = alClient
ExplicitLeft = 2
ExplicitTop = 0
ExplicitHeight = 447
end
object Label1: TLabel
Left = 92
Top = 69
Width = 28
Height = 13
Caption = 'Nome'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clBlack
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
ParentColor = False
ParentFont = False
end
Сторона клиента:
Форма 2 (форма "шкафчик"):
unit Unit2;
private
{ Private declarations }
procedure CreateParams(var Params: TCreateParams); override;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.WndParent := Application.Handle;
Params.ExStyle := Params.ExStyle or WS_EX_TOPMOST or WS_EX_TRANSPARENT;
Params.ExStyle := WS_EX_TRANSPARENT or WS_EX_TOPMOST;
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
windowstate := wsmaximized;
Top := 0;
Left := 0;
Height := Screen.Height;
Width := Screen.Width;
end;
{
Properties of Form2:
Align => alNone
AlphaBlend => True
BorderStyle => BsNone
}
end.
Форма 3 (то же самое со стороны сервера):
unit Unit3;
interface
uses
...
type
TForm3 = class(TForm)
Panel1: TPanel;
Label1: TLabel;
procedure FormShow(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure CreateParams(var pr: TCreateParams); override;
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
uses
Unit2;
{$R *.dfm}
procedure TForm3.FormCreate(Sender: TObject);
begin
Self.Left := (GetSystemMetrics(SM_CXSCREEN) - Self.Width) div 2;
Self.Top := (GetSystemMetrics(SM_CYSCREEN) - Self.Height) div 2;
end;
procedure TForm3.FormShow(Sender: TObject);
begin
ShowWindow(Application.Handle, SW_HIDE);
end;
procedure TForm3.CreateParams(var pr: TCreateParams);
begin
inherited;
pr.WndParent := Form2.Handle;
end;
{
Properties of Form3:
Align => alNone
BorderStyle => BsNone
}
end.
Получение зоны на стороне клиента:
procedure CS1_Read(Self: Pointer; Sender: TObject; Socket: TCustomWinSocket);
var
X1, X2, Y1, Y2: Integer;
List: TStrings;
FormRegion, HoleRegion: HRGN;
StrCommand: string;
begin
if Pos(';', StrCommand) > 0 then
begin
List := TStringList.Create;
try
ExtractStrings([';'], [], PChar(StrCommand), List);
Form3 := TForm3.Create(Form2); // The Form2 already was created and is showing
X1 := Round(StrToIntDef(List[0], 0) - Form2.Left);
Y1 := Round(StrToIntDef(List[1], 0) - Form2.Top);
X2 := Round(StrToIntDef(List[2], 0) - Form2.Left);
Y2 := Round(StrToIntDef(List[3], 0) - Form2.Top);
FormRegion := CreateRectRgn(0, 0, Form3.Width, Form3.Height);
HoleRegion := CreateRectRgn(X1, Y1, X2, Y2);
CombineRgn(FormRegion, FormRegion, HoleRegion, RGN_DIFF);
SetWindowRgn(Form3.handle, FormRegion, true);
FormRegion := CreateRectRgn(0, 0, Form2.Width, Form2.Height);
HoleRegion := CreateRectRgn(X1, Y1, X2, Y2);
CombineRgn(FormRegion, FormRegion, HoleRegion, RGN_DIFF);
SetWindowRgn(Form2.handle, FormRegion, true);
Form3.ShowModal;
Form3.Release;
finally
List.Free;
end;
end;
end;
1 ответ
На стороне клиента у вас есть полупрозрачная серая форма (Form2), которая имеет размер экрана. Поверх этой формы у вас есть непрозрачная белая форма (Form3), центрированная на экране. В Form3
у вас есть прямоугольное отверстие в Top = Y
а также Left = X
в координатах Form3
,
Я понимаю, что ваша проблема в том, что вы хотите нарисовать отверстие в Form2, которое выровнено с отверстием в Form3.
Вам необходимо преобразовать систему координат Form3
к тому из Form2
с простым дополнением:
Form2.Hole.Left := Form3.Left + Form3.Hole.Left;
Form2.Hole.Top := Form3.Top + Form3.Hole.Top;
Это бы выровнять отверстия. Кажется, вы пытаетесь сделать что-то подобное в своих расчетах, но вы ссылаетесь на Form2.Left
а также Form2.Top
что бесполезно, так как они оба равны 0.
Если я неправильно понял ваш вопрос, и вы на самом деле хотели бы Form3
отверстие для выравнивания с Form2
отверстие, то вам нужно будет двигаться Form3
вверху - слева от экрана и не центрировать его...
... Или, учитывая ваш комментарий: если я рисую на стороне сервера в области далеко Form3
(клиент), например, больше в левой части экрана, нарисуйте только отверстие Form2
и если я нарисую больше к середине экрана, то выровнять оба выровненных отверстия можно, просто поменяв местами термины:
Form3.Hole.Left := Form2.Hole.Left - Form3.Left
Form3.Hole.Top := Form2.Hole.Top - Form3.Top
Это преобразует Form2
координаты Form3
Координаты, которые могут стать отрицательными значениями (например, вне формы) в ситуациях, подобных вашему примеру.
Адаптируя вышеизложенное к своему коду, вам необходимо сначала разобраться с регионом формы 2 с Form2.Hole
координаты, затем вычесть Form3
координаты (Left
а также Top
) из X1..Y2, а затем иметь дело с областью Form3 *.
X1 := Round(StrToIntDef(List[0], 0) - Form2.Left); // Form2 props can be removed as hardcoded to 0
Y1 := Round(StrToIntDef(List[1], 0) - Form2.Top); // -"-
X2 := Round(StrToIntDef(List[2], 0) - Form2.Left); // -"-
Y2 := Round(StrToIntDef(List[3], 0) - Form2.Top); // -"-
FormRegion := CreateRectRgn(0, 0, Form2.Width, Form2.Height);
HoleRegion := CreateRectRgn(X1, Y1, X2, Y2);
CombineRgn(FormRegion, FormRegion, HoleRegion, RGN_DIFF);
SetWindowRgn(Form2.handle, FormRegion, true);
X1 := X1 - Form3.Left;
Y1 := Y1 - Form3.Top;
X2 := X2 - Form3.Left;
Y2 := Y2 - Form3.Top;
FormRegion := CreateRectRgn(0, 0, Form3.Width, Form3.Height);
HoleRegion := CreateRectRgn(X1, Y1, X2, Y2);
CombineRgn(FormRegion, FormRegion, HoleRegion, RGN_DIFF);
SetWindowRgn(Form3.handle, FormRegion, true);
редактировать
Кажется нелогичным, что ваш Server.Form2
не такой же размер, как экран (и, следовательно, Client.Form2
). Но, возможно, я так и не понял, для каких целей используется установка.
Во всяком случае, с одинаковым размером, по центру Form3
, но с разными размерами экрана на сервере и на клиенте, вам нужно настроить Form3.Hole
координаты на клиенте с половиной разницы между размерами экрана сервера и клиента, или, так как Form3
формы центрированы, вы можете рассчитать горизонтальную и вертикальную коррекцию как
ResolutionCorrectionX := Server.Form3.Left - Client.Form3.Left;
ResolutionCorrectionY := Server.Form3.Top - Client.Form3.Top;
что вы затем добавляете к X- и Y-координатам для HoleRegion
формы 3.
X1 := X1 - Form3.Left + ResolutionCorrectionX; // and similar for X2, Y1 and Y2
Кстати, просто из любопытства, почему вы используете Round()
для расчетов на основе целых чисел?