DBGridの境界線クリックについて。

解決


のり0203  2012-06-13 00:36:56  No: 42468

DbGridに関してもう一つ質問させていただきます。
DbGridのタイトルの境界線をクリックがダブルクリックして、
Grid幅を最大長にあわせたいのでが
どうしたらよいでしょうか?
Delphi7です。
どなたか解決方法をお願い致します


のり0203  2012-06-13 04:05:49  No: 42469

自己レスですが
delphi-fanさんのホームページをもとに
http://hiderin.air-nifty.com/delphi/tdbgrid/index.html
境界線のクリックを拾えるみたいで、
作成してみました。
あっているかどうかもわかりませんが、
一応、動作します。
どなたかコメントをお願いします。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, DBTables, Grids, DBGrids,SubClassUnit,ExtCtrls,StdCtrls;

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    Table1: TTable;
    DataSource1: TDataSource;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure DBGrid1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure DBGrid1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure DBGrid1TitleClick(Column: TColumn);
  private
    { Private 宣言 }
    RowHeight: Integer;
    SubClass2: TSubClass;
    procedure SubClass2MessageAfter(Sender: TObject;      var message: TMessage);
    function ColumMatchWidth(AFieldName: String): Integer;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
type
  TDummyDBGrid = class(TCustomDBGrid);

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Tableの設定
  Table1.DatabaseName := 'DBDEMOS';
  Table1.TableName := 'country.db';
  Table1.Open;
  // 常に編集モード
  DBGrid1.Options := DBGrid1.Options + [dgAlwaysShowEditor];
  // サブクラスの設定 - MouseDownの取得だけ
  SubClass2:= TSubClass.Create(Self);
  SubClass2.TargetControl := DBGrid1;
  SubClass2.OnMessageAfter := SubClass2MessageAfter;
  // 行の高さ
  RowHeight := TDummyDBGrid(DBGrid1).DefaultRowHeight;

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Table1.Close;
  SubClass2.Free;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  //
end;

var
  AX: Integer =0;
  IsBoundaryLine: Boolean = False;
  IsColumnMoving: Boolean = False;

procedure TForm1.DBGrid1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  // タイトル間のクリックは、ここでは取得できません。
  // タイトルのクリックは、取得できます。
  IsColumnMoving := True;
end;

procedure TForm1.DBGrid1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  I: Integer;
  Cell: TGridCoord;
begin
  IsColumnMoving := False;
  // カラム幅の同期
  // カラムをクリックされた場合のみチェックします。
  // 本来、Cell.Yは0が返されるべきですが、時々1が返ってきます。
  // そのためCell.Y in [0,1]としています。
  Cell := DBGrid1.MouseCoord(X, Y);
  if Y = 0 then
    IsBoundaryLine := False;
end;

// こちらは単純にDBGrid1のMouseDownを取得しているだけです。
// カラム間のクリックは、DBGridのOnMouseDownでは取得できなかった。
procedure TForm1.SubClass2MessageAfter(Sender: TObject; var message: TMessage);
begin
  case Message.Msg of
    WM_LBUTTONDOWN:
      begin
        if (Message.LParamHi < RowHeight) and (not IsColumnMoving)  then
        begin
          IsBoundaryLine:=True;
        end;
      end;
  end;
end;

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var
  ColumnName : String;
  P : TPoint;
  Pos : TPoint;
  ACOl,ARow: Integer;
  dwPos: DWORD;
begin
  //
  ColumnName := Column.FieldName;

  if IsBoundaryLine then
  begin
    //Column.FieldNameをつかうと境界線の右のFieldのときもある
    // イベントが発生したマウスカーソルの位置を取得
    dwPos := GetMessagePos;
    Pos := DBGrid1.ScreenToClient(Point(LoWORD(dwPos), HiWORD(dwPos)));
    // MouseToCell を使うために DBGrid を TDrawGrid にキャストします
    //少し左にずらす
    Pos.X := Pos.X -10;
    TDrawGrid(DBGrid1).MouseToCell(Pos.X, Pos.Y, ACol, ARow);
    //ShowMessage(Format('%d %d',[ACol,Arow]));
    DBGrid1.Columns[ACol-1].Width := ColumMatchWidth(DBGrid1.Columns[ACol-1].FieldName);
  end;
  IsBoundaryLine:=False;

end;

//最大長を求める
function TForm1.ColumMatchWidth(AFieldName: String): Integer;
var
  MaxWidth: Integer;
  AWidth: Integer;
begin
  with Table1 do
  begin
    try
      DisableControls;
      First;
      MaxWidth := 0;
      while not Eof do
      begin
        AWidth := Canvas.TextWidth(Trim(FieldByName(AFieldName).AsString));
        if MaxWidth < AWidth then
          MaxWidth := AWidth;
        Next;
      end;
      First;
    finally
      EnableControls;
    end;
  end;
  //少し短くなってしまうのでプラス
  Result := MaxWidth + 5;
end;

end.


のり0203  2012-06-14 00:24:40  No: 42470

ソースの必要のない部分の削除しました。
バグもありましたので、修正しました。
Mr.XRAY様のサブクラスを使わさせていただいていますが、
コピーして、作成しただけで、
内容は、よく理解していません。
間違っている箇所がありましたら、
お手数ですが、ご指摘をお願いいたします。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, DBTables, Grids, DBGrids,SubClassUnit,ExtCtrls,StdCtrls;

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    Table1: TTable;
    DataSource1: TDataSource;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure DBGrid1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure DBGrid1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure DBGrid1TitleClick(Column: TColumn);
  private
    { Private 宣言 }
    RowHeight: Integer;
    SubClass2: TSubClass;
    procedure SubClass2MessageAfter(Sender: TObject;      var message: TMessage);
    function ColumMatchWidth(AFieldName: String): Integer;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
type
  TDummyDBGrid = class(TCustomDBGrid);

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Tableの設定
  Table1.DatabaseName := 'DBDEMOS';
  Table1.TableName := 'country.db';
  Table1.Open;
  // 常に編集モード
  DBGrid1.Options := DBGrid1.Options + [dgAlwaysShowEditor];
  // サブクラスの設定 - MouseDownの取得だけ
  SubClass2:= TSubClass.Create(Self);
  SubClass2.TargetControl := DBGrid1;
  SubClass2.OnMessageAfter := SubClass2MessageAfter;
  // 行の高さ
  RowHeight := TDummyDBGrid(DBGrid1).DefaultRowHeight;

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Table1.Close;
  SubClass2.Free;
end;

var
  AX: Integer =0;
  IsBoundaryLine: Boolean = False;
  IsColumnMoving: Boolean = False;

procedure TForm1.DBGrid1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  // タイトル間のクリックは、ここでは取得できません。
  // タイトルのクリックは、取得できます。
  IsColumnMoving := True;
  IsBoundaryLine := False;
end;

procedure TForm1.DBGrid1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  IsColumnMoving := False;
end;

// こちらは単純にDBGrid1のMouseDownを取得しているだけです。
// カラム間のクリックは、DBGridのOnMouseDownでは取得できなかった。
procedure TForm1.SubClass2MessageAfter(Sender: TObject; var message: TMessage);
begin
  case Message.Msg of
    WM_LBUTTONDOWN:
      begin
        if (Message.LParamHi < RowHeight) and (not IsColumnMoving)  then
        begin
          IsBoundaryLine:=True;
        end;
      end;
  end;
end;

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var
  Pos : TPoint;
  ACOl,ARow: Integer;
  dwPos: DWORD;
begin
  if IsBoundaryLine then
  begin
    //Column.FieldNameをつかうと境界線の右のFieldのときもある
    // イベントが発生したマウスカーソルの位置を取得
    dwPos := GetMessagePos;
    Pos := DBGrid1.ScreenToClient(Point(LoWORD(dwPos), HiWORD(dwPos)));
    // MouseToCell を使うために DBGrid を TDrawGrid にキャストします
    //少し左にずらす
    Pos.X := Pos.X -10;
    TDrawGrid(DBGrid1).MouseToCell(Pos.X, Pos.Y, ACol, ARow);
    //ShowMessage(Format('%d %d',[ACol,Arow]));
    DBGrid1.Columns[ACol-1].Width := ColumMatchWidth(DBGrid1.Columns[ACol-1].FieldName);
  end;
  IsBoundaryLine:=False;

end;

//最大長を求める
function TForm1.ColumMatchWidth(AFieldName: String): Integer;
var
  MaxWidth: Integer;
  AWidth: Integer;
begin
  with Table1 do
  begin
    try
      DisableControls;
      First;
      MaxWidth := 0;
      while not Eof do
      begin
        AWidth := Canvas.TextWidth(Trim(FieldByName(AFieldName).AsString));
        if MaxWidth < AWidth then
          MaxWidth := AWidth;
        Next;
      end;
      First;
    finally
      EnableControls;
    end;
  end;
  //少し短くなってしまうのでプラス
  Result := MaxWidth + 5;
end;

end.


のり0203  2012-06-15 17:12:39  No: 42471

解決しました。
この方法で、いきたいと思います。
間違っているところがありましたら、ご指摘お願いいたします。
質問することがあるかもしれませんが、その時は、またよろしくお願いいたします。


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

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






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