Question

I'm trying to replace True/False with Yes/No in a DBGrid. The code below almost works:

procedure TDatamodule1.DBGridDrawColumnCell(Sender: TObject;
  const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);

  var
    sText : String;

begin
  if (UpperCase(Column.Field.FieldName) = UpperCase('Approved')) or
     (UpperCase(Column.Field.FieldName) = UpperCase('Obsolete')) then
    begin
      if Column.Field.Value = True then
        sText := 'Yes'
      Else
        If Column.Field.Value = False Then
          sText := 'No'
        Else
          sText := '';
      (Sender as TDBGrid).Canvas.FillRect(Rect);
      (Sender as TDBGrid).Canvas.TextRect(Rect, Rect.Left+3, Rect.Top+2, sText);
    end;
end;

This appeared to work until I started using the keyboard cursor keys to move around the grid. The cell that has the focus always has both True and Yes or False and No drawn on top of each other. How do I prevent the default True/False label from being drawn on the cell that has focus? All other cells of the grid are perfect.

Edit: I failed to mention that the grid is set to Readonly and I've noticed the problem is with both selected and focused. Thanks in advance.

Was it helpful?

Solution 4

I resolved my issue with a lot of trial and error. First, in the DBGrid components I set dgEditing to false as it was unnecessary (my grid is readonly). This prevents the user from getting the cell into the focused mode. Second, I set DefaultDrawing to False. I updated my DBGridDrawColumnCell procedure as follows:

procedure TDatamodule1.DBGridDrawColumnCell(Sender: TObject;
  const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);

  var
    sText : String;

begin
  if gdselected in state then { set proper colors if cell is selected }
    Begin
      (Sender as TDBGrid).Canvas.Font.Color := 
        TStyleManager.ActiveStyle.GetSystemColor(clwindowtext);
      (Sender as TDBGrid).Canvas.Brush.Color := 
        TStyleManager.ActiveStyle.GetSystemColor(clhighlight);
    End;

  if (UpperCase(Column.Field.FieldName) = 'APPROVED') or
     (UpperCase(Column.Field.FieldName) = 'OBSOLETE')) then
    begin
      if Column.Field.Value = True then
        sText := 'Yes'
      Else
        If Column.Field.Value = False Then
          sText := 'No'
        Else
          sText := '';
      (Sender as TDBGrid).Canvas.FillRect(Rect);
      (Sender as TDBGrid).Canvas.TextRect(Rect, Rect.Left+3, Rect.Top+2, sText);
    end
  Else
    Begin { I added this to draw all other columns as defaultdrawing is off }
      (Sender as TDBGrid).defaultdrawcolumncell(Rect, DataCol, Column, State);
    End;
end;

OTHER TIPS

A simple solution would be to set your Boolean field DisplayValues:

MyField.DisplayValues := 'Yes;No';

One way to achieve this is to set an OnGetText event handler for these fields. If you have static fields you can set those during design time. With dynamic fields you can do so in the FormCreate event.

procedure TMyForm.MyFieldGetText(Sender: TField; var Text: string; DisplayText: Boolean);
begin
  if Sender.AsBoolean then
    Text := 'Yes'
  else
    Text := 'No';
end;

I would say that you're working at the wrong level of abstraction. Use two calculated columns (AFlag and OFlag in the example below) and define an OnCalcFields event for your clientdataset. The below code is attached to a dataset called 'qCpap'.

procedure TView.qCpapCalcFields(DataSet: TDataSet);
begin
 if qCpapApproved.AsBoolean 
  then qCpapAFlag.AsString:= 'Yes'
  else qCpapAFlag.AsString:= 'No';

 if qCpapObsolete.AsBoolean 
  then qCpapOFlag.AsString:= 'Yes'
  else qCpapOFlag.AsString:= 'No';
end;

Incidentally, there's no point in using the 'uppercase' function on a string constant: you may as well write the string in uppercase yourself.

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