Андреас прав в буферизации двойной буферизации. Это самый важный аспект, о котором я должен знать.
Как мягкий контрапункт, мне не нравится двойная буферизация вообще, потому что очень трудно сделать это правильно. Многие компоненты не имеют успеха. Я думаю о выпадающих списках VCL, которые не рисуются прямо под Windows Basic. Есть другие!
Но некоторые элементы управления действительно нуждаются в двойной буферизации, чтобы избежать мерцания, так что вы делаете? Вам нужна двойная буферизация, когда пользователь подключен локально, но вы не хотите облагать его налогом пропускной способности сети, когда он удален.
Итак, вот что я делаю:
procedure WMWTSSessionChange(var Message: TMessage); message WM_WTSSESSION_CHANGE;
procedure TBaseForm.WMWTSSessionChange(var Message: TMessage);
begin
case Message.WParam of
WTS_CONSOLE_DISCONNECT,WTS_REMOTE_DISCONNECT,
WTS_SESSION_LOCK,WTS_SESSION_LOGOFF:
SessionDisconnected;
WTS_CONSOLE_CONNECT,WTS_REMOTE_CONNECT,
WTS_SESSION_UNLOCK,WTS_SESSION_LOGON:
SessionConnected;
end;
inherited;
end;
function WTSRegisterSessionNotification(hWnd: HWND; dwFlags: DWORD): BOOL; stdcall; external 'Wtsapi32.dll';
function WTSUnRegisterSessionNotification(hWnd: HWND): BOOL; stdcall; external 'Wtsapi32.dll';
const
NOTIFY_FOR_THIS_SESSION = 0;
NOTIFY_FOR_ALL_SESSIONS = 1;
procedure TBaseForm.CreateWnd;
begin
inherited;
WTSRegisterSessionNotification(WindowHandle, NOTIFY_FOR_THIS_SESSION);
end;
procedure TBaseForm.DestroyWnd;
begin
WTSUnRegisterSessionNotification(WindowHandle);
inherited;
end;
Все формы в моем приложении происходят от TBaseForm
и поэтому наследуют это поведение. Методы SessionConnected
и SessionDisconnected
являются virtual
, поэтому отдельные формы могут выполнять определенные действия.
В частности, все мои формы называют UpdateDoubleBuffered
:
function InRemoteSession: Boolean;
begin
Result := Windows.GetSystemMetrics(SM_REMOTESESSION)<>0;
end;
class procedure TBaseForm.UpdateDoubleBuffered(Control: TWinControl);
var
DoubleBuffered: Boolean;
begin
if InRemoteSession then begin
//see The Old New Thing, Taxes: Remote Desktop Connection and painting
DoubleBuffered := False;
end else begin
DoubleBuffered := (Control is TCustomListView)
or (Control is TCustomStatusBar);
//TCustomListView flickers when updating without double buffering
//TCustomStatusBar has drawing infidelities without double buffering in my app
end;
Control.DoubleBuffered := DoubleBuffered;
end;
procedure TBaseForm.UpdateDoubleBuffered;
var
Control: TControl;
begin
for Control in ControlEnumerator(TWinControl) do begin
UpdateDoubleBuffered(TWinControl(Control));
end;
end;
ControlEnumerator
- это перечислитель, который обходит дочерние элементы компонента.
Ссылка "Старая новая вещь" относится к статье под названием Налоги: подключение к удаленному рабочему столу и рисование , которая послужила моим вдохновением для большей части этого кода.
Я уверен, что существуют другие проблемы, связанные с удаленным рабочим столом, но двойная буферизация, безусловно, является одной из наиболее важных.