나는 로그로 TMemo
을 사용하고 이벤트가 호출 될 때마다 그 행을 추가합니다. 새 줄을 추가하기 전에 BeginUpdate
을 사용한 다음 EndUpdate
을 사용하고 DoubleBuffered
을 사용하도록 설정했습니다. 그러나 스크롤 막대가 두 번 깜박임없이 계속 버퍼링되는 것처럼 보입니다. 스크롤바를 DoubleBuffered := True
으로 설정할 수있는 방법이 있습니까?TMemo의 스크롤 막대 DoubleBuffered
편집 :
국경이 너무 깜박 거리는 것처럼 보입니다. 그것이 스크롤 바 (들)과 관련이 있는지 확실하지 않습니다.
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.
일부 코드를 표시하거나 해결하려는 내용을 설명 할 수 있습니까? TMemo를 여러 앱에서 로그처럼 사용합니다. Begin/EndUpdate 또는 DoubleBuffered를 사용하지 마십시오. 문제가 없습니다. 'Lines.Add()'를 사용하고 있습니까? –
@MarcusAdams 예'Lines.Add'를 사용합니다. GUI와 동기화되는 많은 tthreads 코드는 없습니다. Begin/EndUpdate 또는 DoubleBuffered를 사용하지 않으면 깜박입니다. –
BeginUpdate/EndUpdate 기능을 사용하지 마십시오. –