DBGridの列データ自動保存、自動読込

解決


Ru  2008-04-01 03:07:31  No: 30339

いつも参考にしています。
コンポーネントの作成について相談させてください。

TDBGridColumnsのメソッドに LoadFromFile と SaveToFile がありますが,
このメソッドを TDBGrid作成時と破棄時に 組み込み
列データの保存と呼び出しを自動で行えるように実装したいと考えています(プロパティで切替可能)

現在,作成時は CreateWnd メソッドを,終了時は Destroy メソッドを override を行って処理をしています。
ただこのままだとプロジェクトを開いた時と終了する時に,CreateWndとDestory が動くみたいで,
開く時は下記のエラーが発生します。
  フォーム作成中にエラーが発生しました。_1.Columns の読み込み中のエラー : TColumn.Expanded の読み込み中のエラー : リストのインデックスが範囲を超えています (0)
終了する際はエラーは出ないのですが,設計時の列データが保存されてしまいます。
(設計時は無効にするコンパイラ指令があったりする?)

何か対処法又は,良い手法があれば教えて頂けると幸いです。
コンポーネントを作成するのは初めてで考え方が間違っている所もあると思います。
よろしくお願いします。

=====================================================================
unit MyDBGrid;

interface

uses
  SysUtils, Classes, Controls, Grids, DBGrids;

type
  TMyDBGrid = class(TDBGrid)
  private
    FColumnSave: Boolean;
    { Private 宣言 }
    procedure SetColumnSave(const Value: Boolean);
  protected
    { Protected 宣言 }
    procedure CreateWnd; override;    
  public
    { Public 宣言 }
    destructor Destroy; override;
  published
    { Published 宣言 }
    property ColumnAutoSave: Boolean read FColumnSave write SetColumnSave default False;    
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Data Controls', [TMyDBGrid]);
end;

{ TMyDBGrid }

procedure TMyDBGrid.CreateWnd;
begin
  inherited;

  if FColumnSave then
  begin
    if FileExists('Col_' + Owner.Name + Name + '.dat') = True then
    begin
      Columns.LoadFromFile('Col_' + Owner.Name + Name + '.dat');
    end;
  end;

end;

destructor TMyDBGrid.Destroy;
begin
  if FColumnSave then
  begin
    Columns.SaveToFile('Col_' + Owner.Name + Name + '.dat');
  end;
  inherited;
end;

procedure TMyDBGrid.SetColumnSave(const Value: Boolean);
begin
  FColumnSave := Value;
end;

end.


Ru  2008-04-01 03:22:05  No: 30340

Create部分記載忘れました。

type
  TMyDBGrid = class(TDBGrid)
  private
    FColumnSave: Boolean;
    { Private 宣言 }
    procedure SetColumnSave(const Value: Boolean);
  protected
    { Protected 宣言 }
    procedure CreateWnd; override;    
  public
    { Public 宣言 }
    constructor Create(AOwner: TComponent); override;    //追加
    destructor Destroy; override;
  published
    { Published 宣言 }
    property ColumnAutoSave: Boolean read FColumnSave write SetColumnSave default False;    
  end;

constructor TMyDBGrid.Create(AOwner: TComponent);
begin
  inherited;
  FColumnSave := False;
end;


Ru  2008-04-01 23:22:45  No: 30341

自己レスです。
CreateWndメソッド部分をLoadedメソッドに変更したところ,
プロジェクトを開いた際のエラーは発生しなくなりました。

しかしいまだプロジェクトファイルを開いた時と閉じた時に,
overrideした部分が動いてしまいます(ColumnAutoSave=True時)。
これはコンポーネントの性質,又は私の作成方法では対処方法がないのでしょうか?
よろしくお願いします。
=====================================================================================
unit MyDBGrid;

interface

uses
  SysUtils, Classes, Controls, Grids, DBGrids, DB;

type
  TMyDBGrid = class(TDBGrid)
  private
    FColumnSave: Boolean;
    { Private 宣言 }
    procedure SetColumnSave(const Value: Boolean);
  protected
    { Protected 宣言 }
    procedure Loaded; override;
  public
    { Public 宣言 }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published 宣言 }
    property ColumnAutoSave: Boolean read FColumnSave write SetColumnSave default False;    
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Data Controls', [TMyDBGrid]);
end;

{ TMyDBGrid }

constructor TMyDBGrid.Create(AOwner: TComponent);
begin
  inherited;
  FColumnSave := False;          
end;

procedure TMyDBGrid.Loaded;
begin
  inherited;
  if FColumnSave then
  begin
    Columns.Clear;
    if FileExists('Col_' + Owner.Name + Name + '.dat') = True then
    begin
      Columns.LoadFromFile('Col_' + Owner.Name + Name + '.dat');
    end;
  end;
end;

destructor TMyDBGrid.Destroy;
begin
  if FColumnSave then
  begin
    //列設定なしでデータセットが閉じている時は Columns.Count = 1 になる
    //この場合は保存しない
    if (DataSource.DataSet.State <> dsInactive) or
       ((DataSource.DataSet.State = dsInactive) and (Columns.Count > 1)) then
    begin
      Columns.SaveToFile('Col_' + Owner.Name + Name + '.dat');
    end;
  end;
  inherited;
end;

procedure TMyDBGrid.SetColumnSave(const Value: Boolean);
begin
  FColumnSave := Value;
end;

end.


Ru  2008-04-02 20:38:12  No: 30342

さらに自己レスです。
Create時とDestory時に
  if Not(csDesigning in ComponentState) then
とすればデザイン時は無効にするようにできました。
コンポーネント作る上で基本なんでしょうが初めて見ました・・・
あとDestory時にDataSourceが解放されているとメモリエラーになるので
以下のように修正しました。

destructor TMyDBGrid.Destroy;
begin

  if Not(csDesigning in ComponentState) then
  begin

    if FColumnSave then
    begin
      //列設定なしでデータセットが閉じている時は Columns.Count = 1 になる
      //この場合は保存しない
      if Assigned(DataSource) then
      begin
        if (DataSource.DataSet.State <> dsInactive) or
           ((DataSource.DataSet.State = dsInactive) and (Columns.Count > 1)) then
        begin
          Columns.SaveToFile('Col_' + Owner.Name + Name + '.dat');
        end;
      end
      else
      begin
        if Columns.Count > 1 then
        begin
          Columns.SaveToFile('Col_' + Owner.Name + Name + '.dat');
        end;
      end;
    end;
  end;

  inherited;
end;

とりあえず動く形にはなったので完了とします。
もし問題点があれば助言いただくと幸いです。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加