为啥我在 IDE 中有另一个尺寸的组件?

Posted

技术标签:

【中文标题】为啥我在 IDE 中有另一个尺寸的组件?【英文标题】:Why I got another size of a component in IDE?为什么我在 IDE 中有另一个尺寸的组件? 【发布时间】:2012-02-18 18:01:42 【问题描述】:

使用 Delphi 6 Prof.

我为分离创建了一个斜角组件。

因为我使用了 8 像素(宽 x 高)的垫片,所以我认为我创建了这个组件,当我把它放在一个 Form 上时,我只需要设置 Align - 就是这样。

type
  TSSpacer = class(TBevel)
  public
    constructor Create(aOwner: TComponent); override;
  published
    //property Width default 8;
    //property Height default 8;
    property Shape default bsSpacer;
end;

constructor TSSpacer.Create(aOwner : TComponent);
begin
  inherited Create(aOwner);
  Shape := bsSpacer;
  Width := 8;
  Height := 8;
end;

但是当我使用这段代码(有或没有“默认值”)时,IDE 中的结果是 140 x 41 像素。

那么为什么它的尺寸不是 8 x 8?还有一点很有趣:默认的 TBevel 是 50 x 50。

是什么导致了这种大小调整?

【问题讨论】:

恕我直言,这是一种设计时限制(可能与网格尺寸有关,不知道)。如果你设置例如10x10 它是在设计时正确创建的。我会 hack 它 通过将值改回来但不知道如何例如在SetBounds 中确定组件处于设计时并且它的创建已经完成(Loaded 过程仅用于运行时)。我尝试了快速(没有时间:) 调试,似乎属性填充器中的某些内容修改了这些值。无论如何 +1,有趣的问题! 如果设置为 10x10,它可以工作,但如果设置为 8x8,它会失败?为什么会有不同,@Tlama? @Rob,确切地说;在 D2007 和 D2009 中验证。我会怀疑设计时维度的一些内部限制。 1x10 有效,1x9 无效; 10x1 有效,9x1 无效。似乎两个尺寸都有一个小于 10 的限制,这真的很奇怪(这与网格大小无关,我设置了 8x8)。在运行时,您可以做任何您想做的事情,但是在设计时构造函数之后,有些东西会修改尺寸。很容易覆盖例如SetBounds 但我如何确定组件已完全创建(构造函数完成后 SetBounds 触发几次)。 至少在 D2007 中,用于设置组件初始大小的边界框被扩展为至少 10x10,以防止组件在设计器中无法命中。创建组件后,边界框将应用于组件。这允许用户通过拖动来指定组件的初始大小。 【参考方案1】:

TLama 在他的 cmets 中一针见血:设计师以某种方式防止组件变得太小。奇怪的是,设计师没有设置这个最小尺寸(10 x 10),而是似乎将尺寸随机设置为任意值:如 OP 所述,D6 中为 140 x 41,D7 中为 100 x 41。

好吧,由于 TBevel 确实使用或发布了 AutoSize 属性,并且该属性名称与希望的行为有关,所以我选择扩展它的使用:

type
  TSSPacer = class(TBevel)
  protected
    procedure SetParent(AParent: TWinControl); override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  published
    property Shape default bsSpacer;
  end;

constructor TSSPacer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Shape := bsSpacer;
end;

procedure TSSPacer.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
  if AutoSize then
    inherited SetBounds(ALeft, ATop, 8, 8)
  else
    inherited SetBounds(ALeft, ATop, AWidth, AHeight);
end;

procedure TSSPacer.SetParent(AParent: TWinControl);
begin
  AutoSize := (csDesigning in ComponentState) and (Parent = nil) and
    (AParent <> nil);
  inherited SetParent(AParent);
end;

这在 D7 中有效,但更可靠的实现可能是:

  private
    FFixDesignSize: Boolean;

procedure TSSPacer.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
  if FFixDesignSize then
  begin
    inherited SetBounds(ALeft, ATop, 8, 8);
    FFixDesignSize := False;
  end
  else
    inherited SetBounds(ALeft, ATop, AWidth, AHeight);
end;

procedure TSSPacer.SetParent(AParent: TWinControl);
begin
  FFixDesignSize := (csDesigning in ComponentState) and (Parent = nil) and
    (AParent <> nil);
  inherited SetParent(AParent);
end;

并通过将这个控件放入表单的设计器中的调用堆栈来完成这个答案:

- Before SetBounds
- After SetBounds
- Before SetBounds
- After SetBounds
- Before SetParent
    - Before SetBounds
    - After SetBounds
- After SetParent
- Before SetBounds
- After SetBounds
- Before SetParent
- After SetParent

但我认为您不应依赖此特定的调用顺序或调用次数:我怀疑 Delphi 版本之间可能会有所不同。

【讨论】:

顺便说一句,SetParent 不能保证只被调用一次。每当更改父级时都会调用它。 @TLama 我明白了。我是在回复您的“仅一次”评论,而不是针对所提供的代码。【参考方案2】:

找到一篇应该解释它的文章。我认为你需要覆盖 TControl 的 SetBounds。

在此处阅读更多信息http://www.delphidabbler.com/tips/77

【讨论】:

你能解释一下吗?文章开头是“如果……您需要捕捉或限制对左、上、宽度或高度的更改。”为什么我们需要做这些事情来设置控件的 initial 大小? @John,SetBounds 在构造函数完成其工作后被触发了几次,所以似乎有一些机制阻止您创建两个尺寸都小于 10x10 的组件,您必须让组件来调整大小,所以 SetBounds 中的简单测试 if csDesigning in ComponentState then SetMyDefaults 是不够的。它会解决问题,但会创建另一个问题,您将无法在设计时调整组件的大小。 这不是答案,除非您将其扩展为在此处包含内容。如果大部分内容都在外部链接中,那么如果外部站点关闭或消失,它就变得毫无意义。请编辑更具体;您可以随时链接到外部网站作为“更多信息”摘要。

以上是关于为啥我在 IDE 中有另一个尺寸的组件?的主要内容,如果未能解决你的问题,请参考以下文章

WPF:将组件的高度绑定到另一个组件的高度

为啥不更新我在子组件中传递的父组件中的值并更新使用自定义事件 $emit Vue 3?

为啥获取 scrollIntoView 不是函数

flex 覆盖公共函数集数据

当组件中有解构赋值时,为啥默认道具不能防止 TypeError?

ionic 2 sidemenu - 将导航从 app.ts 传递到菜单组件