TRect 是 Delphi 中一个非常基础且重要的结构,用于表示一个矩形区域,无论是在 VCL 框架(用于 Windows 桌面应用)还是 FMX 框架(用于跨平台应用)中,它都无处不在。

TRect 是什么?
TRect 是一个记录类型,在 System.Types 单元中定义,它由四个整型(或其子类型,如 Single, Double)属性组成,用于定义一个矩形在二维空间中的位置和大小。
核心属性
Left: 矩形左边缘的 X 坐标。Top: 矩形上边缘的 Y 坐标。Right: 矩形右边缘的 X 坐标。Bottom: 矩形下边缘的 Y 坐标。
重要概念:TRect 的坐标是左闭右开的,这意味着矩形包含 (Left, Top) 点,但不包含 (Right, Bottom) 点。
- 宽度:
Width = Right - Left - 高度:
Height = Bottom - Top
常用方法
TRect 还提供了一些非常实用的方法:
Contains(Point: TPoint): Boolean: 判断一个点是否在矩形内部。InflateBy(DeltaX, DeltaY: Integer): 向外或向内扩展矩形。DeltaX/DeltaY为正则扩大,为负则缩小。Intersect(Rect: TRect): 将当前矩形修改为与另一个矩形的交集。Union(Rect: TRect): 将当前矩形修改为与另一个矩形的并集。IsEmpty: Boolean: 判断矩形是否为空(Left >= Right或Top >= Bottom)。
如何传递 TRect 作为参数?
当函数或过程需要接收一个矩形区域时,你可以将 TRect 作为参数传递,主要有两种方式:值传递 和 引用传递。

值传递
这是最常见、最安全的方式,当你传递一个 TRect 时,函数内部会创建该矩形的一个副本,函数内部对这个副本的任何修改(例如调用 InflateBy)都不会影响到原始的矩形变量。
语法:
procedure MyProcedure(const ARect: TRect);
强烈建议使用
const关键字,这有以下好处:
- 高效:
TRect的大小很小(4个整数),传递副本的开销极小。- 安全:防止函数意外修改调用者传入的原始数据。
- 可读性:明确表示该参数是输入参数,函数不会修改它。
示例:

uses
System.Types, System.SysUtils;
// 这个函数只读取矩形信息,不修改它
function GetRectArea(const ARect: TRect): Integer;
begin
// 如果矩形为空,面积为0
if ARect.IsEmpty then
Result := 0
else
Result := ARect.Width * ARect.Height;
end;
var
MyRect: TRect;
begin
MyRect := TRect.Create(10, 10, 100, 100);
ShowMessage(Format('原始矩形: (%d, %d, %d, %d)', [MyRect.Left, MyRect.Top, MyRect.Right, MyRect.Bottom]));
var Area := GetRectArea(MyRect);
ShowMessage(Format('矩形面积: %d', [Area]));
// MyRect 的值没有被改变
ShowMessage(Format('调用函数后矩形: (%d, %d, %d, %d)', [MyRect.Left, MyRect.Top, MyRect.Right, MyRect.Bottom]));
end.
引用传递
当你需要在函数内部修改原始矩形,并将这些修改“带回来”给调用者时,就应该使用引用传递。
语法:
procedure MyProcedure(var ARect: TRect);
使用 var 关键字,传递的是变量的内存地址,函数内部对 ARect 的所有操作都会直接作用于原始变量。
示例:
uses
System.Types, System.SysUtils;
// 这个函数会修改传入的矩形
procedure ExpandRect(var ARect: TRect; DeltaX, DeltaY: Integer);
begin
// 直接修改原始矩形
ARect.InflateBy(DeltaX, DeltaY);
end;
var
MyRect: TRect;
begin
MyRect := TRect.Create(10, 10, 100, 100);
ShowMessage(Format('原始矩形: (%d, %d, %d, %d)', [MyRect.Left, MyRect.Top, MyRect.Right, MyRect.Bottom]));
// 调用函数,传入 var 参数
ExpandRect(MyRect, 10, 5);
// MyRect 的值已经被改变
ShowMessage(Format('调用函数后矩形: (%d, %d, %d, %d)', [MyRect.Left, MyRect.Top, MyRect.Right, MyRect.Bottom]));
end.
输出:
原始矩形: (10, 10, 100, 100)
调用函数后矩形: (0, 5, 110, 105)
注意:
InflateBy(10, 5)会将Left减 10,Top减 5,Right加 10,Bottom加 5。
TRect 在实际开发中的应用场景
TRect 几乎无处不在,尤其是在处理 UI 相关的逻辑时。
场景1:控件和窗体的位置与大小
TControl.BoundsRect: 获取或设置控件在父坐标系中的矩形区域。TControl.ClientRect: 获取控件客户区的矩形区域(不包括边框、标题栏等)。TForm.ClientRect: 获取窗体客户区的矩形区域。
示例:判断鼠标点击是否在按钮上
procedure TForm1.Button1Click(Sender: TObject);
var
MousePos: TPoint;
begin
// 获取鼠标在窗体客户区内的坐标
MousePos := ScreenToClient(Mouse.CursorPos);
// 判断点击是否在按钮1的客户区内
if Button1.ClientRect.Contains(MousePos) then
begin
ShowMessage('点击了按钮1的客户区内部!');
end;
end;
场景2:绘图操作
在 TCanvas 上绘制图形时,TRect 是定义绘制区域的基本参数。
示例:在窗体上画一个矩形
procedure TForm1.FormPaint(Sender: TObject); var R: TRect; begin R := ClientRect; // 使用整个客户区作为绘制区域 Canvas.Brush.Color := clBlue; Canvas.FrameRect(R); // 画一个空心矩形 end;
场景3:屏幕和显示器的操作
Screen.Monitors: 一个数组,包含了系统中所有显示器的信息,每个TMonitor对象都有一个WorkareaRect属性,表示该显示器的工作区(通常不包括任务栏)。
示例:将窗体移动到主显示器的工作区中心
procedure CenterFormOnMainScreen(Form: TForm); var MainWorkArea: TRect; begin // 获取主显示器的工作区 MainWorkArea := Screen.PrimaryMonitor.WorkareaRect; // 计算窗体左上角的目标坐标 Form.Left := MainWorkArea.Left + (MainWorkArea.Width - Form.Width) div 2; Form.Top := MainWorkArea.Top + (MainWorkArea.Height - Form.Height) div 2; end; // 调用示例 procedure TForm1.Button2Click(Sender: TObject); begin CenterFormOnMainScreen(Self); end;
场景4:GDI+ 和第三方库
许多高级绘图库(如 GDI+、OpenGL 等)在 Delphi 中的封装也广泛使用 TRect 或类似的结构来定义裁剪区域、绘制目标等。
总结与最佳实践
- 优先使用
const:对于绝大多数只需要读取矩形信息的函数,使用const ARect: TRect是最佳实践,它既安全又高效。 - 明确使用
var:当函数的目的是修改原始矩形时,才使用var ARect: TRect,这清晰地表达了函数的“副作用”。 - 理解坐标系统:始终记住
TRect的Right和Bottom是开区间,这在处理像素、裁剪区域时尤其重要。 - 利用
IsEmpty:在计算面积、交集或并集之前,先用IsEmpty判断矩形是否有效,可以避免很多潜在的错误。 - 熟悉常用方法:
InflateBy,Contains,Intersect,Union等方法非常实用,能极大简化你的代码。
希望这份详细的解释能帮助你更好地理解和使用 Delphi 中的 TRect 参数!
