お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル

"データベース上複写機能"








◆解説
  DBGridで編集中に、手前のレコードの内容を「上複写」する機能が
  欲しくて作成した関数です。

  関数(関数名が長すぎるかなぁ(^^;)
    function GetFieldValueFromRelativeRecord(BDEDataSet: TBDEDataSet;
                                   PosOffset: Integer; Field: TField;
                                       var RetVal: Variant): Boolean;
  処理内容
    BDEDataSetのカレントレコードに対して、
    PosOffsetで指定した相対位置のレコードから、
    Fieldに対応したフィールド値を RetValに取得します。

  入力パラメータ
    BDEDataSet: TBDEDataSet
                Table1や Query1などを指定する
                CachedUpdatesモードにも対応している(と思う)
    PosOffset: Integer
                カレントレコードからの相対位置を指定する
                -1で手前のレコード, 1で次のレコード
                もちろん -2,-3 といった指定も可能
    Field: TField
                BDEDataSetパラメータに指定したDataSet内の
                TFieldオブジェクトを指定する
                ※このオブジェクトのValue値が変更されることはない
    var RetVal: Variant
                目的のフィールド値を受け取る Varinat型変数
  戻り値
    False: 指定の相対位置のレコードがない(BOF or EOF)
    True:  フィールド値の取得に成功
           var RetVal: Variantに値が代入されている
  ※BOF, EOF以外のエラーが発生した場合には、例外が発生する

◆動作確認
  Delphi3.1 + Win95a + Paradox形式のデータベースファイル

◆例
  (1) Form1に Table1, DataSource1, DBGrid1, SpeedButton1を置く
      DBGrid1     DataSource   ← DataSource1
      DataSource1 DataSet      ← Table1
      Table1      DatabaseName ← DBDEMOS
                  TableName    ← BIOLIFE.DB
                  Active       ← True
  (2) uses に BDE, DBCommon を追加する
----- ここから -----
interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Buttons, Grids, DBGrids, Db, DBTables,
  BDE, DBCommon;

type
  TForm1 = class(TForm)
    ...省略

implementation

{$R *.DFM}
 //-------------------- キリトリ線 --------------------
 //uses
 //  SysUtils, BDE, Db, DBTables, DBCommon が必要
 //
 //↓このtype宣言が必要
type
  TMyBDEDataSet = class(TBDEDataSet);

function GetFieldValueFromRelativeRecord(BDEDataSet: TBDEDataSet;
                          PosOffset: Integer; Field: TField;
                               var RetVal: Variant): Boolean;
var
  CursorProps: CurProps;
  SaveBookmark: String;
  RecBuf: PChar;
  ARecProps: RecProps;
  FieldData: String;
  rc: DBIResult;
  IsBlank: LongBool;
  BlobSize, BlobReadSize: Longint;
  P,dstP: Pointer;
  CurValue: Currency;
  TimeStamp: TTimeStamp;
begin
  Result := True;
  RetVal := Null;

  if not BDEDataSet.Active then
    raise Exception.Create(BDEDataSet.Name+'がOpenされていない');
  if Field.FieldKind <> fkData then
    raise Exception.Create('FieldKindが fkDataでない');

  //カーソルをカレントレコードに移動
  BDEDataSet.UpdateCursorPos;
  //DbiGetBookMark によりカーソル位置を保存
  Check(DbiGetCursorProps(BDEDataSet.Handle, CursorProps));
  SetLength(SaveBookmark, CursorProps.iRecBufSize);
  Check(DbiGetBookMark(BDEDataSet.Handle, PChar(SaveBookmark)));
  try //レコードバッファ確保
    RecBuf := TMyBDEDataSet(BDEDataSet).AllocRecordBuffer;
    try //PosOffset位置のレコードを読み込む
      rc := DbiGetRelativeRecord(BDEDataSet.Handle, PosOffset,
                                 dbiNOLOCK, RecBuf, @ARecProps);
      if rc <> DBIERR_NONE then begin
        Result := False; //読み込みエラー
        if (rc = DBIERR_BOF) or (rc = DBIERR_EOF) then Exit;
        Check(rc);
      end;
      Check(DbiGetField(BDEDataSet.Handle, Field.FieldNo,
                        RecBuf, nil, IsBlank));
      if IsBlank then Exit; //指定Recordの指定Fieldが NULL値だった

      //フィールド値の読み込み&代入
      if not Field.IsBlob then begin
        //BLOBでない場合
        SetLength(FieldData, Field.DataSize);
        Check(DbiGetField(BDEDataSet.Handle, Field.FieldNo,
                          RecBuf, PChar(FieldData), IsBlank));
        P := PChar(FieldData);
        case Field.DataType of
          ftBytes,    //固定長バイト型項目 (バイナリ格納)
          ftVarBytes: //可変長バイト型項目 (バイナリ格納)
            begin
              RetVal := VarArrayCreate([0, Field.DataSize - 1], varByte);
              dstP := VarArrayLock(RetVal);
              try
                Move(P^, dstP^, Field.DataSize);
              finally
                VarArrayUnlock(RetVal);
              end;
            end;
          ftString:  RetVal := StrPas(P);
          ftWord:    RetVal := Word(P^);
          ftSmallint:RetVal := Smallint(P^);
          ftInteger,
          ftAutoInc: RetVal := Integer(P^);
          ftBoolean: RetVal := WordBool(P^);
          ftFloat:   RetVal := Double(P^);
          ftCurrency:RetVal := Currency(P^);
          ftBCD:   begin
                     FMTBCDToCurr(FMTBcd(P^), CurValue);
                     RetVal := CurValue;
                   end;
          ftTime:  begin
                     TimeStamp.Time := LongInt(P^);
                     TimeStamp.Date := DateDelta;
                     RetVal := TimeStampToDateTime(TimeStamp);
                   end;
          ftDate:  begin
                     TimeStamp.Time := 0;
                     TimeStamp.Date := Integer(P^);
                     RetVal := TimeStampToDateTime(TimeStamp);
                   end;
          ftDateTime:RetVal := TimeStampToDateTime(
                               MSecsToTimeStamp(Double(P^)));
        end;
      end else begin
        //BLOB項目の場合  //BLOBハンドル取得
        Check(DbiOpenBlob(BDEDataSet.Handle,
                          RecBuf, Field.FieldNo, dbiReadOnly));
        try //BLOBデータの取得
          Check(DbiGetBlobSize(BDEDataSet.Handle,
                               RecBuf, Field.FieldNo, BlobSize));
          SetLength(FieldData, BlobSize);
          Check(DbiGetBlob(BDEDataSet.Handle, RecBuf, Field.FieldNo,
                           0, BlobSize, PChar(FieldData), BlobReadSize));
          RetVal := FieldData;
        finally //BLOBハンドル解放
          Check(DbiFreeBlob(BDEDataSet.Handle, RecBuf, Field.FieldNo));
        end;
      end;
    finally //レコードバッファ解放
      TMyBDEDataSet(BDEDataSet).FreeRecordBuffer(RecBuf);
    end;
  finally
    //DbiSetToBookMark によりカーソルをもとの位置に戻す
    Check(DbiSetToBookMark(BDEDataSet.Handle, PChar(SaveBookmark)));
  end;
end;
 //-------------------- キリトリ線 --------------------

 //-------------------- ↓使 用 例 --------------------
 //SppeButton1 OnClickイベント
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  Value: Variant;
begin
  if not GetFieldValueFromRelativeRecord
        (Table1, -1, DBGrid1.SelectedField, Value) then begin
    ShowMessage('手前のレコードがありません');
  end else begin
    //上複写する
    if not(Table1.State in [dsInsert, dsEdit]) then Table1.Edit;
    DBGrid1.SelectedField.AsVariant := Value;
  end;
end;
----- ここまで -----

  実行して、DBGrid1で編集作業中に SpeedButton1をクリックすると、
  「上複写」が行われます。
  ※キリトリ線の内側を別ユニットに分離しておくと、何かと便利かも?

◆注意点その1
  指定された相対位置のレコードを読み、その中のフィールド値を返す、
  という関数であるため、計算項目や参照項目などの TFieldを指定する
  と例外が発生します。

◆注意点2
  Fieldの DataTypeが ftString, ftInteger, ftFloat, ftDateTime で
  ある場合はとりあえず正常に取得できます。
  また、:DBDEMOS:BIOLIFE.DBにより ftMemo, ftGraphic型の取得も正常
  に行えることを確認しました。
  その他の項目タイプは動作未確認です。(^^;
  特に ftBytes    固定長バイト型項目 (バイナリ格納)
       ftVarBytes 可変長バイト型項目 (バイナリ格納)
  これらの項目タイプの RetValへの代入ルーチンは、正しいのかどうか?
  不安がいっぱいです...((((;^^)

◆注意点3
  動作を確認したのは、Paradox形式のデータベースのみです。
  Paradox以外の形式のデータベースでも正常に機能するのか?
  私にはわからないです。m(_`_)m

◆その他
  BDE APIを直接呼び出すプログラムは、ほとんど作ったことが無いので
  間違いがあるようでしたら指摘していただけると幸いです。

                                 98/11/21(土) 01:05 Satobe(JCG00336)

Original document by Satobe          氏 ID:(JCG00336)


ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。

Copyright 1996-2002 Delphi Users' Forum