Как сделать одно и то же отверстие в двух формах на удаленном экране (на стороне клиента), основываясь на области, нарисованной на стороне сервера? - PullRequest
0 голосов
/ 21 декабря 2018

У меня есть следующий код, и я хочу нарисовать одну и ту же дыру в двух формах на удаленном экране (на стороне клиента), основываясь на области, нарисованной на стороне сервера.

У меня такая же форма ( Form3 ) с обеих сторон (сервер и клиент), это "зеркало", где я рисую область, которая должна оставаться внутри этой же формы на стороне клиента.

Значение Form3 на стороне сервера имеет 50% макс. AlphaBlend, это необходимо для просмотра удаленного экрана позади Form3 .


Прежде всего, я хочу сказать, что я получаю удаленный экран на стороне сервера, и положение щелчка мыши работает, как и ожидалось .

Тогда это моя проблема:

enter image description here

Следующий код дает результат, показанный на изображении выше.Я думаю, что этот код правильный, но отсутствует, выровняйте это отверстие с 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;

Form3 .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

Клиентская сторона:

Form2 (форма "шкафчик"):

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.

Form3 (то же самое со стороны сервера):

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 Ответ

0 голосов
/ 22 декабря 2018

На стороне клиента у вас есть полупрозрачная серая форма (Form2), которая имеет размер экрана.Поверх этой формы у вас есть непрозрачная белая форма (Form3), центрированная на экране.В Form3 у вас есть прямоугольное отверстие в Top = Y и Left = X с координатами Form3.

Я понимаю, что ваша проблема в том, что вы хотите нарисовать отверстие в Form2, которое выровнено поОтверстие в форме 3.

Вам необходимо преобразовать систему координат 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 и , затем обработайте область формы 3 *.

  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 Form3.

X1 := X1 - Form3.Left + ResolutionCorrectionX; // and similar for X2, Y1 and Y2

Кстати, просто из любопытства, почему вы используете Round() для расчетов, основанных на целых числах?

...