7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Delphi】DBGrid のバグを回避する

Last updated at Posted at 2024-10-08

はじめに

個人的には DBGrid をあまり使わないので気付かなかったのですが、DBGrid には長い間バグが存在したようです。この問題は 『Delphi 10.1 Berlin』 以前のバージョンで発生します。

DBGrid のバグ

バグの再現方法と回避方法です。

再現方法

まず、何でもいいので DBGrid にデータを表示させます。

image.png

テストとして ADO で接続するようにしてみました。データは %ProgramFiles%\Common Files\Borland Shared\Datadbdemos.mdb を使いました。

Button1 と Button2 をクリックした時のイベントハンドラにこんな感じで記述します。

procedure TForm1.Button1Click(Sender: TObject);
begin
  ADOQuery1.Close;
  ADOQuery1.SQL.Text := 'select * from country';
  ADOQuery1.Open;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ADOQuery1.Close;
  ADOQuery1.SQL.Text := 'select * from country where Population < 0';
  ADOQuery1.Open;
end;

Button1 を押すと全件表示され、

image.png

Button2 を押すと 0 件になります。

image.png

もう一度 Button1 を押すと再度全件表示されます。

image.png

では次に、横スクロールバーが出ないようにフィールドを絞ってみます。Button1 と Button2 をクリックした時のイベントハンドラはこんな感じになります。

procedure TForm1.Button1Click(Sender: TObject);
begin
  ADOQuery1.Close;
  ADOQuery1.SQL.Text := 'select Name, Population from country';
  ADOQuery1.Open;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ADOQuery1.Close;
  ADOQuery1.SQL.Text := 'select Name, Population from country where Population < 0';
  ADOQuery1.Open;
end;

先程と同様に実行してみます。Button1 を押すと全件表示され、

image.png

Button2 を押すと 0 件になります。

image.png

もう一度 Button1 を押すと再度全件表示されますが、ここでバグが発生します。

image.png

縦スクロールバーが表示されていませんよね?

回避方法

この問題を回避するには、横スクロールバーを表示させるようにするか、強制的に縦スクロールバーを表示させます。

強制的に縦スクロールバーを表示させるのには ShowScrollBar() API を使います。

  ShowScrollBar(DBGrid1.Handle, SB_VERT, True);

See also:

インターポーザークラスを使った回避方法

インターポーザークラスを使って回避するのが簡単でしょう。以下のユニットを問題の出るプロジェクトに追加してください。

uDBGridFix.pas
unit uDBGridFix;
{$IFDEF CONDITIONALEXPRESSIONS}
  {$IF CompilerVersion >= 32.0}
    {$MESSAGE ERROR 'uDBGridFix.pas: This unit is only required for Delphi 10.1 Berlin or earlier.'}
  {$IFEND}
  {$IF CompilerVersion >= 23.0}
    {$DEFINE XE2_OR_LATER}
  {$IFEND}
{$ENDIF}

interface

uses
{$IFDEF XE2_OR_LATER}
  System.SysUtils, Vcl.DBGrids, Winapi.Windows;
{$ELSE}
  SysUtils, DBGrids, Windows;
{$ENDIF}

type
  TDBGrid = class({$IFDEF XE2_OR_LATER}Vcl.{$ENDIF}DBGrids.TDBGrid)
  protected
    procedure UpdateScrollBar; override;
  end;

implementation

{ TDBGrid }

procedure TDBGrid.UpdateScrollBar;
begin
  inherited;
  ShowScrollBar(Self.Handle, SB_VERT, True);
end;

end.

フォームに DBGrid を貼り付けている (or 使用している) ユニットの uses の最後に uDBGridFix を追記します (Vcl.DBGrid よりも後に記述してください)。

uses
  ..., uDBGridFix;

実行してみます。Button1 を押して、

image.png

Button2 を押して、

image.png

再び Button1 を押します。ちゃんと縦スクロールバーが表示されました。

image.png

0 件の時も縦スクロールバーが表示されるようになってしまいましたが実害はないと思います。

Delphi 10.2 Tokyo 以降で uDBGridFix が uses されているとコンパイル時にエラーが出るようになっています。

image.png

See also:

横スクロールバーの表示される DBGrid と 横スクロールバーの表示されない DBGrid が同じフォームに貼ってあるんだが?

混在しても大丈夫ですよ。縦スクロールバーしか表示されないなんて事はありません。

image.png

おわりに

この問題の解決方法は、今はなき Embarcadero Quality Central に投稿されていました。

バグ自体は一つ前の Quality Portal にも報告されていたようです。

See also:

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?