How can I select multiple individual cells of a string grid? - delphi

I am looking for a string grid that allows me select multiple cells anywhere in the grid without them adjoining each other, e.g pressing CTRL and clicking on various cells over the grid. Or if anyone knows how to do this with the standard Delphi TStringGrid.
Any pointer would be gratefully received.

Although there are a lot of better capable people here, since you haven't gotten any answers, I thought I'd give it a try.
I'm not aware of a way to have the component do this for you. However, when you Control-click a cell, the event OnSelectedCell is called. (I just tested that.) You could put code in an event handler that adds the cell's row and column to a list that you keep of the rows and columns that are selected. Then, in the OnDrawCell event, highlight the cell:
procedure TForm1.StringGrid1DrawCell( Sender: TObject;
ACol: Integer;
ARow: Integer;
Rect: TRect;
State: TGridDrawState);
begin
if CellSelected( ARow, ACol) then // you write CellSelected() to refer to the list you're keeping
begin
StringGrid1.Canvas.Brush.Color := clYellow;
StringGrid1.Canvas.FillRect(Rect);
StringGrid1.Canvas.TextOut(Rect.Left,Rect.Top,StringGrid1.Cells[ACol,ARow]);
end;
end;

Related

TStringGrid: Is it possible to find out the 'State' of a cell?

I want to implement a FillCell procedure for TStringGrid. I want to fill a certain cell with a color but only when the cell (row) is not selected.
procedure TMyStrGrid.FillCell(Rect: TRect; aColor: TColor);
begin
//if NOT (gdSelected in State) then <---- how do I obtain the 'State' here?
begin
Canvas.Brush.Color:= aColor;
Canvas.FillRect(Rect);
end;
end;
This is just an exercise :) I am trying to figure out VCL.Grids.pas which is quite complex.
According to the comments, you are calling this function from an OnDrawCell handler. That OnDrawCell handler is passed a TGridDrawState argument which specifies whether or not the cell is selected. The event handler is of this form:
TDrawCellEvent = procedure (Sender: TObject; ACol, ARow: Longint;
Rect: TRect; State: TGridDrawState) of object;
You are asking whether it is possible to ignore the TGridDrawState and somehow recover the information later. In principle it is possible:
You have available the row and column. That identifies the cell and you can check whether or not the cell is in the current selection.
If you want to ignore the row and column also, then you could inspect the TRect that is supplied. Map that back to the row and column and again check that against the current selection.
Frankly what you are trying to do is silly in my view. You have been supplied with the draw state for a good reason. It has the information you need. Use it.

Mouse over stringgrid when dragging?

Parts of my stringgrid are eligible drop targets, and some are not (first row is column headings, first column is a sort of index and subsequent columns may be dropped to). I have that coded and working.
Now I am thinking that it might be nice to gve a visual indiation to the user as he drags the mouse over a cell which is a potential drop target. I woudl like to highlight the first cell in the row and column of the cell over which he is currently hovering (or possibly the entire row and column, forming a sort of crosshair; I am as yet undecided). I reckon I can code that in OnDrawCell.
I had thought to use OnMouseMove and cehck if Dragging then, but ...
My problem is that when I am dragging the OnMouseMove event never gets called.
Is there any other way to know when the cursor is hovering over a strigngrid during a drag operation?
The OnDragOver event is specifically designed for doing this; it's called automatically, and provides the X and Y coordinates where the mouse pointer is located. There's a code sample available at that link location that demonstrates using it as well - it's for a TListBox, but the principle is the same.
procedure TForm1.FormCreate(Sender: TObject);
begin
ListBox1.Items.Add('Not');
ListBox1.Items.Add('In');
ListBox1.Items.Add('Alphabetical');
ListBox1.Items.Add('Order');
end;
// This OnDragOver event handler allows the list box to
// accept a dropped label.
procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
Accept := Source is TLabel;
end;

How do I use DoMouseWheel to scroll a line at a time?

I've written a grid control and would like to add support for the mouse wheel to it. I thought it would be as simple as overriding the DoMouseWheel virtual method, but there is a bit of a problem with it.
You can set the number of lines to scroll at a time in Control Panel and the default there is three. And this makes perfect sense when scrolling through a document or web page, but on a grid, I think the expectation is rather to scroll a line at a time. But it seems that Delphi's wheel support will call DoMouseWheel three times for every notch that I scroll, meaning that I can only scroll to each third line in the grid (or whatever that global setting is).
How do I go about scrolling a single line at a time for every turn of the mouse wheel?
Update: The short answer here is to simply set Result to True after scrolling - then it doesn't scroll three times, but only once.
Just copy the code from the TCustomGrid class, which overrides both DoMouseWheelDown() and DoMouseWheelUp() to scroll exactly one line at a time.
In general, it is not a very good idea to fight against the system defaults and/or the user preferences. In this case means that you should respect whatever the system or the user has decided to set in the scrolling time.
Having said so, if you really believe that the multiscroll effect is totally wrong and misleading for the kind of component you want to drive, you might envision a way to get rid of this. You could try to set some timer and ignore all but one of the mouseWheel events that happen in a given lapse of time (in the range of milliseconds). One thing you should do is to set a configuration option in your program, to let the user to turn off this behaviour.
In my case, I used the JVDBGrid component, but I think this work for DbGrid too. You may overwrite the following functions: OnMouseWheelDown and OnMouseWheelUp.
E.g.:
Type declaration:
type
TMyGrid = class(TJvExDBGrid);
Implementation
procedure TFExample.JvDBGrid1MouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
Handled := TMyGrid(Sender).DataLink.DataSet.MoveBy(1) <> 0;
end;
procedure TFExample.JvDBGrid1MouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
Handled := TMyGrid(Sender).DataLink.DataSet.MoveBy(-1) <> 0;
end;

DBGrid get selected cell

I need to get the value of the selected cell of a DBGrid in Delphi.
I have no idea how to do it. I tried dbGrid's OnMouseMove
pt : TGridCoord;
...
pt:=dbGrid.MouseCoord(x, y);
[Edited]
I can use the OnCellClick to get the value of the cell with "Column.Field.AsString", but I want to get the value from the first column when I click on any column of that row.
Found it.
dbGrid.Fields[0].AsString gets the value of the first column of the selected row.
procedure TForm1.DBGrid_DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumnEh; State: TGridDrawState);
const defaultCheckBoxFieldNumber = 1;
begin
if DBGrid.SelectedField.FieldNo = defaultCheckBoxFieldNumber then
....;
else
...;
end;
DBGrid.SelectedField.FieldNo gets selected field on event DrawColumnCell in TDBGrid.
I know this is late and not sure if it is what the title means.
But if it means to get the selected cell value, then try this:
procedure Form1.dbGrid1CellClick(Column: TColumn);
begin
ShowMessage(table1.Fields[Column.Index].AsString);
end;
Make sure
dbGrid1.Options.dbRowSelect := False;
i think the easiest way is to connect a hidden DBText to your dataset then set the DBText to display which field you need, this way that DBText will always contain the needed value of the active record
A DBGrid has no focus, and therefore you cannot find out which row is seleted. Instead look at the linked DataSet. A DataSet has an active row.
try this to get the value of selected cell in dbgrid:
procedure Form1.dbGrid1CellClick(Column: TColumn);
begin
ShowMessage(table1.Fields[DBGrid1.SelectedIndex].AsString);
end;

In a devexpress tdxdbgrid, is there a way to allow rowselect and keypress events to both fire?

Client would like to have row selected so that he can tell what record on the left is being worked on, while being able to edit just 1 column.
so, advise on how to allow row-select plus keypress events to fire, or how to color a cell based on whether another cell in it's row has been entered.
Coloring distinct cxGrid rows is best done using their Styles collection with OnGetContentStyle event.
procedure StylesGetContentStyle(Sender: TcxCustomGridTableView;
ARecord: TcxCustomGridRecord; AItem: TcxCustomGridTableItem;
out AStyle: TcxStyle);
begin
if SomeCondition then
AStyle := SomeTcxStyle;
end;
Another way is by using OnCustomDrawCell event and drawing the grid yourself. I prefer to use styles, it's cleaner.

Resources