CRDBGrid problem with StateChange event in UniDataSource

Discussion of open issues, suggestions and bugs regarding UniDAC (Universal Data Access Components) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
Moehre
Posts: 42
Joined: Fri 11 Nov 2005 11:37

CRDBGrid problem with StateChange event in UniDataSource

Post by Moehre » Sun 20 Dec 2015 11:24

Hi, I want to use some special formatting features in the CRDBGrid, so I use the StateChange event
in the TUniDataSource to do so:

procedure TForm7.UniDataSource1StateChange(Sender: TObject);
var
i,p,tw,nk: integer;
ft,cur: string;
begin
if Assigned(UniDataSource1.DataSet) then
begin
if UniDataSource1.DataSet.State = dsBrowse then
begin
With TCustomUniDataSet(UniDataSource1.DataSet) do
begin
for i := 0 to FieldCount-1 do
begin
Fields.Alignment := taLeftJustify;

FType := GetFType(Fields); // a function I wrote to get a "reduced" field type info
if FType = IsNumeric then
Fields.Alignment := taRightJustify;
if (FType = IsDate) or (FType = IsBool) then
Fields.Alignment := taCenter;
// This works OK!

ft := Fields.DisplayLabel;
p := POS('[C',ft);
if p > 0 then
begin
// Special format option for currency fields, using "[Cx]" (x = decimals) is in the display lable
Fields.DisplayLabel := Copy(ft,1,p-1);
Fields.Alignment := taRightJustify;
ft := Copy(ft,p+2,Length(ft)-p-1);
try
nk := StrToInt(Copy(ft,1,1));
except
nk := 0;
end;
ft := Copy(ft,2,Length(ft)-1);
cur := '';
if ft <> ']' then
begin
p := POS(']',ft);
cur := Trim(Copy(ft,1,p-1));
end;

ft := '###,###,##0';
if nk > 0 then
begin
ft := ft + '.';
for p := 1 to nk do
begin
ft := ft + '0';
end;
end;
if cur <> '' then
ft := ft + ' ' + cur;
TNumericField(Fields).DisplayFormat := ft;
ft := '';
// Here is the problem: after changing DisplayFormat or DisplayWidth
// in CRDBGrid the selected row is not correct!
end;

p := POS('[N',ft);
if p > 0 then
begin
Fields.DisplayLabel := Copy(ft,1,p-1);
Fields.Alignment := taRightJustify;
ft := Copy(ft,p+2,Length(ft)-p-1);
try
nk := StrToInt(Copy(ft,1,1));
except
nk := 0;
end;

ft := '########0';
if nk > 0 then
begin
ft := ft + '.';
for p := 1 to nk do
begin
ft := ft + '0';
end;
end;
TNumericField(Fields[i]).DisplayFormat := ft;
ft := '';
end;

p := POS('[D',ft);
if p > 0 then
begin
Fields[i].DisplayLabel := Copy(ft,1,p-1);
Fields[i].Alignment := taCenter;
ft := Copy(ft,p+2,Length(ft)-p-1);
try
nk := StrToInt(Copy(ft,1,1));
except
nk := 8;
end;
ft := 'dd/mm/yyyy';
case nk of
6: ft := 'mm/yyyy';
end;
TDateTimeField(Fields[i]).DisplayFormat := ft;
ft := '';
end;

// Die Zellenbreite muss im Grid gesetzt werden!
// Zur "Vorbereitung" die Zellen aber erstmal zu schmal machen!
// (Displaywidth = Anzahl Zeichen (!) nicht die Breite in Pixel)
Fields[i].DisplayWidth := 1;
end;
end;
end;
end;

in the TCRDBGrid.DrawColumnCell event are some more formatting features:

procedure TForm7.CRDBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
tw: integer;
begin
with (Sender as TCRDBGrid) do
begin

Canvas.Font.Color := clBlack;
Canvas.Font.Style := [];

FType := GetFType(Column.Field);

if FType = IsString then
begin
Canvas.Font.Name := 'Arial Unicode MS';
end
else
begin
Canvas.Font.Name := 'Courier New';
if FType = IsNumeric then
begin
if Column.Field.AsFloat < 0 then
begin
Canvas.Font.Color := clRed;
Canvas.Font.Style := [fsBold];
end;
end;
end;

if (gdSelected in State) then // Here is the main problem: f.e. the 3d row is shown in yellow (selected), but the first row has the selected sign (>)
Canvas.Brush.Color := $00E1FFFF
else
if Odd(Rect.Top div (Rect.Bottom - Rect.Top)) then
Canvas.Brush.Color := clWhite
else
Canvas.Brush.Color := $00F0F7F0;

if FType <> IsBlob then
begin
tw := Canvas.TextWidth(Column.Field.DisplayText) + 8;
if tw > Column.Width then
Column.Width := tw;

DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;
end;
end;

Everything works fine, but using differrent UniQuery / VirtualTable data the selected row in the CRDBGrid (shown in yellow with the "if (gdSelected in State)") differs from the "rearly" selected on (it should always be the first row).

The following picture shows the problem:

http://www.directupload.net/file/d/4208 ... st_png.htm

Here the 3d row is yellow, so on the 3d row the "gdSelected" state was set in the OnDrawColumnCell event, but the 1st row is selected, not the 3d!

Do I made any mistake in my approach?
Thx in advance
Detlev

EDIT: Just a hint: the row with the gdSelected state differs due to the query's sql statement! As you can see in the assigned picture I use 3 Buttons with differrent queries (the 3d button uses a virtual table). Maybe it has something to do with the DisplayLabel change.

And just another problem: is it possible to show the calendar week for TDate or TDateTime fields in a CRDBGrid using standard format options?

AlexP
Devart Team
Posts: 5530
Joined: Tue 10 Aug 2010 11:35

Re: CRDBGrid problem with StateChange event in UniDataSource

Post by AlexP » Tue 22 Dec 2015 14:10

Hello,

We couldn't reproduce the issue. When changing DisplayFormat (not depending on the UniQuery, VirtualTable data access components), the selected row is highlighted with the correct color. Check this behavior on the latest UniDAC version 6.2.9 and let us know the result.

P.S. If the issue repeats on the latest version, please send us a sample (including all the scripts) reproducing the described case to support*devart*com

Post Reply