【发布时间】:2013-10-12 21:33:56
【问题描述】:
我使用TMemo 作为日志,并在每次调用事件时添加行。
在添加新行之前,我使用BeginUpdate,然后使用EndUpdate,并且还启用了DoubleBuffered。但是,滚动条似乎根本没有双缓冲并一直闪烁。有没有办法也可以将滚动条设置为DoubleBuffered := True?
编辑:
似乎寄宿生也在闪烁。不确定这是否与滚动条相关联。
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()吗? -
尽量不要使用BeginUpdate/EndUpdate函数。
-
请出示您的代码。有什么地方不对劲。
-
我可以让它“闪烁”的唯一方法是删除开始/结束更新,因为删除将滚动按钮向上移动,添加向下移动它。我认为这使用GDI。也许您的机器有 GDI 问题(很慢)?也许你可以描述闪烁。
-
如果工作线程将日志信息放入
TThreadedQueue,并且此队列在计时器事件内的主线程中耗尽,则 GUI 的压力会减轻,并且闪烁可能不会有任何问题了。总而言之,这就是大卫的提议。