在我当前的项目中,我有一个带有工具栏和面板(TTbxDock)的TTbxDockablePanel。移动TBX-> SpTBX之后,我无法在TSpTbxDockablePanel上放置面板(TSpTbxDock)。我看到一个运行时错误消息,提示我无法将面板放置在扩展坞上。




我是否需要为面板使用TSpTbxMultiDock?为什么?
我可以将工具栏放在TSpTbxMultiDock而不是TSpTBXDock上吗?


即为什么编写这样的代码:

procedure TSpTBXCustomMultiDock.ValidateInsert(AComponent: TComponent);
begin
  inherited;
  if not (AComponent is TSpTBXCustomDockablePanel) then
    raise EInvalidOperation.CreateFmt('Cannot insert %s into MultiDock', [AComponent.ClassName]);
end;

procedure TSpTBXCustomDockablePanel.ValidateContainer(AComponent: TComponent);
begin
  inherited;
  if (AComponent is TTBDock) and not (AComponent is TSpTBXCustomMultiDock) then
    raise EInvalidOperation.CreateFmt('Cannot insert %s into %s. Place it on a MultiDock instead', [Self.ClassName, AComponent.ClassName]);
end;


为什么我不能只使用一种基座?

最佳答案

“我需要使用TSpTbxMultiDock代替面板?为什么?”

简短的答案是,因为TSpTBXMultiDock组件仅用于处理和停靠TSpTBXDockablePanel

长答案是将TSpTBXMultiDock组件编写为仅处理和停靠TSpTBXDockablePanel,因为停靠代码依赖于停靠控件中的特定方法/属性。请参见TSpTBXCustomDockablePanel.SetParent,它会照看此内容:它访问属性和方法TSpTBXCustomMultiDock.


UpdateDockablePanelsDockPos
ClientAreaWidth
ClientAreaHeight


换句话说,停靠和布局代码需要知道某些信息,并要求停靠的控件执行某些操作。最简单的方法是限制它可以停靠在特定类的后代上的控件的类型,该类声明并实现所需的接口(松散地使用接口,没有声明(类)interface,这只是非正式的方法/属性集。)

从快速扫描代码开始,我认为只有第一个UpdateDockablePanelsDockPos才是真正必要的。我可能错过了一些东西。但是此方法会获取所有停靠面板的列表,并更新每个面板的DockPos,这是停靠面板在面板中的一维位置。也就是说,对于水平面板,它是左/水平起点,对于垂直面板,它是上/垂直起点。它还会更新总数,以便面板知道必须有多大,或者可以选择多大。

我不太确定我已经回答了你的问题。我觉得我给出了正确的答案,但没有提供有用的答案(以上是技术原因,而非概念性原因),这需要深入了解您的工作。我的猜测是您在问这个问题,因为您正在为TBX-> SpTBX迁移而苦苦挣扎,并且希望有可以同时处理工具栏和可停靠面板的停靠区域。幸运的是,这些都引出了您的第二个问题...

“我可以将工具栏放在TSpTbxMultiDock上吗?”

我要进入记忆中的领域,并且不能保证答案的这一部分是正确的,因为很久很久以前我就将应用程序从TBX转换为SpTBX。

首先,不可以,您不能在可停靠面板上放置TSpTBXToolbar。您也不能将TSpTBXDockablePanel停靠在TSpTBXDock上。工具栏可以停靠在停靠栏中,可停靠面板可以停靠在多停靠栏中。

这样做的原因是猜测,但我想这是由于两个停靠控件的行为不同以及它们的目的不同。

工具栏:


旨在包含SpTBX项(按钮,下拉菜单等,而不是任何普通的VCL控件,按钮等),并且可以动态地从工具栏更改为菜单等,例如,在调整窗体大小和缩小工具栏时。
堆栈:工具栏之间也可以留有一定的空间(不同于停靠的面板,后者总是彼此相邻)。他们坐在用户放置它们的任何地方。它们通常也坐成几排,一个码头扩展并包含几排。
设计用于缩小:表单可能会变得太小,或者用户可以将工具栏拖到另一个表单上,并且工具栏将仅显示它可以显示的项目,然后隐藏其他项目或显示人字形(一个小>>按钮可打开一个包含其他项目的菜单。)


可停靠面板:


用于容纳复杂的控件,包括标准的VCL控件-它们作为工具栏和对接系统兼容的方式来构建复杂的对接表单。 (我们将其设计为框架,然后将框架与可固定面板对齐。)
很少在几行上。作为UI实现者,这取决于您,但是彼此相邻停靠的许多面板可能会迅速填满表单空间。对于可停靠的面板,我们保持LimitToOneRow处于打开状态,因此它们只能填充一个维度(即,在表单的左侧和右侧,可停靠的面板只能位于彼此之间的上方和下方,而不能位于彼此的左侧和右侧)其他。)
调整大小的行为是不同的:它们总是相邻的,并且两者之间没有间隙(工具栏可以放置在任何地方),并且通常拉伸面板的一个或多个来填充基座的整个大小(除非设置了MenuBar,否则工具栏就不会这样) (请参见下文)),实际上,工具栏的目的是缩小而不是增长,并显示人字形和下拉菜单。面板没有这种行为。


转移之后,回到您的问题。当我们转换应用程序时,我记得我想知道如果用户想要创建一个布局,使得有多个工具栏,一个可停靠的面板,然后再是一个工具栏,以便尽可能接近混合两种类型,会发生什么。这样做将需要停靠,然后是多停靠,然后再次停靠,但是实际上,这实际上导致用户能够创建非常复杂且令人困惑的布局。可停靠的UI的一个问题是,许多用户发现它们令人困惑(老实说,您会感到惊讶),并且会意外地将其移动或停靠在不需要的位置。 (例如,将菜单栏限制在顶部是一种好习惯-不允许移动该菜单栏。这很令人困惑。)

我们当前的设计是,主窗口的每一侧都有两个停靠点:一个普通停靠点,然后在旁边(靠近表单中心的地方)放置一个多停靠点。结果是,所有工具栏(例如菜单和普通工具栏)只能停靠在窗口边缘的旁边。然后,可停靠面板比该面板更靠近表单内部。在每个窗体边缘上使成对的坞站和多坞站彼此相邻,可以使两种类型的控件都停靠在窗体的任何一侧,但是将工具栏限制为始终位于窗体的最边缘。实际上,这使UI有意义:可停靠的面板在其中往往包含比工具栏更复杂的东西,并且随之而来的是它们是更多的中央控件。当然,如果窗体的一个特定边缘上只有可停靠的面板,而没有可停靠的工具栏,则工具栏停靠区是不可见的(宽度或高度为0),因此该面板也位于窗口边缘的旁边。



以文字形式编写,很难解释前两段(此方案如何工作,以及为什么这样/很好)。您需要在实践中进行尝试,并对用户的行为有所了解。但基本上,我建议您在表单上同时使用两种类型的停靠点,并保持TSpTBXMultiDock对齐在普通工具栏停靠点的“内部”或“内部”。希望此图像有所帮助。

其他

您可能对以下属性感兴趣:


DockableTo(工具栏和可固定面板):限制工具栏或面板可以固定在哪一侧(顶部,底部,左侧,右侧)。使用此选项可以使某些控件只能停靠在某些特定的停靠栏中,例如,仅在顶部停靠的主菜单。
DefaultDock(再次,两者):当用户双击停靠而不是拖放停靠时,它在哪里?
CurrentDock:我想您已经找到了,但是在设计器中对其进行了设置,以在扩展坞之间移动工具栏或面板,并在运行时读取(或者,如果您以编程方式希望将其移动到特定位置,我想在运行时进行设置)停靠。)
DockMode:控制工具栏或面板是否可以浮动(取消固定并成为其自己的窗口),包括是否可以更改停靠。使用此示例的一个例子是主菜单约束。
FixedDockSize(仅限面板):停止由用户或上述对接代码来调整面板的大小。
MenuBar(仅工具栏):使工具栏的行为略有不同,我认为它始终占用停靠栏的整个宽度,并且不允许其他工具栏停靠在旁边。它还可能会更改项目的呈现方式。

10-08 05:06