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

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

# DBGrid のバグ

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

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/f37021ff-5ac8-a614-eb0c-addf649a95e7.png)

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

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

```pascal
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/1e340e51-053a-d18a-cb71-ce902454ff58.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/1d4b0ba8-525a-cbe6-6d7f-e0de81d67ffd.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/1e340e51-053a-d18a-cb71-ce902454ff58.png)

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

```pascal
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/ba72e97e-8e68-f1dd-2a5f-b9dbdc4acdfd.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/cb5c9ed0-e746-53c3-1d14-ccd034d11a2f.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/a579e5e4-51ac-6205-ffb7-b29acb254e81.png)

<font color="Crimson">縦スクロールバーが表示されていません</font>よね？

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

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

```pascal
  ShowScrollBar(DBGrid1.Handle, SB_VERT, True);
```

**See also:**

 - [ShowScrollBar 関数 (winuser.h) (learn.microsoft.com)](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-showscrollbar)

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

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

```pascal: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 よりも後に記述してください)。

```pascal
uses
  ..., uDBGridFix;
```

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/ba72e97e-8e68-f1dd-2a5f-b9dbdc4acdfd.png)

Button2 を押して、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/e1005341-210d-1709-d5f7-3ce36d2872c5.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/ba72e97e-8e68-f1dd-2a5f-b9dbdc4acdfd.png)

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

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/6d3d73c1-f29c-311b-6c93-0300b14206ac.png)
:::


**See also:**

 - [【Delphi】インターポーザークラス (Qiita)](https://qiita.com/ht_deko/items/d5a5fbd37cca097cf186)

### 横スクロールバーの表示される DBGrid と 横スクロールバーの表示されない DBGrid が同じフォームに貼ってあるんだが？
混在しても大丈夫ですよ。縦スクロールバーしか表示されないなんて事はありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/2e68c435-4b8a-27b8-7b29-edd87e269ee7.png)


# おわりに

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

 - [QC#7527: TDBGrid vertical scrollbar dissappears (Quality Central)](http://qc.embarcadero.com/wc/qcmain.aspx?d=7527)
 - [QC#7527: TDBGrid vertical scrollbar dissappears (Internmet Archive)](https://web.archive.org/web/20171221014924/http://qc.embarcadero.com/wc/qcmain.aspx?d=7527)

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

 - [RSP-20092: TDBGrid ScrollBar BUG (Quality Portal)](https://quality.embarcadero.com/browse/RSP-20092)

**See also:**

 - [071_TDBGrid のスクロールバーの表示制御 (Mr.XRAY)](mrxray.on.coocan.jp/Delphi/plSamples/071_TDBGrid_ScrollBar.htm)