Delphi TSplitter 闪烁问题

5
我正在使用启用了VCL样式的Delphi,我想为我的表单更改TSplitter的颜色。 我在一个interposer类中覆盖了TSplitter.Paint以绘制比默认的VCL样式cBtnFace颜色更暗的颜色,但是当调整大小时,表单上会出现明显的闪烁。 有没有办法消除这种闪烁?
我尝试了以下方法来尝试减少闪烁,但都没有成功:
  1. Disabling VCL styles (TSplitter.StyleElements := []).

  2. Changing the VCL Styles Bitmap Style Designer's object element for "Splitter," but modifying this object element doesn't change the splitter's appearance.

  3. Trying to process the WM_ERASEBKGND message on TControl objects, but I was unable to get the procedure to be called in my interposer class.

    procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND;
    ...
    procedure TSplitter.WMEraseBkgnd(var Msg: TWMEraseBkgnd);
    begin
        // this is never invoked by the TSplitter
        Msg.Result := 1;
    end;
    

有没有其他方法可以解决TSplitter的闪烁问题?据我所知,TSplitter没有DoubleBuffer属性或类似的东西。

更新

不幸的是,我无法分享代码库,但我可以告诉您在TSplitter闪烁时应用程序UI的设置方式:

TForm (DoubleBuffered = False)
-> BackgroundPanel (DoubleBuffered = True, ParentBackground = False)
-> -> A TGradient, image and label to fill the BackgroundPanel
-> LeftPanel (ParentBackground = False`, no flickering)
-> -> LeftPanelFrame and frame content (selective double buffering)
-> TSplitter
-> RightPanel (ParentBackground = False, no flickering)
-> -> RightPanelFrame and frame content (selective double buffering)

表单顶部也有一个工具栏和主菜单,但其余的UI组件都设置为alClient(或OnResized以填充空间)。

我假设由于BackgroundPanel在LeftPanel、TSplitter和RightPanel后面(即控件->发送到后面),因此BackgroundPanel上的DoubleBuffered = True和ParentBackground = False将有助于减少/消除其前方任何组件(如TSplitter)上的闪烁。但是,事实并非如此。

也许我会尝试将TPanel放置为LeftPanel、TSplitter和RightPanel的父级,并将其DoubleBuffered = True和ParentBackground = False。我稍后会尝试并回来。所以它看起来像这样:

TForm
-> BackgroundPanel (DoubleBuffered = True, ParentBackground = False)
-> -> A TGradient, image and label to fill the BackgroundPanel
-> EncapsulatingPanel (DoubleBuffered = True, ParentBackground = False)
-> -> LeftPanel (ParentBackground = False)
-> -> -> LeftPanelFrame and frame content
-> -> TSplitter
-> -> RightPanel (ParentBackground = False)
-> -> -> RightPanelFrame and frame content

最后,我应该指出,双缓冲TForm在调整大小时会显著减慢UI(窗口右侧有黑色轨迹),而不是在应用程序不调整大小时进行其他UI操作时。
更新2
不幸的是,虽然我的上述方法(创建背景父TPanel)修复了TSplitter上的闪烁问题,但它也引起了其他奇怪的UI问题,其中一些可能与@David Heffernan在评论中提到的问题有关。目前,我只留下了闪烁问题,因为分隔线只有1像素宽,并且只在宽度+高度调整大小时闪烁。

我仍在等待引入TFlickerFreeFormTFlickerFreeControl - Jerry Dodge
有时候看起来不太可行,但你尝试过启用“DoubleBuffered”吗? - Jerry Dodge
@JerryDodge 如果你是指我的问题底部,TSplitter 上没有 DoubleBuffered 属性。我已经尝试在父 UI 对象上启用 DoubleBuffered,但无济于事。 - spurgeon
2
在窗体上启用DoubleBuffered会破坏许多其他功能。最好只在调整大小时启用它。最好通过其他方式避免它。我对此的回答是一个很好的开始:https://dev59.com/4Wsz5IYBdhLWcg3wNE5q - David Heffernan
1
那个逻辑不能在尺寸循环中运行。尺寸循环只负责计算尺寸。 - David Heffernan
显示剩余8条评论
1个回答

4
TSplitter控件可能没有DoubleBuffered属性,但是这个属性应该在你遇到闪烁的最上层控件上实现 - 在大多数情况下,就是窗体。只要所有的控件仍然默认启用了ParentDoubleBuffered,它们也会获得这个改变。 DoubleBuffered并不总是能解决闪烁问题,在某些情况下甚至会使情况变得更糟。你可以考虑只在调整大小期间使用DoubleBuffered,然后在调整大小完成后将其关闭。这个属性应该只用于那些真正被调整大小的控件。例如,在调整大小窗体时,在窗体上启用DoubleBuffered。但是当仅调整面板的内容时,仅为该面板(及其所有子控件)启用它。
至于应用程序由于这个改变而导致的性能下降,你还可以考虑在调整大小时实现一个标志,暂停任何可能拖慢程序执行的程序执行(例如重新绘制的标签、图像等)。这本身也可能是你问题的解决方案(事实上可能是第二个答案)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接