Select multiple rows in a TStringGrid (Views: 1270)
Problem/Question/Abstract: Is there any way to allow the user to select multiple rows that are not consecutive for example selecting rows 1,4,5,13, and 16 but not 2,3,6,7,8... ? Answer: The standard selection mechanism build into the stringgrid only supports one consecutive block of selected cells (via the selection property). If you want more you have to code it. Find a way to store the selected state on a per-cell or per-row basis and then use the mouse events to give the user a means to change the state and a OnDrawCell handler to draw the cells accordingly. I used the fixed column 0 in this grid to store the selected state for a row, the cell is either empty (not selected) or contains a space character (selected). I choose to draw a selection marker in column 0 instead of painting the selected rows with another background/ foreground color in this app. Something missing is the ability to click on the fixed column cell to toggle the selected state. I never got around to add that, you would use MouseToCell in OnMouseUp for that and make sure the Row property is set to that cells row before calling ToggleSelection. More work needs to be invested to support range selections as well. const sRowSelected = ' '; sRowNotSelected = #0; {This method is attached to the OnKeyPress event handler for the SGridIndications object. We use it to implement selection/ deselection of rows in the grid by a press of the spacebar. The grid is otherwise read-only.} procedure TEinsendeMainForm.SGridIndicationsKeyPress(Sender: TObject; var Key: Char); begin if key = ' ' then ToggleSelectedState; key := #0; end; {This method is attached to the OnMouseUp event handler for the SGridIndications object. We use it to implement selection/deselection of rows in the grid by a click of the mouse. Any mouse button can be used.} procedure TEinsendeMainForm.SGridIndicationsMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin ToggleSelectedState; end; {procedure TEinsendeMainForm.SGridIndicationsDrawCell Parameters: Sender: the SGridIndications object Col: column index for cell to draw Row: row index for cell to draw Rect: cell rectangle State: cell state Call method: static Description: This method is attached to the grids OnDrawCell event that is called every time a cell needs to be draw. We rely mostly on the default drawing done by the grid to display the data.The only thing we add is for the fixed column 0 cells: if the cell contains a blank as a marker that it is selected we draw a red triangle as a visual cue for the selected state for this row. This type of selection is independend of the standard row selection the grid is set up for and allows any number of rows to be selected and deselected individually. The grid does not support this kind of selection directly. Error Conditions: none Created: 29.06.97 11:58:58 by Peter Below } procedure TEinsendeMainForm.SGridIndicationsDrawCell(Sender: TObject; Col, Row: Longint; Rect: TRect; State: TGridDrawState); var poly: array[1..3] of TPoint; dy, dx: Integer; begin if (Col = 0) and ((Sender as TStringGrid).Cells[0, Row] = ' ') then begin with TStringGrid(Sender).Canvas do begin Brush.Color := clRed; Pen.Color := clRed; poly[1].X := Rect.Right - 5; poly[1].Y := (Rect.Bottom - Rect.Top) div 2 + Rect.Top; dy := (Rect.Bottom - Rect.Top) * 6 div 10; dx := Round(Sqrt(3 * dy * dy) / 2); poly[2].X := poly[1].X - dx; poly[3].X := poly[2].X; poly[2].Y := poly[1].Y - dy div 2; poly[3].Y := poly[1].Y + dy div 2; Polygon(poly); end; end; end; {function TEinsendeMainForm.CountSelectedIndications Parameters: none Returns: the number of rows currently marked as selected in the indication grid. Call method: static Description: Iterates over all rows of the grid and checks the content of column 0. Error Conditions: none Created: 29.06.97 13:42:31 by P. Below } function TEinsendeMainForm.CountSelectedIndications: Integer; var i: Integer; begin Result := 0; with SGridIndications do for i := 1 to RowCount - 1 do if Cells[0, i][1] = sRowSelected then Inc(Result); end; {procedure TEinsendeMainForm.UnselectAllIndications | Parameters: none Call method: static Description: Deselects all indications in the indication grid. Error Conditions: none Created: 07.07.97 13:28:28 by P. Below } procedure TEinsendeMainForm.UnselectAllIndications; var i: Integer; begin with sGridIndications do for i := 1 to RowCount - 1 do Cells[0, i] := sRowNotSelected; end; {procedure TEinsendeMainForm.ToggleSelectedState Parameters: none Call method: static Description: Inverts the selection state of the current row in the indication grid. Called by several event handlers for the grid. Error Conditions: none Created: 29.06.97 13:44:28 by P. Below } procedure TEinsendeMainForm.ToggleSelectedState; begin with SGridIndications do if Cells[0, row] = sRowSelected then Cells[0, row] := sRowNotSelected else Cells[0, row] := sRowSelected; LblNumSelIndications.Caption := IntToStr(CountSelectedIndications) + sIndicationsSelected; end; {procedure TEinsendeMainForm.SelectIndication Parameters: IndicationCode: the numeric (Prisma) code for the indication state: new state (selected or unselected) to set. Call method: static Description: Searches thru the indication grid for the indication and sets it state, if found. Error Conditions: none Created: 07.07.97 13:31:41 by P. Below } procedure TEinsendeMainForm.SelectIndication(const IndicationCode: string; state: Boolean); var i: Integer; ch: Char; begin with sGridIndications do begin i := Cols[1].IndexOf(IndicationCode); if i > 0 then begin if state then ch := sRowSelected else ch := sRowNotSelected; Cells[0, i] := ch; end; end; end; |