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.
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.
The DBGrid decides whether to show a text edit box based on a lot of inputs:
- Whether the DBGrid itself is read-only.
- Whether the dataset is read-only
- Whether the column is read-only
- Whether the field is read-only
- 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.