由于数据比较多,
如果不用线程来读取则会出现界面长时间假死的状态,非常不爽,用线程后会出现一些奇怪的现象:
调用线程后,DBGrid会闪一下,然后要拖动滚动条才可以看到显示不正常的数据;
具体表现为: 列宽不对/很多区域为空白,好像没有数据一样,
// 线程类的定义与实现:
type
TLoadDataThrd = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure SetGridWidth;
public
adoConn : TADOConnection;
SQLString:WideString;
DBGridTemp:TDBGrid;
adsData:TADODataSet;
dsData:TDataSource;
end;{ TLoadDataThrd }
procedure TLoadDataThrd.SetGridWidth;
var
i : integer;
begin
for i := 0 to DBGridTemp.Columns.Count-1 do
begin
DBGridTemp.Columns[i].Width := 70;
end;
end;procedure TLoadDataThrd.Execute;
begin
adsData.Close;
adsData.Connection := adoConn;
adsData.CommandText := SQLString;
try
adsData.Open;
if adsData.Active then
begin
SetGridWidth;// 虽然此处调用了此函数来设置Grid列宽度,但是最后显示出的宽度根本不正确!
end;
finally
end;
end;// 在窗口类中实现调用线程
{TfrmData}
//function TfrmData.getSQLCmd:WideString; // 获取 sql语句的函数,返回如:select * from .....
// adoConn1:TAdoConnection;
// DBGridTest:TDBGrid;
// adsTest:TADODataSet;
// dsTest:TDatasource;
function TfrmData.RunThread(adoConnTemp:TADOConnection; SQLString : widestring;
DBGridTemp:TDBGrid; adsTemp: TADODataSet; dsTemp : TDataSource): TLoadDataThrd;
var
loadThread:TLoadDataThrd;
begin
loadThread := TLoadDataThrd.Create(True);
loadThread.adoConn := adoConnTemp;
loadThread.DBGPM := DBGridTemp;
loadThread.adsData := adsTemp;
loadThread.dsData := dsTemp;
loadThread.SQLString := SQLString;
loadThread.Resume; Result := loadThread;
end;// 此处调用线程取数据库数据
procedure TfrmData.btnSearchClick(Sender: TObject);
begin
RunThread(adoConn1,getSQLCmd,DBGridTest,adsTest,dsTest);
end;
如果不用线程来读取则会出现界面长时间假死的状态,非常不爽,用线程后会出现一些奇怪的现象:
调用线程后,DBGrid会闪一下,然后要拖动滚动条才可以看到显示不正常的数据;
具体表现为: 列宽不对/很多区域为空白,好像没有数据一样,
// 线程类的定义与实现:
type
TLoadDataThrd = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure SetGridWidth;
public
adoConn : TADOConnection;
SQLString:WideString;
DBGridTemp:TDBGrid;
adsData:TADODataSet;
dsData:TDataSource;
end;{ TLoadDataThrd }
procedure TLoadDataThrd.SetGridWidth;
var
i : integer;
begin
for i := 0 to DBGridTemp.Columns.Count-1 do
begin
DBGridTemp.Columns[i].Width := 70;
end;
end;procedure TLoadDataThrd.Execute;
begin
adsData.Close;
adsData.Connection := adoConn;
adsData.CommandText := SQLString;
try
adsData.Open;
if adsData.Active then
begin
SetGridWidth;// 虽然此处调用了此函数来设置Grid列宽度,但是最后显示出的宽度根本不正确!
end;
finally
end;
end;// 在窗口类中实现调用线程
{TfrmData}
//function TfrmData.getSQLCmd:WideString; // 获取 sql语句的函数,返回如:select * from .....
// adoConn1:TAdoConnection;
// DBGridTest:TDBGrid;
// adsTest:TADODataSet;
// dsTest:TDatasource;
function TfrmData.RunThread(adoConnTemp:TADOConnection; SQLString : widestring;
DBGridTemp:TDBGrid; adsTemp: TADODataSet; dsTemp : TDataSource): TLoadDataThrd;
var
loadThread:TLoadDataThrd;
begin
loadThread := TLoadDataThrd.Create(True);
loadThread.adoConn := adoConnTemp;
loadThread.DBGPM := DBGridTemp;
loadThread.adsData := adsTemp;
loadThread.dsData := dsTemp;
loadThread.SQLString := SQLString;
loadThread.Resume; Result := loadThread;
end;// 此处调用线程取数据库数据
procedure TfrmData.btnSearchClick(Sender: TObject);
begin
RunThread(adoConn1,getSQLCmd,DBGridTest,adsTest,dsTest);
end;
unit TQueryThreadUnit;interfaceuses
Classes,ADODB,DB,ActiveX,ComCtrls;type
TQueryThread = class(TThread)
private
FDataSet :TADODataSet;
FDataSource :TDataSource;
FStatusBar :TStatusBar;
procedure HookUpUI;
{ Private declarations }
protected
procedure Execute; override;
public
constructor Create(ADataSet:TADODataSet;ADataSource:TDataSource;AStatusBar:TStatusBar);virtual;
end;implementation{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure TQueryThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }{ TQueryThread }
constructor TQueryThread.Create(ADataSet:TADODataSet;ADataSource:TDataSource;AStatusBar:TStatusBar);
begin
inherited Create(True);
FDataSet := ADataSet;
FDataSource := ADataSource;
FStatusBar := AStatusBar;
FreeOnTerminate := True;
Resume;
end;procedure TQueryThread.Execute;
begin
{ Place thread code here }
CoInitialize(nil);
try
if not FDataSet.Active then FDataSet.Open;
Synchronize(HookUpUI);
finally
CoUninitialize;
end;
end;procedure TQueryThread.HookUpUI;
begin
FDataSource.DataSet := FDataSet;
FStatusBar.SimpleText := '已經打開數據表!';
end;
end.
[Error] UnitData.pas(122): There is no overloaded version of 'Synchronize' that can be called with these arguments
如果同步的时间很长则没有多大改变
建议数据如果很多的话进行分页显示
procedure TLoadDataThrd.Execute;
begin
adsData.Close;
adsData.Connection := adoConn;
adsData.CommandText := SQLString;
try
adsData.Open;
if adsData.Active then
begin
Synchronize(SetGridWidth);// 虽然此处调用了此函数来设置Grid列宽度,但是最后显示出的宽度根本不正确!
end;
finally
end;
end;
function SetGridWidth:Boolean;还有一个问题就是,假如我的function/procedure带有参数,该如何用Synchronize来调用?
比如:
function SetGridWidth(iCount:integer):boolean;
你可以把参数放在线程的局部变量里
然后在Synchronize调用的过程里访问它们
TMyThread=class(TThread)
private
FVar: Integer;
procedure UpdateUI;
...
procedure Execute; override;
begin
FVar:= 100;
..
Synchronize(UpdateUI);
end;procedure UpdateUI;
begin
Form1.caption:= Inttostr(FVar);
end;类似这种吧,线程单元里引入主窗体单元,把FrmMain传进来,在UpdateUI里更新主窗体;其实没必要一定要用Synchronize,给主线程发消息,消息里面带参数,主线程收到消息处理参数也是可以的; 建议Google下 delphi+线程+UI,研究下看看~
如:invalid pointer operation,
Access violation at address ......