« MyBaseを試してみる。(グループ化) | トップページ | DBGridを同期させる。 »

MyBaseを試してみる。(インデックスを使わずに、行の追加、挿入、削除編) REVENGE(^o^)

前回、MyBaseを試してみる。(インデックスを使わずに、行の追加、挿入、削除編) の処理では、フィルターが使えなかったのですが、次の処理をフィルター前、挿入処理前に入れることにより、フィルターも可能になりました。でも、全く論理的ではない処理のため、使っている間に不具合が出るかも知れませんけどね(^-^)
// 挿入時、レコード位置を保持するための処理
procedure cdsUpdate(CDS: TClientDataSet);
var
  I: Integer;
  Data: OleVariant;
begin
  SaveUndoPoint(CDS);
  I := CDS.RecNo;
  Data := CDS.Data;
  CDS.Data := Data;
  CDS.RecNo := I;
end;

前回の処理では、一度レコードを挿入してから、フィルター処理・解除をすると、それ以降挿入したレコードは、最後に追加されてしまいました。例えスクリーン上で、正しく表示されていたとしても、正しくファイルに書き込むことができませんでした。今回の処理では、二度目以降のフィルター処理後も正しく表示されています。FilterプロパティでもOnFilterRecordでも問題ないようです。

とりあえずレコードを挿入します。

1


フィルター処理します。

2


フィルターを解除して、再びレコードを挿入します。

3


フィルター処理します。

4


フィルターを解除しても、レコードの並びは保持されています。(^o^)/

5


var
  RecNoList: TList<Integer> // Undoに使用
  SP: Integer = -1;          // Undoの処理に使用
  SN: Integer = 0;

// サンプルデータ
procedure MakeSample(DataSet: TDataSet);
var
  F: Boolean;
begin
  F := DataSet.Active;
  if not F then
    DataSet.Open;
  try
    // サンプルデータの追加
    with DataSet do
    begin
      Appendrecord(['iPod Touch']);
      Appendrecord(['Zaurus C-860']);
      Appendrecord(['Delphi 2009 Handbook']);
      Appendrecord(['GEORGIA BLACK']);
      CheckBrowseMode;
    end;
  finally
    if not F then
      DataSet.Close;
  end;
end;

// データベースの作成
procedure CreateDB(CDS: TClientDataSet; UsingIndex: Boolean);
var
  I: Integer;
begin
  CDS.Close;
  CDS.FieldDefs.Add('ITEM',ftWideString,20);
  CDS.CreateDataSet;
  CDS.Close;

  for I := 0 to CDS.FieldDefs.Count - 1 do
    CDS.FieldDefs[I].CreateField(CDS);

  CDS.Open;
  MakeSample(CDS);
end;

// DataSetの有効/無効
procedure DataSetEnabled(DataSet: TDataSet; Value: Boolean);
begin
  if Value then
    DataSet.EnableControls
  else
    DataSet.DisableControls;
end;

// SaveToFile
procedure cdsSaveToFile(CDS: TClientDataSet;
  const FileName: String);
begin
  if CDS.ChangeCount > 0 then
    CDS.MergeChangeLog;
  CDS.SaveToFile(FileName, dfXMLUTF8);
end;

// LoadFromFile
procedure cdsLoadFromFile(CDS: TClientDataSet;
  const FileName: String);
begin
  CDS.LoadFromFile(FileName);
end;

// 通し番号を返します。別に要らない処理です。
function GetSN: String;
begin
  Inc(SN);
  Result := IntToStr(SN);
end;

// 現在の状態を保存
procedure SaveUndoPoint(CDS: TClientDataSet);
begin
  // 変更があれば更新させます。
  if CDS.ChangeCount > 0 then
    CDS.MergeChangeLog;
  SP := (CDS as TClientDataSet).SavePoint;
end;

// SavePointから元に戻す処理
procedure Undo(CDS: TClientDataSet);
begin
  if SP > -1 then
    CDS.SavePoint := SP;
  SP := -1;
end;

// 削除されたレコードを元に戻す処理 ※コテコテ(^-^)
procedure UndoDelete(CDS: TClientDataSet);
var
  I, RC, RecNo: Integer;
  Delta: TClientDataSet;
begin
  if (RecNoList.Count <> 0) and (CDS.ChangeCount > 0) then
  begin
    Delta := TClientDataSet.Create(nil);
    try
      Delta.Data := CDS.Delta;
      Delta.Open;
      Delta.Last;
      I := -1;
      RC := CDS.RecordCount;

      // Insertで戻す場合、最後に追加されることをあるため、この処理を行う。
      cdsUpdate(CDS);  //20110922 追記 procedure cdsUpdateを前に持ってきてね。

      // Deltaから順番に戻していきます。
      while not Delta.Bof do
      begin
        Inc(I);
        if I < RecNoList.Count then
        begin
          RecNo := RecNoList[I];
          if RecNo > RC then
          begin
            CDS.Append;
            Inc(RC);
          end
          else
          begin
            CDS.RecNo := RecNo;
            CDS.Insert;
            Inc(RC);
          end;
          CDS.FieldByName('Item').AsString :=
            Delta.FieldByName('Item').AsString;
        end;
        Delta.Prior;
      end;
      CDS.CheckBrowseMode;
      CDS.MergeChangeLog;
      RecNoList.Clear;
    finally
      Delta.Free;
    end;
  end;
end;

// Undo
procedure cdsUndoNoIndex(CDS: TClientDataSet);
begin
    if RecNoList.Count > 0 then
    UndoDelete(CDS)            // 削除
  else if (SP > -1)  then
    Undo(CDS)                  // 追加/挿入-SavePoint
  else if CDS.ChangeCount > 0 then
    CDS.UndoLastChange(True);  // 上記以外
end;

// 追加
procedure cdsAppendNoIndex(CDS: TClientDataSet;
  Count: Integer = 1);
var
  I: Integer;
begin
  SaveUndoPoint(CDS);
  DataSetEnabled(CDS, False);
  try
    // Count分空白行を追加します。
    for I := 0 to Count - 1 do
    begin
      // 追加します。
      CDS.Append;
      CDS.FieldByName('ITEM').AsString := '追加'+ GetSN;
    end;
    CDS.CheckBrowseMode;
    // 今回追加した空白行の先頭レコードに移動させます。
    CDS.MoveBy(1-Count);
  finally
    DataSetEnabled(CDS, True);
  end;
end;

// 挿入時、レコード位置を保持するための処理
procedure cdsUpdate(CDS: TClientDataSet);
var
  I: Integer;
  Data: OleVariant;
begin
  SaveUndoPoint(CDS);
  I := CDS.RecNo;
  Data := CDS.Data;
  CDS.Data := Data;
  CDS.RecNo := I;
end;

// 挿入
procedure cdsInsertNoIndex(CDS: TClientDataSet;
  Count: Integer = 1);
var
  I: Integer;
  Data: OleVariant;
begin
  DataSetEnabled(CDS, False);
  try
    cdsUpdate(CDS);
    for I := 0 to Count -1 do
    begin
      // 挿入します。
      CDS.Insert;
      CDS.FieldByName('ITEM').AsString := '挿入'+ GetSN;
    end;
      CDS.CheckBrowseMode;
  finally
    DataSetEnabled(CDS, True);
  end;
end;

// 削除
procedure cdsDeleteNoIndex(CDS: TClientDataSet;
  BMList: TBookmarkList = nil);
type
  TIntegerComparer = TComparer<Integer>;
var
  I: Integer;
begin
  if not Assigned(BMList) then Exit;

  RecNoList.Clear;
  SaveUndoPoint(CDS);
  DataSetEnabled(CDS, False);
  try
    if Assigned(BMList) and (BMList.Count > 0) then
    begin
     for I := BMList.Count -1 downto 0 do
      begin
        CDS.GotoBookmark(BMList[I]);
        RecNoList.Add(CDS.RecNo);
        CDS.Delete;
      end;
      BMList.Clear;
    end;

    // RecNoListのソート
    RecNoList.Sort(TComparer<Integer>.Default);
  finally
    DataSetEnabled(CDS, True);
  end;
end;

// Filter
procedure cdsFiltered(CDS: TClientDataSet);
begin
  cdsUpdate(CDS);
  CDS.Filtered := not CDS.Filtered;
end;

// OnFilterRecord - ClientDataSet1で作成しておきます。
procedure TForm1.ClientDataSet1FilterRecord(DataSet: TDataSet;
  var Accept: Boolean);
begin
  Accept :=
    AnsiPos(Edit2.Text, DataSet.FieldByName('ITEM').AsString) > 0;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Undo用
  RecNoList:= TList<Integer>.Create;
  // データベースの作成
  CreateDB(ClientDataSet1, False);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(RecNoList);
end;

// SaveToFile
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  FileName: String;
begin
  FileName := ExtractFilePath(Application.ExeName) + 'MyBase.cds';
  cdsSaveToFile(ClientDataSet1,FileName);
end;

// LoadFromFile
procedure TForm1.SpeedButton2Click(Sender: TObject);
var
  FileName: String;
begin
  FileName := ExtractFilePath(Application.ExeName) + 'MyBase.cds';
  if FileExists(FileName) then
    cdsLoadFromFile(ClientDataSet1, FileName);
end;

// 追加
procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
  cdsAppendNoIndex(ClientDataSet1, StrToIntDef(Edit1.Text,1));
end;

// 挿入
procedure TForm1.SpeedButton4Click(Sender: TObject);
begin
  cdsInsertNoIndex(ClientDataSet1, StrToIntDef(Edit1.Text,1));
end;

// 削除
procedure TForm1.SpeedButton5Click(Sender: TObject);
begin
  cdsDeleteNoIndex(ClientDataSet1, DBGrid1.SelectedRows);
end;

// Undo
procedure TForm1.SpeedButton6Click(Sender: TObject);
begin
  cdsUndoNoIndex(ClientDataSet1);
end;

// Filter
procedure TForm1.SpeedButton7Click(Sender: TObject);
begin
  cdsUpdate(ClientDataset1);
  if not ClientDataset1.Filtered then
  begin
    case RadioGroup1.ItemIndex of
      0: begin
           ClientDataset1.Filter := '';
           ClientDataSet1.OnFilterRecord := ClientDataSet1FilterRecord;
         end;
      1 : begin
            ClientDataSet1.OnFilterRecord := nil;
            ClientDataset1.filter := 'ITEM LIKE '+QuotedStr('%' +  Edit2.Text+'%');
         end;
    end;
  end;
  cdsFiltered(ClientDataSet1);
end;

|

« MyBaseを試してみる。(グループ化) | トップページ | DBGridを同期させる。 »