Вот тестап, демонстрирующий выравнивание Server.Form3
с Client.Form3
на изображении со стороны «клиента».
Первый Form2
.Это основная форма в этом testapp.У него есть прокрутка и изображение (изображение «клиентской» стороны), представленное здесь кирпичной стеной 1000 x 400.Изображение имеет зеленый прямоугольник, центрированный по вертикали и горизонтали, имитируя Form3
, видимый на стороне клиента.
type
TScrollBox = class(Vcl.forms.TScrollBox) // we need to handle scroll events
protected
procedure WMHScroll(var Msg: TMessage); message WM_HSCROLL;
procedure WMVScroll(var Msg: TMessage); message WM_VSCROLL;
end;
TForm2 = class(TForm)
ScrollBox1: TScrollBox;
Image1: TImage;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ScrollBox1Resize(Sender: TObject);
private
{ Private declarations }
protected // we also need to react to form moves
procedure WMWindowPosChanged(var Msg: TWMWindowPosChanged); message WM_WINDOWPOSCHANGED;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
// a helper function
function fnMyRgn(HostControl: TWinControl; Form: TForm): HRGN;
begin
result := CreateRectRgn(
(HostControl.ClientOrigin.X - Form.Left),
(HostControl.ClientOrigin.Y - Form.Top),
(HostControl.ClientOrigin.X - Form.Left + HostControl.ClientWidth),
(HostControl.ClientOrigin.Y - Form.Top + HostControl.ClientHeight));
end;
// Note how Form3 is centered to the scrollbox content (the image) by using scrollbar ranges
procedure TForm2.Button1Click(Sender: TObject);
var
rgn: HRGN;
begin
Form3 := TForm3.Create(self);
Form3.Left := ScrollBox1.ClientOrigin.X - ScrollBox1.HorzScrollBar.Position +
(ScrollBox1.HorzScrollBar.Range - Form3.Width) div 2;
Form3.Top := ScrollBox1.ClientOrigin.Y - ScrollBox1.VertScrollBar.Position +
(ScrollBox1.VertScrollBar.Range - Form3.Height) div 2;
rgn := fnMyRgn(ScrollBox1, Form3);
if 0 = SetWindowRgn(Form3.Handle, rgn, True) then
DeleteObject(rgn);
Form3.Visible := True;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
Form3.Close;
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
Form3.AlphaBlend := False;
Form3.TransparentColor := True;
end;
// Scrollbox is anchored to all sides of the form,
// ergo, size changes if form size changes
procedure TForm2.ScrollBox1Resize(Sender: TObject);
var
ScrBox: TScrollBox;
rgn: hRgn;
begin
if Form3 = nil then exit;
ScrBox := Sender as TScrollBox;
Form3.Left := ScrBox.ClientOrigin.X - ScrBox.HorzScrollBar.Position +
(ScrBox.HorzScrollBar.Range - Form3.Width) div 2;
Form3.Top := ScrBox.ClientOrigin.Y - ScrBox.VertScrollBar.Position +
(ScrBox.VertScrollBar.Range - Form3.Height) div 2;
rgn := fnMyRgn(ScrBox, Form3);
if 0 = SetWindowRgn(Form3.Handle, rgn, True)then
DeleteObject(rgn);
end;
// Form3 must be moved if Form2 is moved
procedure TForm2.WMWindowPosChanged(var Msg: TWMWindowPosChanged);
begin
inherited;
if Form3 = nil then exit;
Form3.Left := ScrollBox1.ClientOrigin.X - ScrollBox1.HorzScrollBar.Position +
(ScrollBox1.HorzScrollBar.Range - Form3.Width) div 2;
Form3.Top := ScrollBox1.ClientOrigin.Y - ScrollBox1.VertScrollBar.Position +
(ScrollBox1.VertScrollBar.Range - Form3.Height) div 2;
end;
{ TScrollBox }
procedure TScrollBox.WMHScroll(var Msg: TMessage);
var
rgn: hRgn;
begin
inherited;
if Form3 = nil then exit;
Form3.Left := self.ClientOrigin.X - HorzScrollBar.Position +
(HorzScrollBar.Range - Form3.Width) div 2;
rgn := fnMyRgn(self, Form3);
if 0 = SetWindowRgn(Form3.Handle, rgn, True) then
DeleteObject(rgn);
end;
procedure TScrollBox.WMVScroll(var Msg: TMessage);
var
rgn: hRgn;
begin
inherited;
if Form3 = nil then exit;
Form3.Top := self.ClientOrigin.Y - VertScrollBar.Position +
(VertScrollBar.Range - Form3.Height) div 2;
rgn := fnMyRgn(self, Form3);
if 0 = SetWindowRgn(Form3.Handle, rgn, True) then
DeleteObject(rgn);
end;
end.
Тогда у нас есть Form3
, который здесь представляет собой форму без полей шириной 400 x 300 высотойс парой кнопок и красным нарисованным контуром.Он может быть в форме буквы или полностью прозрачным.Устанавливается в алфавитном порядке со значением наложения 127. При нажатии Form2.Button3
он переключается на прозрачный.Желтый цвет заливки: TransparentColoValue
type
TForm3 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure FormPaint(Sender: TObject);
private
public
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
uses Unit2;
procedure TForm3.FormPaint(Sender: TObject);
begin
Canvas.Pen.Color := clRed;
Canvas.Pen.Style := psSolid;
Canvas.Pen.Width := 3;
Canvas.Rectangle(1, 1, clientwidth-1, clientheight-1);
end;
Первый снимок экрана показывает Form2
только
![enter image description here](https://i.stack.imgur.com/SicXy.png)
Второе изображение показывает Form2
с Form3
как в алфавитном порядке, слегка прокрученный
![enter image description here](https://i.stack.imgur.com/5M8IR.png)
И третье изображение показывает Form2
с Form3
как прозрачный, далее прокручивается
![enter image description here](https://i.stack.imgur.com/eh3ap.png)
Теперь, когда Client.Form3
центрируется на экране клиента, а Server.Form3
центрируется на изображении экрана клиента, любые дыры вырисовать с теми же координатами, должны совпадать.
Обратите внимание, что я использовал TImage
в поле прокрутки в соответствии с вашим первым вопросом, потому что я не совсем понимаю, почему вы должны перейти на ящик для рисования.Однако, если вы предпочитаете это, не будет проблематично использовать ящик для краски вместо TImage
.
По запросу добавлено используемое фоновое изображение
![enter image description here](https://i.stack.imgur.com/0trEr.png)