我注意到Delphi工具栏有些令人讨厌的怪异。我有一个TToolbar
具有逻辑图标组。为了使分组脱颖而出,我想使用样式为tbsDivider
的分隔符按钮。
当我这样做时,它看起来像这样:
注意每个图标之间的双垂直线。右手一个位于分隔符工具按钮的中间。左手一个位于分隔符工具按钮的左边缘。
所以,我可以切换到删除中间行的tbsSeparator
:
但是我并不热衷于此,因为我希望分频器处于中间位置。
我查看了我的真实应用程序的古老版本,发现它有居中的分隔符。当禁用Windows主题时,似乎可以实现。以下是使用tbsDivider
并删除应用程序清单的情况:
这就是我要找的布局。当主题活跃时,这是否可以实现?
我确实在Embarcadero论坛上找到了关于这个问题的讨论,但是没有有用的见解:https://forums.embarcadero.com/message.jspa?messageID=467842
为了完整起见,这里是.dfm文件的相关摘录
object ToolButton1: TToolButton
Left = 0
Top = 0
ImageIndex = 0
end
object ToolButton2: TToolButton
Left = 23
Top = 0
Width = 16
ImageIndex = 1
Style = tbsDivider
end
object ToolButton3: TToolButton
Left = 39
Top = 0
ImageIndex = 1
end
object ToolButton4: TToolButton
Left = 62
Top = 0
Width = 16
ImageIndex = 2
Style = tbsDivider
end
object ToolButton5: TToolButton
Left = 78
Top = 0
ImageIndex = 2
end
答案 0 :(得分:4)
这看起来像VCL中的一个缺陷。 tbsDivider
样式未映射到Win32中的等效样式。具有该样式的工具按钮在VCL中以与tbsSeparator
样式相同的方式实现,但具有自定义绘制方法。这是从TToolButton.Paint
:
if Style = tbsDivider then
with Canvas do
begin
R := Rect(Width div 2 - 1, 0, Width, Height);
if StyleServices.Enabled then
begin
Details := StyleServices.GetElementDetails(ttbSeparatorNormal);
StyleServices.DrawElement(Handle, Details, R);
end
else
DrawEdge(Handle, R, EDGE_ETCHED, BF_LEFT)
end;
在v6之前的comctl32中,tbsSeparator
样式映射到Win32 TBSTYLE_SEP
样式工具按钮。在pre-v6 comctl32中,它简单地呈现为没有垂直线的空间。 VCL设计师显然希望做更多工作,并在上面的自定义绘画中添加了tbsDivider
。
快进到v6 comctl32。现在,公共控件在所有TBSTYLE_SEP
分隔符的左边缘绘制一条垂直线。因此,上面的代码只是在分隔符的中间添加了一条额外的垂直线。
我们可以尝试通过修改代码来摆脱tbsDivider
的左侧垂直线:
if Style = tbsDivider then
with Canvas do
begin
if StyleServices.Enabled then
begin
//re-paint the background to remove the vertical line drawn
//for the standard separator button
R := Rect(0, 0, Width, Height);
StyleServices.DrawParentBackground(FToolBar.Handle, Handle, nil, False, R);
end;
R := Rect(Width div 2 - 1, 0, Width, Height);
if StyleServices.Enabled then
begin
Details := StyleServices.GetElementDetails(ttbSeparatorNormal);
StyleServices.DrawElement(Handle, Details, R);
end
else
DrawEdge(Handle, R, EDGE_ETCHED, BF_LEFT)
end;
然而,这并不奏效,因为画了左手线然后画了很多闪烁。
我怀疑VCL设计师在过渡到v6 comctl32时错过了这个神秘的细节。
我会在适当的时候提交质量控制报告。
答案 1 :(得分:3)
当工具栏具有平面样式时,本机控件会为分隔符按钮绘制垂直线。因此,如果您删除平面样式,您将独自使用VCL的 divider 行。您可以安全地删除应用程序主题时的样式,主题工具栏按钮不考虑平面样式(为什么工具栏分隔符,我不知道)。但是,当禁用主题时,将再次出现两行。在这种情况下,保持分隔符而不是分隔符似乎是更好的选择。
有人会猜测取消设置Flat
属性会对documentation状态产生任何影响。但是,TToolBar.CreateParams
在启用StyleServices
时无条件启用它。因此需要API调用;
procedure TForm1.FormCreate(Sender: TObject);
var
TbStyle: DWORD;
begin
if StyleServices.Enabled then begin
TbStyle := SendMessage(ToolBar1.Handle, TB_GETSTYLE, 0, 0);
SendMessage(Toolbar1.Handle, TB_SETSTYLE, 0, TbStyle and not TBSTYLE_FLAT);
end;
end;
这消除了部分问题,剩下的部分是分隔线并不完全位于两个按钮之间的中心。这里的VCL问题是,它不想画线本身。因此它调用主题api,它将分隔符行绘制在分隔符的左侧。为了规避,VCL将分隔符矩形的右半部分传递给api,并且该行在中间得到 about 。我不知道是否有任何方法可以确切地说出主题api的确切位置,我怀疑是否存在。
答案 2 :(得分:3)
如前所述,由于操作系统的变化,您无法使用TToolBar执行此操作。
但是,通过使用ActionToolBars,您可以实现您想要实现的目标 - 即使使用当前版本的Delphi(XE6)和Windows 8.1 / 2012 R2主题。以下是步骤:
最终结果 - 一个漂亮的应用程序,在你的图标旁边有分隔符。