0

I have a TStringGrid with several rows in which I implemented some kind of 'read-only' row. More exactly, I don't allow the user to click the penultimate row. If the user clicks the last row nothing happens; the focus won't be moved to the cells of that row.

I have the code (in KeyDown) and everything works smooth. However, if the user clicks the top row and then uses the mouse wheel to scroll down, eventually the focus will move to the penultimate row. Any idea how to prevent this?

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • To answer your question, how to prevent it... Simply fix your code, since behavior you've described is different from a default behavior of a string grid without any event handling. The grid row selection is changed while you're scrolling but by one row per scroll step, not from the first row to the penultimate one (except when you'd have 3 rows of course :-) – TLama Sep 04 '12 at 15:20
  • @TLama - I never said that it will jump from the first row to the last. If the user keeps scrolling it will eventually reach the last row :) – Gabriel Sep 04 '12 at 15:25
  • Well, so then I didn't get the part, *if the user clicks the top row and then uses the mouse wheel to scroll down, the focus will move to the penultimate row. Any idea* ***how to prevent this*** *?* It sounds like it's happening to you and you want to prevent that behavior. – TLama Sep 04 '12 at 15:28
  • @TLama - No.... sorry for confusion. I added 'eventually' in the OP. – Gabriel Sep 04 '12 at 15:50
  • 1
    A point of clarification: "penultimate" means "next-to-last", not last. Your question is saying that focus shouldn't change to the second-last row. You mean the last row, right? – Graham Sep 04 '12 at 16:00

2 Answers2

5

Well, you could override DoMouseWheelDown to achieve this.

function TMyStringGrid.DoMouseWheelDown(Shift: TShiftState; 
  MousePos: TPoint): Boolean;
begin
  if Row<RowCount-2 then
    //only allow wheel down if we are above the penultimate row
    Result := inherited DoMouseWheelDown(Shift, MousePos)
  else
    Result := False;
end;

But how do you know that there isn't some other way to move the focus to the last row?

In fact a much better solution is to override SelectCell:

function TMyStringGrid.SelectCell(ACol, ARow: Longint): Boolean;
begin
  Result := ARow<RowCount-1;
end;

When you do it this way you don't need any KeyDown code, and you don't need to override DoMouseWheelDown. All possible mechanisms to change the selected cell to the final row will be blocked by this.

As @TLama correctly points out, you don't need to sub-class TStringGrid to achieve this. You can use the OnSelectCell event:

procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol, ARow: Longint;
  var CanSelect: Boolean);
begin
  CanSelect := ARow<(Sender as TStringGrid).RowCount-1;
end;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • It seems that DoMouseWheelDown is called AFTER the event (the scroll) takes place (when the focus leaves the read-only cell/row). I put a BEEP in the code and it confirms this. First the focus is set to my read-only cell, then I scroll one more time and I hear the beep. – Gabriel Sep 04 '12 at 15:08
  • 1
    Not in my `TCustomGrid` derived class. Anyway, use `SelectCell`. It's just better all round. One line of code to do everything. You can rip out all the rest of your efforts. – David Heffernan Sep 04 '12 at 15:09
  • Good. `DoMouseWheelDown` does what's needed also, when you derive from TCustomGrid. Perhaps there's something else in between that and your code that messed that up. No matter, `SelectCell` is the right way to go. – David Heffernan Sep 04 '12 at 15:25
  • You don't need to derive anything, just handle the `OnMouseWheelDown` event and assign True to the `Handled` parameter. – TLama Sep 04 '12 at 15:30
  • 1
    @TLama And also deal with `KeyDown`. So, I respectfully propose that `SelectCell` is the way to go. – David Heffernan Sep 04 '12 at 15:31
  • So then `OnSelectCell` and `CanSelect` parameter ;-) – TLama Sep 04 '12 at 15:32
  • 1
    @TLama Yes that's right. Sorry, I'm just so used to my own grid which is derived from `TCustomGrid`. Answer now updated. – David Heffernan Sep 04 '12 at 15:35
-1

I solved this problem by putting this in the event OnMouseWheelUp:

procedure Tmainform.sgup(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
        sg.RowCount := sg.RowCount + 1;
        sg.RowCount := sg.RowCount - 1;
end;
Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
  • I'm sorry, but this site works in English so that anyone would understand the answer. Can you translate it? – ZygD May 21 '15 at 18:50