views:

319

answers:

1

Question:

Can anyone point to an article or code samples anywhere on how to provide BOTH editing AND range selection in a TStringGrid?

Yes, I KNOW there are third-party grids that do this, but it's frustrating that the built-in grid lacks this basic capability.

Background:

It's pretty normal to expect to be able to both edit a cell in a grid, and also to select a range of cells such as for a Copy operation.

As delivered, TStringGrid doesn't do that. It's either/or. In fact, the docs tell us about the grid Options, "When goEditing is included in Options, goRangeSelect has no effect".

However, it looks like it may be possible to do editing and rangeselects in a TStringGrid anyway!!! Through careful use of the mousedown, mouseup, selectcell and exit events, you can get dang close by switching editing elements on and off at the right times. But I still don't have it perfect, and that only covers mouse use, not keyboard changes.

+1  A: 

I have not used the TStringGrid for this, so I can't provide a specific answer. But am I right in assuming you can manually (in code) start a cell being edited? That link implies it is possible even if the grid doesn't have goEditing included in its Options. (See below to work around this if this is not true.)

If so, I'd suggest the following approach:

Combined selection and edit behaviour

I find this is a good, Windows-standard-behaviour sort of approach:

  • Leave the grid in selection mode, so mouse and keyboard interaction selects cells

  • Trigger a cell being edited yourself, based on certain criteria (I think you are on the way to doing this from what you said in your last paragraph.) There are common ways to trigger editing, and the following criteria are what my programs follow when they do something similar with other controls:

    • Selection is normal. Ie, click to select, click and drag to multi-select, use the keyboard arrows and Shift or Control to select, etc.

    • A cell enters edit mode when either:

      1. A cell is selected and the user presses Enter or F2 (F2 is the standard "Rename" or "Edit" shortcut, which works in a number of programs)

      2. The user "slow-double-clicks" on a cell - ie, slow-double-clicks to select and edit, or clicks again, after a pause, on an already-selected cell. This mimics Explorer's behaviour, where if a file is selected and you later click on it, it enters the inline edit/rename mode. To implement this, record when a cell was last clicked (and selected.) If it is clicked again, and if the time is greater than GetDoubleClickTime then they have clicked twice, slowly, and enter edit mode. This allows you to distinguish between the first click to select, a double-click (to perform some kind of action), and a slow second click, to enter edit mode.

        I also tend to check the mouse position, so that if an object is slow-double-clicked and it wasn't first selected (ie, this both selects the object and then enters edit mode) I verify the mouse hasn't moved very much. I use GetSystemMetrics to find the double-click distance, and check that the slow double click was within this box. (Because it's not a true doubleclick, I actually check the distance times 2. My action code is:

        const int iMAX_MOVE_AMOUNT = ::GetSystemMetrics(SM_CYDOUBLECLK) * 2; (sorry, C++ not Delphi, but should be convertable easily enough!)

        but I'm actually not certain if this is completely and utterly 100% to Windows guidelines. In practice users find it works as they expect, though.)

That should let you change between selecting and editing at the appropriate times with both the keyboard and the mouse.

Miscellaneous thoughts

You may find some of this is cleaner and easier to implement by subclassing TStringGrid and creating a new component. That will allow you to implement this in normal code and override the inbuilt behaviour (rather than event handlers) while keeping it invisible to the form code. It will also give you lower-level access to the mouse events or Windows messages than are exposed simply through events such as OnMouseDown. Finally, if there are problems with showing the editor when goEditing is included in Options, this will allow you to change that behaviour. You could also add your own events if you want your code to respond to certain things happening, such as creating an OnBeginEdit event, say.

Creating your own components is normally regarded as an advanced Delphi topic, but it's actually remarkably easy once you know how! This site has a few good topics that will introduce you to the subject in general, and if you go this route and encounter problems, Stack Overflow is of course a good place to ask questions :) The Embarcadero Delphi » VCL » Writing Components newsgroup / forum is also an excellent resource, in fact possibly even better than SO for this specific topic.

Hope that helps!

David M