Điều duy nhất tôi đã tìm thấy để làm việc tốt là sử dụng phong cách WS_EX_COMPOSITED
cửa sổ. Đây là một hog hiệu suất vì vậy tôi chỉ kích hoạt nó khi trong một vòng lặp kích thước. Đó là kinh nghiệm của tôi rằng, với các điều khiển tích hợp, trong ứng dụng của tôi, nhấp nháy chỉ xảy ra khi thay đổi kích thước biểu mẫu.
Trước tiên, bạn nên thực hiện kiểm tra nhanh để xem liệu phương pháp này có giúp bạn không đơn giản bằng cách thêm kiểu cửa sổ WS_EX_COMPOSITED
vào tất cả các điều khiển cửa sổ của bạn. Nếu thành công, bạn có thể xem xét các phương pháp tiên tiến hơn dưới đây: Hack
nhanh
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;
Gọi này, ví dụ, trong OnShow
cho TForm
của bạn, đi qua các ví dụ mẫu. Nếu điều đó giúp bạn thực sự nên thực hiện nó một cách sáng suốt hơn. Tôi cung cấp cho bạn các chất chiết xuất có liên quan từ mã của tôi để minh họa cách tôi đã làm điều đó.
Full đang
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, GWL_EXSTYLE, 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;
này sẽ không biên dịch cho bạn, nhưng nó phải chứa một số ý tưởng hữu ích. ControlEnumerator
là tiện ích của tôi để biến bước đi đệ quy của điều khiển con thành vòng lặp for
phẳng. Lưu ý rằng tôi cũng sử dụng bộ tách tùy chỉnh gọi BeginSizing/EndSizing khi nó đang hoạt động.
Một mẹo hữu ích khác là sử dụng TStaticText
thay vì TLabel
mà đôi khi bạn cần phải thực hiện khi bạn có lồng sâu các bảng điều khiển và bảng điều khiển trang.
Tôi đã sử dụng mã này để làm cho ứng dụng của tôi không bị nhấp nháy 100% nhưng nó đã cho tôi độ tuổi và độ tuổi của thử nghiệm để làm cho nó tất cả tại chỗ. Hy vọng rằng những người khác có thể tìm thấy một cái gì đó sử dụng ở đây.
Câu hỏi này có một vài ý tưởng bổ sung trong câu trả lời và nhận xét: http://stackoverflow.com/q uestions/4031147 – Argalatyr