|
分類 : win32 版本
TMemDataset 就是存在記憶體上的資料表 (Table) 控件, 可供我們臨時存放二維資料之用, 也可當陣列使用, 處理一些需要在背景即時處理的資料運算功能, 像是收銀機上的刷入商品交易明細 Table, 每筆交易結帳後產生交易資料電文檔後即清空(等待下一個來客交易), 它就可以直接拿 TMemDataset 來用, 不用實際在硬碟中開一個實體 Table 檔, 免除 FILE I/O 的動作
■ TMemDataset 的問題
Lazarus 的 MemDataset 控件固然好用, 但它還有一些 bug, 像是它沒有一般 Table 控件都有的 搜尋Locate(), 排序索引(Index), 清空 EmptyTable() 等功能無法運作, 或是有該功能 Function 但使用時無反應 (如 Locate() ), 不過這些都是小事情, 今天要介紹的就是如何幫 MemDataset 控件加入這些功能, 讓它跟一般的 Table 控件一樣方便 ; 換句話說, 經過以下函式的加強與處理, MemDataset 控件就有完整的搜尋, 排序功能 (我把學校書本中學過的快速排序法都拿出來實做了)
■ 相關公用函式介紹
寫了一些公用函式, 主要是做字串處理的, 不只今天介紹的加強 MemDataset 功能會用到, 以後在別的地方也可以用
//------------------------------------------------------------------------------------------------------------------------------------
// 函數名稱:function _StrSeg(Str ,SegSymbol: String ; SegIndex: integer): String;
// 中文說明:依照逗點或其他分隔符號,取出字串中某一區段
// 傳 回 值:原始字串中第某段的字串
// 參 數:(原始字串, 分隔符號, 段別)
// 機能說明:分隔符號可以是任何字元(如逗點,分號,或是空白),甚至可以多 Byte 字串當分隔符號
// 例如有個字串(原始字串) S 內容為 'A,B,C,D,E;F,G'
// _StrSeg(S,',',2); 表以逗點當分隔字元識別,並取出第二段內容->'A,B,C,D,E;F,G' -> 即取出'B'
// _StrSeg(S,';',2); 表以分號當分隔字元識別,並取出第二段內容->'A,B,C,D,E;F,G' -> 即取出'F,G'
// _StrSeg(S,'D,E',2); 表以'D,E'(多 Byte 字串)當分隔字元識別,並取出第二段內容->'A,B,C,D,E;F,G' -> 即取出';F,G'
//------------------------------------------------------------------------------------------------------------------------------------
function _StrSeg(Str ,SegSymbol: String ; SegIndex: integer): String;
var r,c,s,sTmp : String;
i:integer;
begin
r:='';
if ((Str='') or (SegIndex<1)) then
begin
result:=r;
exit;
end;
c:=UTF8ToAnsi(SegSymbol);
if (c='') then c:=',';
i:=0;
s:=UTF8ToAnsi(Str);
sTmp:='';
while Pos(c,s)>0 do
begin
i:=i+1;
sTmp := Copy(s,1,Pos(c,s)-1);
if (SegIndex=i) then
begin
r:=AnsiToUTF8(sTmp);
break;
end;
s:=Copy(s , Pos(c,s)+Length(c) , Length(s)-(Pos(c,s)+Length(c))+1);
end;
if SegIndex=(i+1) then
begin
r:=AnsiToUTF8(s);
end;
result:=r;
end;
//------------------------------------------------------------------------------------------------------------------------------------
// 函數名稱:function _StrSegCount(Str,SegSymbol: String): integer;
// 中文說明:依照分隔符號,求區段數
// 傳 回 值:段數
// 參 數::(原始字串, 分隔符號, 段別)
// 機能說明:
//------------------------------------------------------------------------------------------------------------------------------------
function _StrSegCount(Str,SegSymbol: String): integer;
var r,i:integer;
c,s,sTmp : String;
begin
r:=0;
if (Str='') then
begin
result:=r;
exit;
end;
c:=UTF8ToAnsi(SegSymbol);
if (c='') then c:=',';
i:=0;
s:=UTF8ToAnsi(Str);
sTmp:='';
while Pos(c,s)>0 do
begin
i:=i+1;
sTmp := Copy(s,1,Pos(c,s)-1);
s:=Copy(s , Pos(c,s)+Length(c) , Length(s)-(Pos(c,s)+Length(c))+1);
end;
r:=i+1;
result:=r;
end;
■ 主要函式介紹
//------------------------------------------------------------------------------------------------------------------------------------
// 函數名稱:procedure _EmptyMemDataSet(DataSet:TMemDataSet);
// 中文說明:清空 MemDataSet
//網路抄來的 EmptyMemDataSet(), 原作提到
//Looping deletion of records seems to be increadibly slow.
//Therefore I use my EmptyMemDataset procedure instead of while not EOF do Delete;
//------------------------------------------------------------------------------------------------------------------------------------
procedure _EmptyMemDataSet(DataSet:TMemDataSet);
var
vTemporaryMemDataSet:TMemDataSet;
vFieldDef:TFieldDef;
I:Integer;
begin
try
//Create temporary MemDataSet
vTemporaryMemDataSet:=TMemDataSet.Create(nil);
//Store FieldDefs to Temporary MemDataSet
for I:=0 to DataSet.FieldDefs.Count-1 do begin
vFieldDef:=vTemporaryMemDataSet.FieldDefs.AddFieldDef;
with DataSet.FieldDefs[I] do begin
vFieldDef.Name:=Name;
vFieldDef.DataType:=DataType;
vFieldDef.Size:=Size;
vFieldDef.Required:=Required;
end;
end;
//Clear existing fielddefs
DataSet.Clear;
//Restore fielddefs
DataSet.FieldDefs:=vTemporaryMemDataSet.FieldDefs;
DataSet.Active:=True;
finally
vTemporaryMemDataSet.Clear;
vTemporaryMemDataSet.Free;
end;
end;
//------------------------------------------------------------------------------------------------------------------------------------
// 函數名稱:function _LocateMemDataSet(DataSet:TMemDataSet; FieldNames:String; FieldValues:String): Boolean;
// 中文說明:搜尋 MemDataSet 中的資料 (可使用複合欄位)
// 範 例: if LocateMemDataSet(MemDataset1,'GRP_NO;GRP_PQTY','d001;400') then
//------------------------------------------------------------------------------------------------------------------------------------
function _LocateMemDataSet(DataSet:TMemDataSet; FieldNames:String; FieldValues:String): Boolean;
var field_count:integer;
i,j:integer;
is_find:boolean;
begin
is_find:=false;
DataSet.First;
while not DataSet.Eof do
begin
is_find:=true;
for i:=1 to _StrSegCount(FieldNames,';') do
begin
if (DataSet.FieldByName(_StrSeg(FieldNames,';',i)).AsString<>_StrSeg(FieldValues,';',i)) then is_find:=false;
end;
if is_find then break;
DataSet.Next;
end;
result:=is_find;
end;
//------------------------------------------------------------------------------------------------------------------------------------
// 函數名稱:procedure _SortMemDataSet(DataSet:TMemDataSet; FieldNames:String; desc:integer);
// 中文說明:排序 MemDataSet 中的資料 (可使用複合欄位)
// 範 例: _SortMemDataSet(MemDataset1,'GRP_NO;GRP_PQTY',0); //升冪排序
// _SortMemDataSet(MemDataset1,'GRP_NO;GRP_PQTY',1); //降冪排序(Descending)
//------------------------------------------------------------------------------------------------------------------------------------
procedure _SortMemDataSet(DataSet:TMemDataSet; FieldNames:String; desc:integer);
var bookmark1,bookmark2:TBookmark;
left,right:String;
i:integer;
begin
DataSet.DisableControls;
if desc=0 then
_QuickSort(DataSet, FieldNames, 0, DataSet.RecordCount-1) //升冪
else
_QuickSortDesc(DataSet, FieldNames, 0, DataSet.RecordCount-1); //降冪
DataSet.EnableControls;
end;
//------------------------------------------------------------------------------------------------------------------------------------
//快速排序法(QUICK SORT)-升冪(一般)
//------------------------------------------------------------------------------------------------------------------------------------
procedure _QuickSort(DataSet: TMemDataSet; FieldNames: String; left, right: integer);
var i,j,k: integer;
pivot, tmp: string;
begin
if (left >= right) then Exit;
DataSet.First; DataSet.MoveBy(left);
pivot:='';
for k:=1 to _StrSegCount(FieldNames,';') do
begin
//pivot:=pivot+DataSet.FieldByName(_StrSeg(FieldNames,';',k)).AsString;
pivot:=pivot+_FieldValueAsString(DataSet, _StrSeg(FieldNames,';',k));
end;
i := left + 1;
j := right;
while (true) do
begin
while (i <= right) do
begin
DataSet.First; DataSet.MoveBy(i);
tmp:='';
for k:=1 to _StrSegCount(FieldNames,';') do
begin
//tmp:=tmp+DataSet.FieldByName(_StrSeg(FieldNames,';',k)).AsString;
tmp:=tmp+_FieldValueAsString(DataSet, _StrSeg(FieldNames,';',k));
end;
if (tmp > pivot) then
begin
break;
end;
i := i + 1;
end;
while (j > left) do
begin
DataSet.First; DataSet.MoveBy(j);
tmp:='';
for k:=1 to _StrSegCount(FieldNames,';') do
begin
//tmp:=tmp+DataSet.FieldByName(_StrSeg(FieldNames,';',k)).AsString;
tmp:=tmp+_FieldValueAsString(DataSet, _StrSeg(FieldNames,';',k));
end;
if (tmp < pivot) then
begin
break;
end;
j := j - 1;
end;
if (i > j) then break;
_Swap(DataSet, i, j);
end;
_Swap(DataSet, left, j);
_QuickSort(DataSet, FieldNames, left, j - 1);
_QuickSort(DataSet, FieldNames, j + 1, right);
end;
//------------------------------------------------------------------------------------------------------------------------------------
//快速排序法(QUICK SORT)-降冪
//------------------------------------------------------------------------------------------------------------------------------------
procedure _QuickSortDesc(DataSet: TMemDataSet; FieldNames: String; left, right: integer);
var i,j,k: integer;
pivot, tmp: string;
begin
if (left >= right) then Exit;
DataSet.First; DataSet.MoveBy(left);
pivot:='';
for k:=1 to _StrSegCount(FieldNames,';') do
begin
//pivot:=pivot+DataSet.FieldByName(_StrSeg(FieldNames,';',k)).AsString;
pivot:=pivot+_FieldValueAsString(DataSet, _StrSeg(FieldNames,';',k));
end;
i := left + 1;
j := right;
while (true) do
begin
while (i <= right) do
begin
DataSet.First; DataSet.MoveBy(i);
tmp:='';
for k:=1 to _StrSegCount(FieldNames,';') do
begin
//tmp:=tmp+DataSet.FieldByName(_StrSeg(FieldNames,';',k)).AsString;
tmp:=tmp+_FieldValueAsString(DataSet, _StrSeg(FieldNames,';',k));
end;
if (tmp < pivot) then //** 降冪修改這裡
begin
break;
end;
i := i + 1;
end;
while (j > left) do
begin
DataSet.First; DataSet.MoveBy(j);
tmp:='';
for k:=1 to _StrSegCount(FieldNames,';') do
begin
//tmp:=tmp+DataSet.FieldByName(_StrSeg(FieldNames,';',k)).AsString;
tmp:=tmp+_FieldValueAsString(DataSet, _StrSeg(FieldNames,';',k));
end;
if (tmp > pivot) then //** 降冪修改這裡
begin
break;
end;
j := j - 1;
end;
if (i > j) then break;
_Swap(DataSet, i, j);
end;
_Swap(DataSet, left, j);
_QuickSortDesc(DataSet, FieldNames, left, j - 1); //** 降冪修改這裡
_QuickSortDesc(DataSet, FieldNames, j + 1, right); //** 降冪修改這裡
end;
//------------------------------------------------------------------------------------------------------------------------------------
//將兩個不同的資料列(Row)中所有欄位值做交換
//------------------------------------------------------------------------------------------------------------------------------------
procedure _Swap(DataSet: TMemDataSet; row1, row2: integer);
var i:Integer;
var tmp: array[0..99] of Variant;
var tmp2: array[0..99] of Variant;
begin
DataSet.First; DataSet.MoveBy(row1);
for i:=0 to DataSet.FieldCount-1 do
begin
tmp:=DataSet.Fields.Fields.AsVariant;
end;
DataSet.First; DataSet.MoveBy(row2);
for i:=0 to DataSet.FieldCount-1 do
begin
tmp2:=DataSet.Fields.Fields.AsVariant;
end;
DataSet.First; DataSet.MoveBy(row1);
DataSet.Edit;
for i:=0 to DataSet.FieldCount-1 do
begin
DataSet.Fields.Fields.AsVariant:=tmp2;
end;
DataSet.Post;
DataSet.First; DataSet.MoveBy(row2);
DataSet.Edit;
for i:=0 to DataSet.FieldCount-1 do
begin
DataSet.Fields.Fields.AsVariant:=tmp;
end;
DataSet.Post;
end;
//------------------------------------------------------------------------------------------------------------------------------------
//數值欄位比大小的特別處理
//------------------------------------------------------------------------------------------------------------------------------------
function _FieldValueAsString(DataSet: TMemDataSet; fieldname: String): String;
var r:string;
begin
r:='';
case DataSet.FieldByName(fieldname).DataType of
ftSmallint : r:=FormatFloat('00000',DataSet.FieldByName(fieldname).AsInteger);
ftInteger : r:=FormatFloat('0000000000',DataSet.FieldByName(fieldname).AsInteger);
ftFloat : r:=FormatFloat('0000000000.00',DataSet.FieldByName(fieldname).AsFloat);
else
r:=DataSet.FieldByName(fieldname).AsString;
end;
result:=r;
end; |
评分
-
查看全部评分
|