>所以,我有一个应用程序加载不同的插件并创建一个
每个TPageControl上的新选项卡。
>每个DLL都有一个与它相关联的TForm。
>这些表单是用他们的父hWnd作为新的TTabSheet创建的。
>由于TTabSheets不是VCL的父表单(不想使用动态RTL和其他语言的插件),因此我必须手动调整大小。我这样做如下:
每个TPageControl上的新选项卡。
>每个DLL都有一个与它相关联的TForm。
>这些表单是用他们的父hWnd作为新的TTabSheet创建的。
>由于TTabSheets不是VCL的父表单(不想使用动态RTL和其他语言的插件),因此我必须手动调整大小。我这样做如下:
var ChildHandle : DWORD; begin If Assigned(pcMain.ActivePage) Then begin ChildHandle := FindWindowEx(pcMain.ActivePage.Handle,'TfrmPluginForm',nil); If ChildHandle > 0 Then begin SetWindowPos(ChildHandle,pcMain.ActivePage.Width,pcMain.ActivePage.Height,SWP_NOZORDER + SWP_NOACTIVATE + SWP_NOCOPYBITS); end; end;
现在,我的问题是当应用程序调整大小时,TGroupBox中的所有TGroupBox和TLabels闪烁。不在TGroupBox内的TLabel很好,不闪烁。
我试过的事情
> WM_SETREDRAW,后跟一个RedrawWindow
> ParentBackground在TGroupBoxes和TLabels设置为False
> DoubleBuffer:= True
> LockWindowUpdate(是的,即使我知道这是非常错误的)
> Transparent:= False(甚至覆盖创建来编辑ControlState)
有任何想法吗?
解决方法@H_502_22@
我发现唯一可以正常工作的是使用WS_EX_COMPOSITED窗口样式。这是一个性能猪,所以我只是在大小循环中启用它。我的经验是,使用内置的控件,在我的应用程序中,只有在调整窗体大小时才会发生闪烁。
您应该首先执行一个快速测试,看看这种方法是否可以帮助您,只需将WS_EX_COMPOSITED窗口样式添加到所有窗口控件。如果这样工作,你可以考虑下面更先进的方法:
快攻
procedure EnableComposited(WinControl: TWinControl);
var
i: Integer;
NewExStyle: DWORD;
begin
NewExStyle := GetWindowLong(WinControl.Handle,GWL_EXSTYLE) or WS_EX_COMPOSITED;
SetWindowLong(WinControl.Handle,GWL_EXSTYLE,NewExStyle);
for i := 0 to WinControl.ControlCount-1 do
if WinControl.Controls[i] is TWinControl then
EnableComposited(TWinControl(WinControl.Controls[i]));
end;
调用这个,例如,在您的TForm的OnShow中,传递表单实例。如果这有帮助,那么你真的应该更明智地实施它。我向我提供了我的代码中的相关摘录,以说明我是如何做到的。
全代码
procedure TMyForm.WMEnterSizeMove(var Message: TMessage);
begin
inherited;
BeginSizing;
end;
procedure TMyForm.WMExitSizeMove(var Message: TMessage);
begin
EndSizing;
inherited;
end;
procedure SetComposited(WinControl: TWinControl; Value: Boolean);
var
ExStyle,NewExStyle: DWORD;
begin
ExStyle := GetWindowLong(WinControl.Handle,GWL_EXSTYLE);
if Value then begin
NewExStyle := ExStyle or WS_EX_COMPOSITED;
end else begin
NewExStyle := ExStyle and not WS_EX_COMPOSITED;
end;
if NewExStyle<>ExStyle then begin
SetWindowLong(WinControl.Handle,NewExStyle);
end;
end;
function TMyForm.SizingCompositionIsPerformed: Boolean;
begin
//see The Old New Thing,Taxes: Remote Desktop Connection and painting
Result := not InRemoteSession;
end;
procedure TMyForm.BeginSizing;
var
UseCompositedWindowStyleExclusively: Boolean;
Control: TControl;
WinControl: TWinControl;
begin
if SizingCompositionIsPerformed then begin
UseCompositedWindowStyleExclusively := Win32MajorVersion>=6;//XP can't handle too many windows with WS_EX_COMPOSITED
for Control in ControlEnumerator(TWinControl) do begin
WinControl := TWinControl(Control);
if UseCompositedWindowStyleExclusively then begin
SetComposited(WinControl,True);
end else begin
if WinControl is TPanel then begin
TPanel(WinControl).FullRepaint := False;
end;
if (WinControl is TCustomGroupBox) or (WinControl is TCustomRadioGroup) or (WinControl is TCustomGrid) then begin
//can't find another way to make these awkward customers stop flickering
SetComposited(WinControl,True);
end else if ControlSupportsDoubleBuffered(WinControl) then begin
WinControl.DoubleBuffered := True;
end;
end;
end;
end;
end;
procedure TMyForm.EndSizing;
var
Control: TControl;
WinControl: TWinControl;
begin
if SizingCompositionIsPerformed then begin
for Control in ControlEnumerator(TWinControl) do begin
WinControl := TWinControl(Control);
if WinControl is TPanel then begin
TPanel(WinControl).FullRepaint := True;
end;
UpdateDoubleBuffered(WinControl);
SetComposited(WinControl,False);
end;
end;
end;
function TMyForm.ControlSupportsDoubleBuffered(Control: TWinControl): Boolean;
const
NotSupportedClasses: array [0..1] of TControlClass = (
TCustomForm,//general policy is not to double buffer forms
TCustomRichEdit//simply fails to draw if double buffered
);
var
i: Integer;
begin
for i := low(NotSupportedClasses) to high(NotSupportedClasses) do begin
if Control is NotSupportedClasses[i] then begin
Result := False;
exit;
end;
end;
Result := True;
end;
procedure TMyForm.UpdateDoubleBuffered(Control: TWinControl);
function ControlIsDoubleBuffered: Boolean;
const
DoubleBufferedClasses: array [0..2] of TControlClass = (
TMyCustomGrid,//flickers when updating
TCustomListView,//flickers when updating
TCustomStatusBar//drawing infidelities,e.g. my main form status bar during file loading
);
var
i: Integer;
begin
if not InRemoteSession then begin
//see The Old New Thing,Taxes: Remote Desktop Connection and painting
for i := low(DoubleBufferedClasses) to high(DoubleBufferedClasses) do begin
if Control is DoubleBufferedClasses[i] then begin
Result := True;
exit;
end;
end;
end;
Result := False;
end;
var
DoubleBuffered: Boolean;
begin
if ControlSupportsDoubleBuffered(Control) then begin
DoubleBuffered := ControlIsDoubleBuffered;
end else begin
DoubleBuffered := False;
end;
Control.DoubleBuffered := DoubleBuffered;
end;
procedure TMyForm.UpdateDoubleBuffered;
var
Control: TControl;
begin
for Control in ControlEnumerator(TWinControl) do begin
UpdateDoubleBuffered(TWinControl(Control));
end;
end;
这不会为你编译,但它应该包含一些有用的想法。 ControlEnumerator是我的实用工具,用于将子控件的递归步调转换为平面循环。请注意,我还使用一个自定义分割器,当它处于活动状态时调用BeginSizing / EndSizing。
另一个有用的技巧是使用TStaticText而不是TLabel,当您拥有深度嵌页的页面控件和面板时,您偶尔需要执行此操作。
我使用这个代码使我的应用程序100%闪烁免费,但它花了我的年龄和年龄的实验,以获得它所有到位。希望别人能在这里找到有用的东西。
您应该首先执行一个快速测试,看看这种方法是否可以帮助您,只需将WS_EX_COMPOSITED窗口样式添加到所有窗口控件。如果这样工作,你可以考虑下面更先进的方法:
快攻
procedure EnableComposited(WinControl: TWinControl); var i: Integer; NewExStyle: DWORD; begin NewExStyle := GetWindowLong(WinControl.Handle,GWL_EXSTYLE) or WS_EX_COMPOSITED; SetWindowLong(WinControl.Handle,GWL_EXSTYLE,NewExStyle); for i := 0 to WinControl.ControlCount-1 do if WinControl.Controls[i] is TWinControl then EnableComposited(TWinControl(WinControl.Controls[i])); end;
调用这个,例如,在您的TForm的OnShow中,传递表单实例。如果这有帮助,那么你真的应该更明智地实施它。我向我提供了我的代码中的相关摘录,以说明我是如何做到的。
全代码
procedure TMyForm.WMEnterSizeMove(var Message: TMessage); begin inherited; BeginSizing; end; procedure TMyForm.WMExitSizeMove(var Message: TMessage); begin EndSizing; inherited; end; procedure SetComposited(WinControl: TWinControl; Value: Boolean); var ExStyle,NewExStyle: DWORD; begin ExStyle := GetWindowLong(WinControl.Handle,GWL_EXSTYLE); if Value then begin NewExStyle := ExStyle or WS_EX_COMPOSITED; end else begin NewExStyle := ExStyle and not WS_EX_COMPOSITED; end; if NewExStyle<>ExStyle then begin SetWindowLong(WinControl.Handle,NewExStyle); end; end; function TMyForm.SizingCompositionIsPerformed: Boolean; begin //see The Old New Thing,Taxes: Remote Desktop Connection and painting Result := not InRemoteSession; end; procedure TMyForm.BeginSizing; var UseCompositedWindowStyleExclusively: Boolean; Control: TControl; WinControl: TWinControl; begin if SizingCompositionIsPerformed then begin UseCompositedWindowStyleExclusively := Win32MajorVersion>=6;//XP can't handle too many windows with WS_EX_COMPOSITED for Control in ControlEnumerator(TWinControl) do begin WinControl := TWinControl(Control); if UseCompositedWindowStyleExclusively then begin SetComposited(WinControl,True); end else begin if WinControl is TPanel then begin TPanel(WinControl).FullRepaint := False; end; if (WinControl is TCustomGroupBox) or (WinControl is TCustomRadioGroup) or (WinControl is TCustomGrid) then begin //can't find another way to make these awkward customers stop flickering SetComposited(WinControl,True); end else if ControlSupportsDoubleBuffered(WinControl) then begin WinControl.DoubleBuffered := True; end; end; end; end; end; procedure TMyForm.EndSizing; var Control: TControl; WinControl: TWinControl; begin if SizingCompositionIsPerformed then begin for Control in ControlEnumerator(TWinControl) do begin WinControl := TWinControl(Control); if WinControl is TPanel then begin TPanel(WinControl).FullRepaint := True; end; UpdateDoubleBuffered(WinControl); SetComposited(WinControl,False); end; end; end; function TMyForm.ControlSupportsDoubleBuffered(Control: TWinControl): Boolean; const NotSupportedClasses: array [0..1] of TControlClass = ( TCustomForm,//general policy is not to double buffer forms TCustomRichEdit//simply fails to draw if double buffered ); var i: Integer; begin for i := low(NotSupportedClasses) to high(NotSupportedClasses) do begin if Control is NotSupportedClasses[i] then begin Result := False; exit; end; end; Result := True; end; procedure TMyForm.UpdateDoubleBuffered(Control: TWinControl); function ControlIsDoubleBuffered: Boolean; const DoubleBufferedClasses: array [0..2] of TControlClass = ( TMyCustomGrid,//flickers when updating TCustomListView,//flickers when updating TCustomStatusBar//drawing infidelities,e.g. my main form status bar during file loading ); var i: Integer; begin if not InRemoteSession then begin //see The Old New Thing,Taxes: Remote Desktop Connection and painting for i := low(DoubleBufferedClasses) to high(DoubleBufferedClasses) do begin if Control is DoubleBufferedClasses[i] then begin Result := True; exit; end; end; end; Result := False; end; var DoubleBuffered: Boolean; begin if ControlSupportsDoubleBuffered(Control) then begin DoubleBuffered := ControlIsDoubleBuffered; end else begin DoubleBuffered := False; end; Control.DoubleBuffered := DoubleBuffered; end; procedure TMyForm.UpdateDoubleBuffered; var Control: TControl; begin for Control in ControlEnumerator(TWinControl) do begin UpdateDoubleBuffered(TWinControl(Control)); end; end;
这不会为你编译,但它应该包含一些有用的想法。 ControlEnumerator是我的实用工具,用于将子控件的递归步调转换为平面循环。请注意,我还使用一个自定义分割器,当它处于活动状态时调用BeginSizing / EndSizing。
另一个有用的技巧是使用TStaticText而不是TLabel,当您拥有深度嵌页的页面控件和面板时,您偶尔需要执行此操作。
我使用这个代码使我的应用程序100%闪烁免费,但它花了我的年龄和年龄的实验,以获得它所有到位。希望别人能在这里找到有用的东西。