如何使用 Delphi 的 TSplitter 和面板避免这种不需​​要的行为?

发布于 2024-10-14 18:22:05 字数 3725 浏览 8 评论 0原文

其中包括一个展示我的问题的小项目。我有一个与主窗体对齐的TPageControl。在两个选项卡中的每一个上,我都有客户端对齐的面板。在每个面板上我都有 2 个子面板和一个分离器。左侧面板和分离器向左对齐,右侧面板与客户端对齐。

基本上问题是两个选项卡之间的交互。演示:

  • 运行程序
  • 水平拉伸主窗体。面板 3 会将
  • 分离器尽可能向右移动。面板 2 将增大,面板 3 将缩小至其 10 像素最小宽度限制。
  • 选择选项卡2。面板5按照设计,面板6在主窗体拉伸时变大,
  • 将主窗体宽度减少到其原始宽度。面板 6 收缩太多(不合需要),
  • 单击选项卡 1。主窗体宽度再次增加(不合需要)

好的,该行为可能可以用对齐面板的规则来解释,但是有人可以建议改进操作吗?

unit Unit17;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, ComCtrls;

type
  TForm17 = class(TForm)
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    Panel1: TPanel;
    Panel2: TPanel;
    Splitter1: TSplitter;
    Panel3: TPanel;
    Panel4: TPanel;
    Splitter2: TSplitter;
    Panel5: TPanel;
    Panel6: TPanel;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form17: TForm17;

implementation

{$R *.dfm}

end.


object Form17: TForm17
  Left = 0
  Top = 0
  Caption = 'Form17'
  ClientHeight = 254
  ClientWidth = 314
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object PageControl1: TPageControl
    Left = 0
    Top = 0
    Width = 314
    Height = 254
    ActivePage = TabSheet1
    Align = alClient
    Constraints.MinWidth = 30
    TabOrder = 0
    ExplicitWidth = 480
    object TabSheet1: TTabSheet
      Caption = 'TabSheet1'
      ExplicitWidth = 281
      ExplicitHeight = 165
      object Panel1: TPanel
        Left = 0
        Top = 0
        Width = 306
        Height = 226
        Align = alClient
        Caption = 'Panel1'
        TabOrder = 0
        ExplicitWidth = 109
        ExplicitHeight = 165
        object Splitter1: TSplitter
          Left = 151
          Top = 1
          Width = 12
          Height = 224
          ExplicitLeft = 145
        end
        object Panel2: TPanel
          Left = 1
          Top = 1
          Width = 150
          Height = 224
          Align = alLeft
          Caption = 'Panel2'
          Constraints.MinWidth = 10
          TabOrder = 0
        end
        object Panel3: TPanel
          Left = 163
          Top = 1
          Width = 142
          Height = 224
          Align = alClient
          Caption = 'Panel3'
          Constraints.MinWidth = 10
          TabOrder = 1
          ExplicitLeft = 141
          ExplicitWidth = 330
        end
      end
    end
    object TabSheet2: TTabSheet
      Caption = 'TabSheet2'
      ImageIndex = 1
      ExplicitWidth = 281
      ExplicitHeight = 165
      object Panel4: TPanel
        Left = 0
        Top = 0
        Width = 306
        Height = 226
        Align = alClient
        Caption = 'Panel4'
        TabOrder = 0
        ExplicitWidth = 109
        ExplicitHeight = 165
        object Splitter2: TSplitter
          Left = 149
          Top = 1
          Width = 11
          Height = 224
          ExplicitLeft = 141
        end
        object Panel5: TPanel
          Left = 1
          Top = 1
          Width = 148
          Height = 224
          Align = alLeft
          Caption = 'Panel5'
          Constraints.MinWidth = 10
          TabOrder = 0
        end
        object Panel6: TPanel
          Left = 160
          Top = 1
          Width = 145
          Height = 224
          Align = alClient
          Caption = 'Panel6'
          Constraints.MinWidth = 10
          TabOrder = 1
          ExplicitLeft = 141
          ExplicitWidth = 139
          ExplicitHeight = 163
        end
      end
    end
  end
end 

Included is a small project demonstrating my problem. I have a TPageControl aligned to the main form. On each of two tabsheets I have panels client aligned. On each of those panels I have 2 subpanels and a splitter. The LH panel and splitter is aligned left, the RH panel client-aligned.

Basically the problem is interaction between the 2 tabs. To demonstrate:

  • run the program
  • stretch the main form horizontally. Panel 3 will grow
  • move the splitter as far to the right as it will go. Panel 2 will grow, Panel 3 will shrink to its 10-pixel min-width constraint.
  • select tabsheet 2. Panel 5 is as designed, panel 6 grew when the main form was stretched
  • reduce the main form width to its original width. Panel 6 shrinks too much (undesirable)
  • click on tabsheet 1. Main form increases in width again (undesirable)

OK, the behaviour is probably explainable in terms of the rules of aligned panels, but can anybody suggest improvements to the operation?

unit Unit17;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, ComCtrls;

type
  TForm17 = class(TForm)
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    Panel1: TPanel;
    Panel2: TPanel;
    Splitter1: TSplitter;
    Panel3: TPanel;
    Panel4: TPanel;
    Splitter2: TSplitter;
    Panel5: TPanel;
    Panel6: TPanel;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form17: TForm17;

implementation

{$R *.dfm}

end.


object Form17: TForm17
  Left = 0
  Top = 0
  Caption = 'Form17'
  ClientHeight = 254
  ClientWidth = 314
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object PageControl1: TPageControl
    Left = 0
    Top = 0
    Width = 314
    Height = 254
    ActivePage = TabSheet1
    Align = alClient
    Constraints.MinWidth = 30
    TabOrder = 0
    ExplicitWidth = 480
    object TabSheet1: TTabSheet
      Caption = 'TabSheet1'
      ExplicitWidth = 281
      ExplicitHeight = 165
      object Panel1: TPanel
        Left = 0
        Top = 0
        Width = 306
        Height = 226
        Align = alClient
        Caption = 'Panel1'
        TabOrder = 0
        ExplicitWidth = 109
        ExplicitHeight = 165
        object Splitter1: TSplitter
          Left = 151
          Top = 1
          Width = 12
          Height = 224
          ExplicitLeft = 145
        end
        object Panel2: TPanel
          Left = 1
          Top = 1
          Width = 150
          Height = 224
          Align = alLeft
          Caption = 'Panel2'
          Constraints.MinWidth = 10
          TabOrder = 0
        end
        object Panel3: TPanel
          Left = 163
          Top = 1
          Width = 142
          Height = 224
          Align = alClient
          Caption = 'Panel3'
          Constraints.MinWidth = 10
          TabOrder = 1
          ExplicitLeft = 141
          ExplicitWidth = 330
        end
      end
    end
    object TabSheet2: TTabSheet
      Caption = 'TabSheet2'
      ImageIndex = 1
      ExplicitWidth = 281
      ExplicitHeight = 165
      object Panel4: TPanel
        Left = 0
        Top = 0
        Width = 306
        Height = 226
        Align = alClient
        Caption = 'Panel4'
        TabOrder = 0
        ExplicitWidth = 109
        ExplicitHeight = 165
        object Splitter2: TSplitter
          Left = 149
          Top = 1
          Width = 11
          Height = 224
          ExplicitLeft = 141
        end
        object Panel5: TPanel
          Left = 1
          Top = 1
          Width = 148
          Height = 224
          Align = alLeft
          Caption = 'Panel5'
          Constraints.MinWidth = 10
          TabOrder = 0
        end
        object Panel6: TPanel
          Left = 160
          Top = 1
          Width = 145
          Height = 224
          Align = alClient
          Caption = 'Panel6'
          Constraints.MinWidth = 10
          TabOrder = 1
          ExplicitLeft = 141
          ExplicitWidth = 139
          ExplicitHeight = 163
        end
      end
    end
  end
end 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

孤单情人 2024-10-21 18:22:05

为了获得预期的行为,请从面板中删除约束 (MinWidth)。无论如何,这些设置目前无效,因为您的拆分器具有MinSize 为 '30'(默认值,不存储)。

编辑(对评论的回应):您不能指望位于拆分器右侧的控件的“MinWidth”约束来调整左侧控件的大小。这是合乎逻辑的,约束是您设置的控件的属性。您将实现的只是,如果您的控件已经处于其“MinWidth”,则表单将拒绝缩小,因此您会观察到切换选项卡时表单变大的不良行为。正如 Marjan 在他的回答中所说,你想要什么,就必须与代码有关。应该有不止一种方法可以实现这一点,例如,将以下内容添加到 Panel3 的“OnCanResize”事件中:

procedure TForm1.Panel3CanResize(Sender: TObject; var NewWidth,
  NewHeight: Integer; var Resize: Boolean);
begin
  if NewWidth < Splitter1.MinSize then
    Panel2.Width := Panel2.Width - Splitter1.MinSize + NewWidth;
end;

To get expected behavior remove the constraints (MinWidth) from your panels. These settings are currently ineffective anyway, since your splitters have a MinSize of '30' (the default, not stored).

edit (response to the comment): You cannot expect the 'MinWidth' constraint of a control that's at the right side of a splitter to adjust the size of the left-side control. That's only logical, the constraint is a property for the control that you set. All you'll achieve is that the form will deny shrinking if your control is already at its 'MinWidth', hence the undesirable behavior that you observe that the form is getting larger when you switch tabs. What you desire, you have to do with code - as Marjan told in his answer. There should be more than one way to achieve this, for instance, put the below to the Panel3's 'OnCanResize' event:

procedure TForm1.Panel3CanResize(Sender: TObject; var NewWidth,
  NewHeight: Integer; var Resize: Boolean);
begin
  if NewWidth < Splitter1.MinSize then
    Panel2.Width := Panel2.Width - Splitter1.MinSize + NewWidth;
end;
少女七分熟 2024-10-21 18:22:05

不一定是真正的答案,但有几点说明:

  • MinSize 是一个左对齐的拆分器,与拆分器左侧和右侧的控件有关。您的面板 6 确实被调整为(略大于)其自己的 minWidth (10),而不是分割器的 MinSize (30)。您可以更轻松地演示这一点,方法是在每个面板 2、3、5 和 6 上添加两个左对齐面板,并为其指定宽度 10 和 20 以及不同的颜色。

  • 在减小主窗体的宽度后再次选择一个选项卡,主窗体会增大(哎呀),并且显示现在 Panel3 也已减小到其最小宽度,而不是拆分器的 minSize。

主窗体大小调整的解决方案?不知道,但确保面板的最小宽度与分离器的最小尺寸同步应该可以消除收缩。正如 Sertac 所说,我怀疑您只需要选择其中之一,而不是两者都选择...

更新:

  • 将分离器的 minSize 设置为 30,并将面板的 minWidth 设置为 0。调整大小,但确实将右侧面板减少到 0 宽度。

  • 将拆分器的 minSize 设置为 30 并将面板的 minWidth 设置为 30,可以解决最小宽度问题,但仍会调整主窗体的大小。

  • 将面板的 minWidth 设置为 30,并将拆分器的 minSize 设置为 1(最小值),这样您就可以将拆分器一直向右移动,并在释放拆分器时根据面板的 minWidth 调整主窗体的大小。它确实可以防止 Panel6 减少到小于 30,但是当您重新选择选项卡 1 时,主窗体会再次调整大小。

看来您最好的选择是依靠拆分器的 minSize 并“手动”防止右侧面板减少到太远当分离器到达最右侧时限制分离器的移动。您可以在拆分器的 OnCanResize 事件中执行此操作。

顺便说一句,使用 D2009

Not necessarily a real answer, but a couple of remarks:

  • MinSize voor an alLeft aligned Splitter pertains to the control on the Splitter's left and right. Your Panel 6 is indeed resized to (slightly more than) its own minWidth (10) instead of the splitter's MinSize (30). You can more easily demonstrate this by adding two left aligned panels on each of your panels 2, 3, 5 and 6 and give them a width of 10 and 20 and a different color.

  • Selecting tabsheet one again after reducing the mainform's width, does grow the mainform (yikes) AND shows that now Panel3 has now also been reduced to its min width instead of the splitter's minSize.

The solution to the main form resizing? Dunno, but making sure your panels' minwidth is in sync with the splitters' minsize should remove the shrinking. And as Sertac says, I suspect that you simply need to opt for one or the other, but not both...

Update:

  • Setting the splitters' minSize to 30 and setting the panels' minWidth to 0. Takes away the mainform's resize, but does reduce the right hand panels to 0 width.

  • Setting the splitters' minSize to 30 and setting the panels' minWidth to 30, takes away the minimum width problems, but still resized the main form.

  • Setting the panels' minWidth to 30 and setting the splitters' minSize to 1 (the minimum) allows you to move the splitter all the way to the right and resizes the main form by the panels minWidth when you release the splitter. It does keep Panel6 from reducing to less than 30, but again the mainform resizes when you reselect tab 1.

It would seem that your best bet is to rely on the splitters' minSize and "manually" prevent the right hand panels from reducing to far by restricting the splitters' movement when it gets to far right. You can do this in the OnCanResize event of the splitters.

btw, using D2009

负佳期 2024-10-21 18:22:05
void __fastcall TFMain::SplitterCanResize(TObject *Sender, int &NewSize, bool &Accept)
{
    TSplitter *S = (TSplitter*) Sender;
    for (int i = 0; Accept && i < S->Parent->ControlCount; i++)
        if (S->Parent->Controls[i]->Constraints->MaxHeight && S->Parent->Controls[i]->Align == S->Align && NewSize >= S->Parent->Controls[i]->Constraints->MaxHeight *2)
            Accept = false;
}
void __fastcall TFMain::SplitterCanResize(TObject *Sender, int &NewSize, bool &Accept)
{
    TSplitter *S = (TSplitter*) Sender;
    for (int i = 0; Accept && i < S->Parent->ControlCount; i++)
        if (S->Parent->Controls[i]->Constraints->MaxHeight && S->Parent->Controls[i]->Align == S->Align && NewSize >= S->Parent->Controls[i]->Constraints->MaxHeight *2)
            Accept = false;
}
淡淡绿茶香 2024-10-21 18:22:05

如果当表单较宽时,您将拆分器移至右侧较远的位置,然后减小表单的宽度,使其变得比左侧面板更窄(因此拆分器发现自己位于表单“外部”),那么表单的行为应该如何在这种情况下?有人问您关于理想行为的标准,到目前为止我在您的回答中只能看到您对不理想行为的理解。

现在,我曾多次担心调整带有面板和分隔符的表单大小可能产生的副作用。我没有对此进行太多调查,所以特别是我之前从未了解过像您的情况那样的自动调整大小效果。无论如何,为了防止大多数(如果不是任何)可能的行为假象,我考虑使用 TScrollBox 作为面板和拆分器的父控件,而不是 TPanel

我相信,这会将表单大小的调整更改为滚动框客户区域大小的调整,如果我像您一样使用选项卡,那么在我使用拆分器的几个小项目中,这对我来说效果很好。但我无法了解你的情况。我知道这更多的是一种解决方法,而不是解决您的问题。

If while the form was wider you moved the splitter far to the right then reduced the form's width so it became narrower than the left-hand panel (and thus the splitter found itself 'outside' the form), what should the behaviour of your form be in this case? You have been asked about your criteria for desirable behaviour and all I can see in your answer so far is your understanding of undesirable behaviour.

Now I have been concerned a couple of times with possible side effects of resizing a form that has panels and splitters on it. I didn't investigate very much into it and so in particular I never knew before about the auto-resize effect like in your situations. Anyway, in order to prevent most (if not any) of the possible behavioral artefacts I considered using TScrollBox as a parent control to panels and splitters instead of TPanel.

I believe, this would change resizing of the form into resizing of the scroll box's client area, which would work fine for me in however few little projects of mine where I used splitters, if I employed tabsheets like you do. However I cannot know about your case. And I understand that this is more of a workaround than a solution to your problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文