I am working on Delphi 10.2 and SQL Server 2008.
I have to modify some value in TDBGrid
. when I modify the value using OnDrawColumnCell
Data is getting over lapped when I click on that column and the same is working fine in Delphi 7.
Example Code:
Create table and insert some data in SQL Server 2008.
CREATE TABLE [dbo].[Persons](
[P_ID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[LastName] [varchar](15) NOT NULL,
)
insert into Persons (LastName) values ('LastName')
Create New VCL Forms Application - Delphi
To display the Data on DBGrid I am using TADOCOnnection
, TADOQuery
, TDataSource
and TDBGrid
set TADOQuery.SQL
to "select LastName from Persons"
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grids, DBGrids, DB, ADODB, Vcl.StdCtrls;
type
TForm1 = class(TForm)
ADOConnection1: TADOConnection;
ADOQuery1: TADOQuery;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
procedure FormShow(Sender: TObject);
procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormShow(Sender: TObject);
begin
ADOQuery1.Active := False;
ADOQuery1.Active := True;
end;
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
Var
CellData : String;
begin
CellData := Column.Field.DisplayText;
if Column.Field.FieldName = 'LastName' then
begin
CellData := 'change';
DBGrid1.Canvas.TextRect(Rect, Rect.Left, Rect.Top, CellData);
end
else
DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, state);
end;
end.
This is a general drawing issue and not related to SQL Server or the TDBGrid
in particular. The same would apply to drawing to a VCL TCanvas
or something similar.
You are calling Canvas.TextRect(..)
, but nothing more. The text will get drawn, but nothing more. You will have to clear the area first: Imagine painting a white background before drawing black text.
The TDBGrid
offers a convenient method DrawCellBackground(..). Since this method is not public, this screams for implementing it by leveraging helper classes.
The following code uses DrawCellHighlight(..)
for clearing the cell paint area when the cell is selected and DrawCellBackground(..)
otherwise.
type
TDBGridHelper = class helper for TDBGrid
public const textPaddingPx = 2; // Siehe TDBGrid::DefaultDrawColumnCell
public procedure writeText(
const inRect: TRect;
const text: String;
const State: TGridDrawState;
const columnIndex: Integer
);
end;
procedure TDBGridHelper.writeText(
const inRect: TRect;
const text: String;
const State: TGridDrawState;
const columnIndex: Integer
);
const
cellGridPx = 1;
var
backgroungRect: TRect;
begin
backgroungRect := inRect;
backgroungRect.Inflate(-cellGridPx, -cellGridPx);
if (Vcl.Grids.gdSelected in State) then
DrawCellHighlight(inRect, State, columnIndex, 0)
else
DrawCellBackground(backgroungRect, self.Color, State, Columnindex, 0);
Canvas.TextRect(
inRect,
inRect.Left + textPaddingPx,
inRect.Top + textPaddingPx,
text
);
end;
Leveraging the TDBGrid.OnDrawColumnCell
event was absolutely correct, you can now simplify it to something like
procedure TYourFrame.dbGridDrawColumnCell(
Sender: TObject;
const Rect: TRect;
DataCol: Integer;
Column: TColumn;
State: TGridDrawState
);
var
columnText: String;
begin
columnText := '---';
if Assigned(Column.Field) then begin
if (Column.FieldName = 'yourField') then
columnText := getDeviationColumnText(Column.Field.AsSingle)
else
// This is the default text
columnText := Column.Field.DisplayText;
end;
(Sender as TDBGrid).writeText(Rect, columnText, State, Column.Index);
end;