2

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.

enter image description here

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.
GuidoG
  • 11,359
  • 6
  • 44
  • 79
DelphiLearner
  • 489
  • 6
  • 25
  • For Delphi 7, you probably did not include a manifest for theming and the application was rendered with that ancient Windows 2000 look. Long story short, you just draw text, and that's what happens. It's not enough. You have to clear the background before (by DrawCellHighlight(..) or DrawCellBackground(..)). If you need a detailed answer on this, please let me know. – Günther the Beautiful Apr 13 '18 at 08:00
  • @GünthertheBeautiful: Can you please give me detailed answer. – DelphiLearner Apr 13 '18 at 08:06
  • This seems like a lot of work to change text. Why not just create a calculated field, do your your testing in OnCalcs, then use the calculated field in the grid? Or am I missing something... – John Easley Apr 13 '18 at 14:39
  • @JohnEasley: i have to add some dropdowns also to dbgrid.... so i need to handle OnDrawColumnCell. if there are no dropdowns to be added to dbgrid i will go with CalcFeild.Thank you. – DelphiLearner Apr 17 '18 at 06:27

2 Answers2

2

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.

Clear the area before drawing text

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.

Implementation example

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;
0

If going through 30 forms is to tedious, you can turn off "Runtime themes" to get back that fancy Windows 2000 look and the drawing algorithms that came with it.

  1. Choose Project > Options > Application.
  2. Clear the Enable Runtime Themes check box.

Source: http://docwiki.embarcadero.com/RADStudio/en/Disabling_Themes_in_the_IDE_and_in_Your_Application

  • not able to clear the Enable Runtime Themes check box. i am clearing and building the project and it is setting back to previous value. – DelphiLearner Apr 13 '18 at 11:33