Extending DBGrid with some row colors - delphi

I want to extend DbGrid functionality to add colors on odd and even rows. So i wrote this
procedure TGridx.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
row : Integer;
begin
inherited;
row := Self.DataSource.DataSet.RecNo;
if (row mod 2 = 0) then
Self.Canvas.Brush.Color := FColor1 //some color
else
Self.Canvas.Brush.Color := FColor2; //some color
end;
What i am doing wrong ?

The event you want is called DBGridDrawColumnCell, and you need to decide whether to turn the DefaultDrawing property on or off, and the way you handle DBGridDrawColumnCell changes accordingly. For your case, you just set the colors, but leave DefaultDrawing true, and don't do any other canvas.Text or GDI drawing.
A recent question I asked here showed that in later Delphi versions (2010,Xe,Xe2) you ALSO sometimes need to call Canvas.Refresh for both TDBGRID and TListView, when changing canvas properties in ownerdraw events but that doesn't apply to delphi 7.

you should try also 3d party solution which are free, and extends already a lot the DBGrid, like the ones provided by the Jedi project

Opc0de, may be you should override not the "DrawCell" method but "DrawCellBackground"?

Try drawing the cell as well after the brush color is defined:
Self.Canvas.FillRect(ARect);

Related

Custom drawing of TCustomListbox items

I'm rewriting a VCL component showing a customized TCustomListbox to Firemonkey in Delphi 10.2. The customization used an overridden DrawItem, basically adding some indentation and setting the text color depending on the item text and index.
DrawItem made it rather easy, but there seem to be nothing like that in FMX. I can override PaintChildren and draw every item myself, but then it looks differently and I have to deal with scrolling and everything myself. I'm just starting with FMX and don't have the sources yet.
Is there a DrawItem replacement in FMX? I may have missed it.
If not, how do it get the needed information? Basically, the rectangle to draw in and ideally the style used.
Problems
The solution by Hans works, but has some major problems:
Color
Setting the color doesn't work, the text is always black. I tried various possibilities including this one:
PROCEDURE TMyItem.Paint;
BEGIN
TextSettings.FontColor := TAlphaColorRec.Red;
INHERITED;
END;
Speed
Opening a box with 180 Items takes maybe two seconds. We need that many items and their count is actually the reason why we need a customized box (we provide filtering using the TEdit part of our component). A version using strings without TMyItem was faster (though probably slower than the VCL version), but using these items seems to slow it down even more (it's slower than filling an HTML list styled similarly).
Or something else? Having no sources and practically no documentation I can't tell.
I tried to cache the items for reuse, but this didn't help.
It looks like using custom items is actually faster than using strings, (timing in milliseconds):
nItems String TMyItem
200 672 12
2000 5604 267
20000 97322 18700
The speed problem seems to accumulate when the content changes multiple times. I was using FListBox.Items.Clear;, then I tried
n := FListBox.Items.Count;
FOR i := 0 TO n-1 DO FListBox.ListItems[n-1-i].Free;
and finally FListBox.Clear;, which makes most sense (and which I found last). Still, in the end it seems to need 2 ms per item.
Here is an example of how it can be done. The key is to set the Parent of the (custom) ListBoxItem to the ListBox. This will append it to its list of items. I set the parent in the constructor, so I don't have to do it (and remember it) each time I add something to a listbox.
type
tMyListBoxItem = class(TListBoxItem)
strict private
fTextLabel: TLabel;
public
constructor Create(aOwner: TComponent);
property TextLabel: TLabel read fTextLabel;
end;
implementation
constructor tMyListBoxItem.Create(aOwner: TComponent);
begin
inherited;
fTextLabel := TLabel.Create(self);
fTextLabel.Parent := self;
Assert(aOwner is TFMXObject, 'tMyListBoxItem.Create');
Parent := TFMXObject(aOwner);
end;
procedure tMyForm.FillListBox(aListBox: TListBox; aStringList: TStringList);
var
lItem: tMyListBoxItem;
i: integer;
begin
aListBox.BeginUpdate; //to avoid repainting for every item added
aListBox.Clear;
for i := 0 to aStringList.Count-1 do
begin
lItem := tMyListBoxItem.Create(aListBox);
lItem.TextLabel.Text := aStringList[i];
lItem.Margins.Left := 20;
end;
aListBox.EndUpdate;
end;
I use custom ListBoxItems in many places now because you can have ComboBoxes, EditBoxes, and all other controls in a ListboxItem. This opens for a very dynamic (list based) screen layout that easily adapts to all platforms and screen sizes.

Delphi TStringGrid Background color missing on left side [duplicate]

FillRect doesn't paint the complete TStringGrid cell in Delphi XE2. There is a gap of 3 pixels on the left side in the default color (with BiDiMode set to bdLeftToRight). This problem doesn't exist in Delphi 6 which I used before.
procedure TShapeline.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
begin
Stringgrid1.Canvas.Brush.Color:=$00FF80FF;
StringGrid1.Canvas.FillRect(Rect);
end;
I tried to change all properties (including the DrawingStyle) and different brush styles, the painted rectangle doesn't fill the complete cell.
This is expected behaviour in XE2 when DefaultDrawing = true and themes are enabled (I'm not going to argue about good or bad here - as you might have noticed, the behaviour is different for RigthToLeft mode...).
A workaround is to check for this condition and decrement Rect.Left by 4 pixel before calling FillRect.
You can use the StringGrid1.CellRect(ACol, ARow) that returns the actual TRect of the cell instead of using the parameter Rect.
Turn off the first 4 options in TStringGrid:
goFixedVertLine
goFixedHorizLine
goVertLine
goHorizLine
Then it won't paint the grid lines, and your grid cells will paint right to the edges. Just tried it with XE.
Since you're drawing the grid cell yourself then just turn off the grid property DefaultDrawing, set it to false.

Add WordWrap functionality to ButtonGroup buttons in Delphi XE3

Currently TButtonGroup doesn't have a WordWrap property. I was looking a way to have that functionality but my search for examples was so far not yielding any results.
My question is how can I add a wordwrap function for the caption of the buttons in TButtonGroup? Can you give me an example or guide me in the right track?
Your answer is much appreciated!
BTW I use delphi XE3
A simple wordwrap will already happen, which can be seen if you change the caption at runtime of by editing the DFM like this.
Items = <
item
Caption = 'Word'#13'Wrap'#13'3 Lines'
end
...
But the default painting will not look to good with WordWrap.
You could implement OnDrawButton, but that would need to write a lot of code.
The fastest way will be to set gboShowCaption in ButtonOptions to false and implementing OnAfterDrawButton like this:
procedure TForm1.ButtonGroup1AfterDrawButton(Sender: TObject; Index: Integer; Canvas: TCanvas; Rect: TRect; State: TButtonDrawState);
var
s:String;
begin
InFlateRect(Rect,-4,-4);
s := TButtonGroup(Sender).Items[Index].Caption;
Canvas.TextRect(Rect,s,[tfWordBreak,tfCenter]);
end;

FillRect doesn't paint the complete TStringGrid cell in Delphi XE2

FillRect doesn't paint the complete TStringGrid cell in Delphi XE2. There is a gap of 3 pixels on the left side in the default color (with BiDiMode set to bdLeftToRight). This problem doesn't exist in Delphi 6 which I used before.
procedure TShapeline.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
begin
Stringgrid1.Canvas.Brush.Color:=$00FF80FF;
StringGrid1.Canvas.FillRect(Rect);
end;
I tried to change all properties (including the DrawingStyle) and different brush styles, the painted rectangle doesn't fill the complete cell.
This is expected behaviour in XE2 when DefaultDrawing = true and themes are enabled (I'm not going to argue about good or bad here - as you might have noticed, the behaviour is different for RigthToLeft mode...).
A workaround is to check for this condition and decrement Rect.Left by 4 pixel before calling FillRect.
You can use the StringGrid1.CellRect(ACol, ARow) that returns the actual TRect of the cell instead of using the parameter Rect.
Turn off the first 4 options in TStringGrid:
goFixedVertLine
goFixedHorizLine
goVertLine
goHorizLine
Then it won't paint the grid lines, and your grid cells will paint right to the edges. Just tried it with XE.
Since you're drawing the grid cell yourself then just turn off the grid property DefaultDrawing, set it to false.

Prevent series from using clWhite with Delphi TChart

I have a report that uses a TChart that I am maintaining. One of the TLineSeries that gets added automatically gets assigned the color clWhite, which is too close to the background (clBtnFace).
If I change it, then the next series that gets added takes clWhite. So short of going back and changing it after all the other series are created, is there some way to tell the TChart that I don't want any of my series to be clWhite?
When a series is added to the TChart the TChart assigns it a color. I want it to not assign clWhite.
OK not one to give up easily, I did some more searching. There is a unit variable called ColorPalette of type TColorArray in the TeeProcs unit. If I find and replace white with a different color that fixes it. There may be an instance copy of it. I'll keep looking since that would be preferred.
To revert the ColorPalette back just call the unit method SetDefaultColorPalette in the same unit.
SetDefaultColorPalette; // Make sure we start with the default
ColorPalette[4] := $007FFF; // Change White to Orange
try
// add series to the chart
finally
SetDefaultColorPalette; // Set it back to Default
end;
BTW, I can't accept as answer because I asked the question too, but I tested it and it works.
Near as I can tell from the TeeCharts module; no you can't specify a color that it should not be as it ships.
You can programatically walk through all the TLineSeries entries making sure at run-time that they don't use clWhite.
Say you have an array of acceptable colors clArray, you can use the following code to set the colors of each of the tLineSeries entries at run time.
procedure TForm1.setColors(aChart: TChart; aColorArray: array of TColor);
var
chi : Integer;
coi : Integer;
begin
coi := low(aColorArray);
for chi := 0 to aChart.SeriesList.Count - 1 do begin
aChart.SeriesList[chi].Color := aColorArray[coi];
inc(coi);
if coi > high(aColorArray) then
coi := low(aColorArray);
end;
end;
procedure TForm1.FormShow(Sender: TObject);
var
ca : array of TColor;
begin
setLength(ca, 3);
ca[0] := clRed;
ca[1] := clBlue;
ca[2] := clGreen;
setColors(Chart1, ca);
end;
You can use the series methods ClearPalette then AddPalette to create your custom palette.

Resources