I have a string grid where user can change colors of columns. I'm storing a color in a string it looks likethis : columnToColor:= '1;233,233,233' 1 is the column 233;233;233 is a rgb color; I change this string everytime i have to change colors. It never contains more than one column and one color
In my drawcellevent i'm doing this:
color := Explode(';',columnToColor); //this will return an array
if (length(color)-1 >= 0) then
begin
if TryStrToInt(color[0], val) then
begin
if aCol = StrToInt(color[0]) then
begin
cellText := grid.Cells[aCol,aRow];
grid.Canvas.Brush.Color := TColor(RGB(StrToInt(color[1]),StrToInt(color[2]),StrToInt(color[3])));
rec := grid.CellRect(aCol,aRow);
grid.Canvas.FillRect(rec);
grid.Canvas.TextOut(rec.Left,rec.top,cellText);
end;
end;
end;
I'm calling invalidateCol from another procedure using a hacked StringGrid class:
With TCustomStringGrid(grid) do
InvalidateCol(grid.col)
This works when i change only one column color. I can scroll freely trought the grid and it will still be there with the good column color. But when i change the color of another column the colors are shown when their are still visibile. Once i scroll horizontally and get back to the columns only the last colored column is colored and other are set to default color. The color only stays on the last colored column. So if i color 2 columns and i click on the first one, the cell's color is set to default. And i scroll horizontally the whole column 1 is set to default color. Only the second column keep its color what ever i do.
How can i fix this pls?
This is perhaps becoming a little more clear to me. The problem is that you want the grid control to paint each column in separate colors. Although your columnToColor string specifies the color for only a single column, you want each column to have, potentially, a different color. When you scroll the grid, and columns are re-painted, only the column specified in columnToColor has the desired color.
All this is happening because Windows controls need to be able to re-paint themselves completely at any time. Once you have painted a control, the control does not remember its state. If it becomes invalid (control dragged over, scrolled, etc.) then the control must be able to re-paint itself in its entirety.
Your code fails to do that. Since it only remembers the color for the most recently modified column, when it needs to paint other columns, they get the default color. Your approach cannot succeed since the control only keeps track of one single column color.
The solution is simple enough. You need to remember the color for each column. An obvious way to do so would be to hold the colors in an array:
FColumnColor: array of TColor;
or
FColumnColor: TArray<TColor>;
in a more modern Delphi. Or perhaps even TList<TColor>.
When you need to change a column's color do so by modifying FColumnColor[ColIndex]. Likewise, whenever you need to paint, read the color out of FColumnColor[ColIndex].
Related
I am using TeeChart (Build 2020.30.200525) in a Delphi XE3 VCL-Application.
In that application I am setting up a Gantt series and I would like to style an individual row label on the left axis to set it apart from the others.
Something like changing the color or font-style of the label or highlighting it by using a background.
How could I achieve this?
I have found the OnGetAxisLabel event which I ca use to change the text of the labels.
And I have also tried Axes.Left.Items, but that only has a single element even after I have added several Values to the Gantt-Series.
You need to force a chart repaint to populate the axis items. Ie:
uses VclTee.GanttCh;
procedure TForm1.FormCreate(Sender: TObject);
begin
Chart1.AddSeries(TGanttSeries).FillSampleValues;
Chart1.Draw; // Force a repaint to populate Axis Items
Chart1.Axes.Left.Items.Automatic:=False;
Chart1.Axes.Left.Items[2].Format.Font.Color:=clRed;
end;
I have two grids:
in one form and compare between two value I need to change the color of the column in the grid when the two values are not equal
TotalYear:=0 ;
while not (mTblDetail.eof) do
begin
TotalYear:=TotalMonth +mTblDetail.FieldByName('Target_').AsFloat;
mTblDetail.Next;
end;
TotalMonth:=0;
while not(DataSet.Eof) do
begin
TotalMonth:=TotalMonth+DataSet.FieldByName('Target_').AsFloat;
DataSet.Next;
end;
I need to compare the two values and change the color
if(TotalYear<>TotalMonth) then
I tried to use this :
DataSet.Columns[8].Color:= clRed
but is displays an error "Not Accepted". How Can change the color of a column of a Tcxgrid?
Coloring in cxGrids is best done via cxStyles. Drop a TcxStyleRepository on the form and add some styles. You can assign them to the View.Styles.* properties or via events like OnGetContentStyle. I'm sure the online help contains an overview with screenshots and examples.
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 got a TCheckListBox on a form. Its Columns property is set to 2, and if there are more items than can fit on-screen in two columns, it puts a horizontal scrollbar across the bottom of the control.
Thing is, the way this form it laid out, it would be much more convenient to scroll vertically. But I can't seem to figure out how to make the box do that. I thought setting Columns to 1 should work, but it doesn't.
Anyone know how to make a TCheckListBox scroll vertically instead of horizontally?
You need to set Columns to 0.
For all positive values the VCL sends a LB_SETCOLUMNWIDTH message to the underlying native list box control, with the width parameter set to the list box client width divided by the number of columns. Items that don't fit will start a new column with the same column width, so the horizontal scrollbar becomes visible.
If Columns is 0 then there is a single column that spans the entire client width of the list box, and items that don't fit will make the vertical scrollbar visible, and hide the horizontal scrollbar.
Edit:
There seems to be genuine interest what happens when a negative value is used for the Columns property.
The method TCustomListBox.CreateParams() sets the LBS_MULTICOLUMN list box style depending on the Columns property being different from 0. For negative values the style flag is set, but the VCL doesn't send the LB_SETCOLUMNWIDTH message, so the native control uses the default column width. It is documented to be:
15 times the average character width for the font used by the list box.
(Search for "The LBS_MULTICOLUMN style specifies" to find the relevant passage of text.)
I've got a TdxDBGrid that's displaying some information retrieved from a database query. One of the columns is a Memo column, (TdxDbGridMemoColumn,) which is necessary because the data in the field it's bound to comes out of the database as type TEXT, not CHAR or VARCHAR.
Problem is, the memo column likes to display whole words, and if it can't display a whole word, it doesn't display any part of it. The normal grid columns show everything they can up to the right border and cut off the display there, but the memo column doesn't, and that's bound to confuse end-users. Is there any way I can get the memo column to display partial words?
You could owner-draw the column. Then you can make the text look however you want. Call DrawText and use the dt_End_Ellipsis flag to draw an ellipsis on the end of long text, or else just let the long text be clipped to the drawing area.
in the onGetText event of the column, you can modify the displayed text to accommodate the available size:
// the TTextFormats flags are defined in Graphics, add it to your uses clause
procedure TMyForm.gridMyColGetText(Sender: TObject; ANode: TdxTreeListNode;
var AText: string);
var
R: TRect;
begin
// Calculate actual displayable text (with ellipsis) depending on cell size
R := (Sender as TdxDBGridColumn).TreeList.CellRect(ANode, (Sender as TdxDBGridColumn).ColIndex); // get the cell rectangle
Windows.InflateRect(R, -2, 0); // shrink a bit for grid lines
grid.Canvas.TextRect(R, AText, [tfModifyString, tfEndEllipsis]); // shorten the text ...
end;