Question

I want only some cells editable in a TDBGrid. In a given column, some but not all cells will be editable, so I can't just set Column.ReadOnly for the entire column and then leave it that way.

What events are best to use so I can get control when a cell is entered. I might use TDbGrid.ColumnEnter to catch horizontal movement and TDataSet.AfterScroll for vertical movement in the grid. Or I could perhaps use TDBGrid.DrawColumnCell (which I'm already using to change the color of some cells...)

And I'm also having trouble figuring out the best way change the read-only status of a cell. I could set the underlying TTable.Field.ReadOnly, or TDbGrid.Columns[].ReadOnly.

I could experiment with all of the above, but then I'm depending on my testing to determine how the grid is implemented, and might overlook some situation. I'd prefer to know if the VCL provides a way to manage this need, if there are caveats, etc.

Related: ReadOnly TDBGrid/TwwDBGrid Cell in Delphi?, but doesn't handle scrolling via the keyboard.

Was it helpful?

Solution

You can override the CanEditModify function and add your wished condition. This can be done by creating a new compoent with adding a new Event or just by an interposerclass.

unit Unit6;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, ADODB, Grids, DBGrids;

type
  TDBGrid=Class(DBGrids.TDBgrid)
    function CanEditModify: Boolean; override;
    Property Col; // make property col visible
  End;

  TForm6 = class(TForm)
    DBGrid1: TDBGrid;
    ADOConnection1: TADOConnection;
    ADODataSet1: TADODataSet;
    DataSource1: TDataSource;
    ADODataSet1Componame: TStringField;
    ADODataSet1TrackTitle: TStringField;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form6: TForm6;

implementation

{$R *.dfm}

{ TDBGrid }

function TDBGrid.CanEditModify: Boolean;
var
 f:TField;
 c:Integer;
begin
  Result := inherited CanEditModify;
  c := Col;
  if dgIndicator in Options then dec(c); 
  F := Columns[c].Field;
  if Assigned(F) then
    begin // here just an example condition
      if (f.FieldName='TrackTitle') then
        if Pos('aa',F.AsString)>0 then Result := False;
      // you also can access the dataset via
      // if f.DataSet.FieldByName('xy').SomeCondition then ....    
    end;
end;

end.

OTHER TIPS

The DBGrid decides whether to show a text edit box based on a lot of inputs:

  1. Whether the DBGrid itself is read-only.
  2. Whether the dataset is read-only
  3. Whether the column is read-only
  4. Whether the field is read-only
  5. Whether the dataset can be put into edit mode

If you want to make some cells in a DBGrid column editable, and other cells in the same column not editable, you're going to have to do that yourself. The DBGrid looks to the dataset for most of its cues, with grid-wide and columnar overrides.

I don't recall if the dataset field CanModify can be configured to return different true or false based on individual row data. If so, this is probably your best option. The DBGrid will honor whatever field CanModify returns.

If CanModify isn't per-row contextual, you can put your logic to decide which cells should be editable in CanEditModify. Create a new grid class inheriting from TDBGrid (or TCustomDBGrid) and override the CanEditModify virtual method. You should probably do your custom logic first, then call the inherited method if your logic doesn't apply. You may need to override a few other methods to fine tune appearances, such as CanEditShow.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top