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.
Related
The OnDrawCell event gives me a "Rect" record so that I know where the real pixel coordinates are:
OnDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
On the other hand, the OnSelectCell only gives me the row/col coordinates.
OnSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);
How do I translate the row/col to pixel coordinates?
I need those because I need to create a ComboBox at runtime to cover the whole selected cell, but only when the cell is selected. I know how to do everything, but I do not know how to get the coordinates (right now, I am just creating the combo at 0,0 of the parent tStringGrid).
I am using Delphi7, but I think it is a general question and not related to the Delphi version.
PS: I am aware that there are plenty of commercial and freeware components that implement a combobox inside a cell, but I cannot and/or do not want to use them.
Thank you
You can determine cell screen coordinates using CellRect method
P.S. Have you ever tried to integrate controls into StringGrid?
When you meet problems with controls (having grid as Parent) behavior, look at this topic
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.
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);
I have ListView (vsReport) and StringGrid and what I want is if I click on some element in ListView, particular cells in StringGrid have to change colors. How do I do it?
Path is filled with 1 (move up) and 0(move right), it starts in left bottom and ends in right top corner, and I have to color these cells.
Thanks for the answers, I handled with my problem, but there's another little issue, how can I leave text in cells visible? FillRect fills the entire cell.
procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
var aRect: TRect;
a,x,y:integer;
path:string;
begin
path:=ListView1.Items[Item.Index].Caption;
x:=0;
y:=StringGrid1.RowCount;
for a := 0 to length(path) do
begin
if path[a]='1' then y:=y-1 else x:=x+1;
aRect := StringGrid1.CellRect(x-1,y-1);
StringGrid1.Canvas.Brush.Color := clBlue;
StringGrid1.Canvas.FillRect(aRect);
end;
end;
Realize that a cell's color change should be permanent, so that when the StringGrid is painted again, e.g. when the StringGrid was obfuscated by a dialog, also the special colors should be painted again.
Thus you need to store the desired colors somewhere. Say you want to use an array for that, then make a choice between:
Storing the special colors along with the grid coordinates in a one-dimensional array. This is good for memory usage, but you would need to search this entire array for the specific coordinate which the StringGrid's OnDrawCell handler (see step 3) provides,
Storing only the special colors in a two-dimensional array. This is good for speed when drawing, but you need to synchronize the array's column and row bounds to that of the StringGrid,
Or, when you do not need the Objects property of the StringGrid for any purpose, you could employ this property for color storage by typecasting the color to and from a TObject. Shout if you need help with that.
Paint the colored cells in a StringGrid's OnDrawCell event handler (search here on Stack Overflow for [Delphi] StringGrid OnDrawCell when in need of assistance with that).
The ListView's OnSelectItem event exposes the Item which is clicked or otherwise selected.
Retrieve necessery information from that item or its sub-items to determine which cell is to be changed in what color.
Add that information to the chosen storage solution of step 2.
Realize that when all painting now is done "automatically", just a call to StringGrid.Repaint should be enough.
I've narrowed a problem I have drawing on TImage.Canvas in Delphi 2009 down to the following reproducible case:
Given: a form, a TImage, TLabel and TButton on it. The TImage is anchored to all four edges so that resizing the form will resize the TImage. What I want to be able to do is draw on the maximal area of Image1 available to me after resizing. So in my test case I have the following code in my the Button's OnClick handler:
procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption:= IntToStr (Image1.Width)+' x '+IntToStr(Image1.Height);
Image1.Canvas.Pen.Color:= 0;
Image1.Canvas.Rectangle(0,0,Image1.Width, Image1.Height);
end;
You'll see that if the form is resized, Image1.Width and .Height change as expected, however the rectangle that is drawn if the resized form is larger than the original one, will be incomplete, only drawing on the same area that was there previously.
How do I get it do use the entire resized area?
For what it's worth, in my original problem I had played with Image1.Stretch, which allows me to use more of the area upon resizing but will result in my drawings being distorted (not desired). If I also use Image1.Proportional, then it's better but I still can't use the full area available. Image1.AutoSize doesn't seem to be doing anything useful to me either.
Any help appreciated.
Add an OnResize-event to your form:
procedure TForm1.FormResize(Sender: TObject);
begin
Image1.Picture.Bitmap.Width := Image1.Width;
Image1.Picture.Bitmap.Height := Image1.Height;
end;
Also, if you are using the component to draw on, rather than displaying images from file etc, consider using the TPaintBox rather than TImage.
Maybe you have to also adjust Image1.Picture.Width/Height or Image1.Picture.Bitmap.Width/Height.