5
votes

Is it possible to force a selection in my StrinGrid? I would like to only allow the user to select cells horizontally, even if the mouse may move up and down when selecting, I want to stringgrid to show the selection only on the row where there was the MouseDown. So when the user wants to select a range of cells, he will click the mouse, drag the mouse to the right (or left) while seeing how cells are selected one-after-the-other, and then comes the MouseUp event. While dragging I do not want the user to see other rows (than the one where the dragging begun) being selected as he moves the mouse. I assume I should do something in onMouseMove of the StringGrid... but how ?

My code so far is:

// this draws a focus rect around the selected cell (DefaultDrawing=false)
procedure TForm2.sgDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect;
  State: TGridDrawState);
begin
if (gdFocused in State)or(gdSelected in State) then
            begin
              sg.Canvas.Pen.Color:=$00FFEECC;
              sg.Canvas.MoveTo(Rect.Left,Rect.Top);
              sg.Canvas.LineTo(Rect.Right,Rect.Top);
              sg.Canvas.LineTo(Rect.Right,Rect.Bottom);
              sg.Canvas.LineTo(Rect.Left,Rect.Bottom);
              sg.Canvas.LineTo(Rect.Left,Rect.Top);
            end
            else
            begin
              sg.Canvas.Brush.Color:=clWhite;
              sg.Canvas.FillRect(Rect);
            end;
end;

procedure TForm2.sgMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 myrow:=sg.Row;
 mycol:=sg.Col;
end;

procedure TForm2.sgMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  sg.Row:=myrow;
end;

Is it possible? How can I do this?

1

1 Answers

5
votes

Yes it is posible. Instead of controling the grid I would set the bounds of the mouse movement while selecting: using Windows.ClipCursor;

First on mouseDown calculate the valid bounds:

procedure TForm8.StringGrid1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  StringGrid: TStringGrid;
  GridRect: TGridRect;
  Row: Integer;
  CursorClipArea: TRect;
  BoundsRect: TRect;
begin
  // The Sender argument to StringGrid1Click is actually the StringGrid itself,
  // and the following "as" cast lets you assign it to the StringGrid local variable
  // in a "type-safe" way, and access its properties and methods via the temporary variable
  StringGrid := Sender as TStringGrid;

  // Now we can retrieve the use selection
  GridRect := StringGrid.Selection;

  // and hence the related GridRect
  // btw, the value returned for Row automatically takes account of
  // the number of FixedRows, if any, of the grid
  Row := GridRect.Top;

  //Then set the bounds of the mouse movement.
  //ClipCursor uses Screen Coordinates to you'll have to use ClientToScreen
  CursorClipArea.TopLeft := StringGrid.ClientToScreen(StringGrid.CellRect(StringGrid.FixedCols, Row).TopLeft);
  CursorClipArea.BottomRight := StringGrid.ClientToScreen(StringGrid.CellRect(StringGrid.ColCount - 1, Row).BottomRight);
  Windows.ClipCursor(@CursorClipArea)
end;

//Then on mouse up release the mouse
    procedure TForm8.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    begin
      //Release mouse
      Windows.ClipCursor(nil)
    end;