I use TMemo as a Log and I add lines to it every time an event has been called. Before I add a new line I use BeginUpdate and then EndUpdate and also have DoubleBuffered enabled. However, it seems like that the scrollbar(s) are not double buffered at all an keep flickering. Is there a way I can also set the scrollbars to DoubleBuffered := True?
Edit:
It seems like that the boarder is flickering too. Not sure if that's associated with the scrollbar(s).
unit uMainWindow; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, IdContext, IdBaseComponent, IDGlobal, IdComponent, IdCustomTCPServer, IdTCPServer, Vcl.ComCtrls, Winsock; type TMainWindow = class(TForm) TCPServer: TIdTCPServer; StatusBar: TStatusBar; PageControl: TPageControl; ConfigSheet: TTabSheet; StartButton: TButton; PortEdit: TLabeledEdit; LogSheet: TTabSheet; LogMemo: TMemo; LogEdit: TLabeledEdit; TCPLogSheet: TTabSheet; TCPLogEdit: TLabeledEdit; TCPLogMemo: TMemo; CheckBox1: TCheckBox; procedure StartButtonClick(Sender: TObject); private public end; // ============================= Public Vars =================================== var MainWindow : TMainWindow; hServer : TSocket; sAddr : TSockAddrIn; ListenerThread : TThread; // =============================== Threads ===================================== type TListenThread = class (TThread) private procedure WriteToTCPLog (Text : String); public Form : TMainWindow; procedure Execute; override; end; type TReceiveThread = class (TThread) private procedure WriteToTCPLog (Text : String); public Form : TMainWindow; hSocket : TSocket; IP : String; procedure Execute; override; end; implementation {$R *.dfm} // ================================= Uses ====================================== uses uTools, uCommonConstants; // ================================== TListenThread ============================ procedure TListenThread.WriteToTCPLog(Text: string); var MaxLines : Integer; begin if not(Form.CheckBox1.Checked) then exit; if GetCurrentThreadId = MainThreadID then begin Form.TCPLogMemo.Lines.BeginUpdate; MaxLines := StrToInt(Form.TCPLogEdit.Text); if Form.TCPLogMemo.Lines.Count >= MaxLines then begin repeat Form.TCPLogMemo.Lines.Delete(0); until Form.TCPLogMemo.Lines.Count < MaxLines; end; Form.TCPLogMemo.Lines.Add (Text); Form.TCPLogMemo.Lines.EndUpdate; end else begin Text := '[' + DateToStr (Now) + ' - ' + TimeToStr(Now) + '] ' + Text; Synchronize(procedure begin WriteToTCPLog(Text); end); end; end; procedure TListenThread.Execute; var iSize : Integer; hClient : TSocket; cAddr : TSockAddrIn; SynchIP : String; begin WriteToTCPLog ('Server started'); while not (terminated) do begin iSize := SizeOf(cAddr); hClient := Accept(hServer, @cAddr, @iSize); if (hClient <> INVALID_SOCKET) then begin SynchIP := inet_ntoa(cAddr.sin_addr); WriteToTCPLog(SynchIP + ' - connected.'); with TReceiveThread.Create (TRUE) do begin FreeOnTerminate := TRUE; hSocket := hClient; IP := SynchIP; Form := Self.Form; Resume; end; end else begin break; end; end; WriteToTCPLog('Server stopped.'); end; // ==================================== TReceiveThread ========================= procedure TReceiveThread.WriteToTCPLog(Text: string); var MaxLines : Integer; begin if not(Form.CheckBox1.Checked) then exit; if GetCurrentThreadId = MainThreadID then begin Form.TCPLogMemo.Lines.BeginUpdate; MaxLines := StrToInt(Form.TCPLogEdit.Text); if Form.TCPLogMemo.Lines.Count >= MaxLines then begin repeat Form.TCPLogMemo.Lines.Delete(0); until Form.TCPLogMemo.Lines.Count < MaxLines; end; Form.TCPLogMemo.Lines.Add (Text); Form.TCPLogMemo.Lines.EndUpdate; end else begin Text := '[' + DateToStr (Now) + ' - ' + TimeToStr(Now) + '] ' + Text; Synchronize(procedure begin WriteToTCPLog(Text); end); end; end; procedure TReceiveThread.Execute; var iRecv : Integer; bytBuf : Array[0..1023] of byte; begin iRecv := 0; while true do begin ZeroMemory(@bytBuf[0], Length(bytBuf)); iRecv := Recv(hSocket, bytBuf, SizeOf(bytBuf), 0); if iRecv > 0 then begin WriteToTCPLog(IP + ' - data received (' + inttostr(iRecv) + ' bytes).'); end; if iRecv <= 0 then break; end; WriteToTCPLog(IP + ' - disconnected.'); closesocket(hSocket); end; // ================================= TMainWindow =============================== procedure TMainWindow.StartButtonClick(Sender: TObject); begin if StartButton.Caption = 'Start' then begin try hServer := Socket(AF_INET, SOCK_STREAM, 0); sAddr.sin_family := AF_INET; sAddr.sin_port := htons(StrToInt(PortEdit.Text)); sAddr.sin_addr.S_addr := INADDR_ANY; if Bind(hServer, sAddr, SizeOf(sAddr)) <> 0 then raise Exception.Create(''); if Listen(hServer, 3) <> 0 then raise Exception.Create(''); except OutputError (Self.Handle, 'Error','Port is already in use or blocked by a firewall.' + #13#10 + 'Please use another port.'); exit; end; ListenerThread := TListenThread.Create (TRUE); TListenThread(ListenerThread).Form := Self; TListenThread(ListenerThread).Resume; StartButton.Caption := 'Stop'; end else begin closesocket(hServer); ListenerThread.Free; StartButton.Caption := 'Start'; end; end; end.
Lines.Add()?TThreadedQueue, and this queue is drained in the main thread inside a timer event, the strain of the GUI will ease and likely the flicker will not be of any problem anymore. All in all, this is what David is proposing.