You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows10下Delphi11 VCL如何实现相邻GroupBox边框拖拽调整大小?

相邻GroupBox拖动调整实现(Delphi 11 VCL)

直接用GroupBox实现的方案

要实现鼠标悬停边框显示拆分指针、拖动调整两个GroupBox宽度的效果,需手动处理鼠标事件,步骤如下:

1. 声明变量

在窗体类的private段添加变量,记录拖动状态与初始参数:

private
  FIsDragging: Boolean;       // 是否处于拖动状态
  FStartX: Integer;           // 拖动起始鼠标X坐标
  FGB1Width, FGB2Width: Integer; // 两个GroupBox的初始宽度

2. 定义常量

根据需求设置边框检测范围和控件最小宽度:

const
  EDGE_DETECT_RANGE = 2; // 边框检测范围(像素)
  MIN_CONTROL_WIDTH = 50; // 控件最小宽度,防止拖动至消失

3. 实现鼠标事件代码

鼠标移动事件(处理悬停指针与拖动调整)

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
  EdgeX: Integer;
  CommonTop, CommonBottom: Integer;
  DeltaX: Integer;
  NewGB1Width, NewGB2Width: Integer;
begin
  if FIsDragging then
  begin
    // 计算拖动偏移量
    DeltaX := X - FStartX;
    NewGB1Width := FGB1Width + DeltaX;
    NewGB2Width := FGB2Width - DeltaX;

    // 限制最小宽度
    if NewGB1Width < MIN_CONTROL_WIDTH then
    begin
      DeltaX := MIN_CONTROL_WIDTH - FGB1Width;
      NewGB1Width := MIN_CONTROL_WIDTH;
      NewGB2Width := FGB2Width - DeltaX;
    end
    else if NewGB2Width < MIN_CONTROL_WIDTH then
    begin
      DeltaX := FGB2Width - MIN_CONTROL_WIDTH;
      NewGB1Width := FGB1Width + DeltaX;
      NewGB2Width := MIN_CONTROL_WIDTH;
    end;

    // 更新控件尺寸
    GroupBox1.Width := NewGB1Width;
    GroupBox2.Left := GroupBox1.Left + GroupBox1.Width;
    GroupBox2.Width := NewGB2Width;
    FStartX := X; // 更新起始坐标,避免累积误差
  end
  else
  begin
    // 判断鼠标是否在两个GroupBox的相邻边框区域
    EdgeX := GroupBox1.Left + GroupBox1.Width;
    // 计算两个GroupBox的共同垂直区间
    CommonTop := Max(GroupBox1.Top, GroupBox2.Top);
    CommonBottom := Min(GroupBox1.Top + GroupBox1.Height, GroupBox2.Top + GroupBox2.Height);

    if (Abs(X - EdgeX) <= EDGE_DETECT_RANGE) and (Y >= CommonTop) and (Y <= CommonBottom) then
      Cursor := crHSplit
    else
      Cursor := crDefault;
  end;
end;

鼠标按下事件(触发拖动状态)

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  EdgeX: Integer;
  CommonTop, CommonBottom: Integer;
begin
  if Button <> mbLeft then Exit;

  EdgeX := GroupBox1.Left + GroupBox1.Width;
  CommonTop := Max(GroupBox1.Top, GroupBox2.Top);
  CommonBottom := Min(GroupBox1.Top + GroupBox1.Height, GroupBox2.Top + GroupBox2.Height);

  if (Abs(X - EdgeX) <= EDGE_DETECT_RANGE) and (Y >= CommonTop) and (Y <= CommonBottom) then
  begin
    FIsDragging := True;
    FStartX := X;
    FGB1Width := GroupBox1.Width;
    FGB2Width := GroupBox2.Width;
    Screen.Cursor := crHSplit;
  end;
end;

鼠标释放事件(结束拖动状态)

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if FIsDragging then
  begin
    FIsDragging := False;
    Screen.Cursor := crDefault;
  end;
end;

更简便的替代控件方案

若不想手动编写事件逻辑,VCL自带的TSplitter是最优选择,配合以下控件使用:

  • TSplitter + GroupBox/TPanel:

    1. 将第一个GroupBox(或TPanel)的Align属性设为alLeft;
    2. 添加TSplitter控件,设置其Align为alLeft,放在第一个控件右侧;
    3. 将第二个GroupBox(或TPanel)的Align属性设为alClient;
      TSplitter会自动处理鼠标悬停显示拆分指针、拖动调整相邻控件宽度的所有逻辑,无需额外代码。
  • TControlBar:
    适合多控件的布局管理,可容纳多个可调整大小的面板,但对于两个相邻控件的场景,TSplitter方案更简洁。

内容的提问来源于stack exchange,提问作者Bart Kindt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 09:12:50