Recent

Author Topic: Here is how to achieve shift-click (contiguous) select on TDBGrid  (Read 2810 times)

grandehombre

  • New Member
  • *
  • Posts: 40
Code: [Select]
{
Usage:
in the form that needs this functionality, add

var
    previousGridBookmark: TBookmark;

...
...
...


procedure TfrmTest.DBGrid1CellClick(Column: TColumn);
begin
DBGridShiftSelect(DBGrid1, previousGridBookmark);

  // save last selected bookmark
  previousGridBookmark := DBGrid1.DataSource.DataSet.GetBookmark;
end;


// Don't forget to clear the above bookmark when you clear or re-populate the grid
//
// Example code
//if assigned(previousGridBookmark) then begin
//        DBGrid1.DataSource.DataSet.FreeBookmark(previousGridBookmark);
//        previousGridBookmark := nil;
//    end;


}

Add this code to a unit of its own (or in the form itself, though  it would be best on its own, so it can be reused!)


// Allow shift-Ckick marking of a contiguous block
procedure DBGridShiftSelect(Sender: TObject; existingBookmarks: TBookmark);
var
curPos: TBookmark;
limiter: integer;
grid: TDBGrid;
dSet: TDataSet;
rFrom, rTo, rTmp: integer;
begin
grid := (Sender as TDBGrid);
dSet := grid.DataSource.DataSet;

// Get the current position (bookmark) and record number (the row we shift-clicked on)
curPos := dSet.GetBookmark;
rTo := dSet.RecNo;

dSet.DisableControls;
try
        // dummy loop that allows multiple exits to a single point
repeat
if not (ssShift in GetKeyShiftState) then begin
        exit;
end;

if (existingBookmarks = nil) then begin
exit;
end;

// go to the last bookmark before we shift-clicked
dSet.GotoBookmark(existingBookmarks);
rFrom := dSet.RecNo;

if rTo = rFrom then begin
exit;
end;

// we want to only mark moving forward, so if need be, swap the bookmarks
if rTo < rFrom then begin
rTmp := rTo;
rTo := rFrom;
rFrom := rTmp;
grid.SelectedRows.CurrentRowSelected := True;
dSet.GotoBookmark(curPos);
end;

// stop after marking 255 rows (just in case recNo is not a reliable method of doing this.
// This is probably no longer an issue but it doesn't hurt to leave it here :-)
limiter := 255;
repeat
// highlight current row
grid.SelectedRows.CurrentRowSelected := True;
dset.Next;

rFrom := dSet.recNo;
limiter := limiter - 1;

// keep going until we reach the shift-clicked row
until (limiter < 0) or (rFrom = rTo);
until true;
finally
dSet.FreeBookmark(curPos);
dSet.EnableControls;
end;
end;


UPDATE: Added note on clearing the bookmark when clearing/repopulating the grid
« Last Edit: August 12, 2013, 02:30:42 am by grandehombre »
Lazarus v1.2RC2  i386-win32-win32/win64,  FPC v2.6.2, svn43696 on Win7-64 and win8.1

rfwoolf

  • Newbie
  • Posts: 4
Re: Here is how to achieve shift-click (contiguous) select on TDBGrid
« Reply #1 on: July 13, 2020, 02:34:36 am »
Well done!
I just tested this and it works pretty well.
One thing that needs improvement:
If you want to use shift-click twice:

Example:
1. You select row 10.
2. You use shift-click to select row 20.
  Rows 10-20 are now selected
3. You use shift-click to select row 30.
  Expected behaviour:
  It should select rows 10-30.
  Actual behaviour:
  It selects rows 20-30
 
I made some minor tweaks to the code, but essentially it's the same as you wrote:

Code: Pascal  [Select][+][-]
  1. //Declare a global variable
  2.  
  3. //Used for special function on TDBGrids: the ability to use Shift to select multiple rows
  4. //(See DBGridShiftSelect)
  5. var
  6.   DBGridPriorBookmark : TBookmark;
  7.  
  8. //Don't forget to clear the above bookmark when you clear or re-populate the grid
  9. //Example, place this in Dataset.AfterRefresh:
  10. //begin
  11. //  if assigned(DBGridPriorBookmark) then
  12. //  begin
  13. //    DataSet.FreeBookmark(DBGridPriorBookmark);
  14. //    DBGridPriorBookmark := nil;
  15. //  end;
  16. //end;
  17.  
  18. //Add this code to a unit of its own (or in the form itself, though it would be best on its own, so it can be reused!)
  19. // In a DBGrid, allow Shift-Click marking of a contiguous block
  20. procedure DBGridShiftSelect(Sender: TObject; existingBookmarks: TBookmark);
  21. var
  22.   curPos: TBookmark;
  23.   limiter: integer;
  24.   aDBGrid: TDBGrid;
  25.   aDataset: TDataSet;
  26.   iFrom,
  27.   iTo,
  28.   iTmp: integer;
  29. begin
  30.  
  31.   //Validation
  32.   if not (ssShift in GetKeyShiftState) then
  33.     exit;
  34.  
  35.   if (existingBookmarks = nil) then
  36.     exit;
  37.  
  38.   //Initiliasation
  39.   aDBGrid := (Sender as TDBGrid);
  40.   aDataset := aDBGrid.DataSource.DataSet;
  41.  
  42.   // Get the current position (bookmark) and record number (the row we shift-clicked on)
  43.   curPos := aDataset.GetBookmark;
  44.   iTo := aDataset.RecNo;
  45.  
  46.   aDataset.DisableControls;
  47.   try
  48.     //dummy loop that allows multiple exits to a single point
  49.     repeat
  50.       //go to the last bookmark before we shift-clicked
  51.       aDataset.GotoBookmark(existingBookmarks);
  52.       iFrom := aDataset.RecNo;
  53.  
  54.       if iTo = iFrom then
  55.         exit;
  56.  
  57.       //we want to only select moving forward, so if need be, swap the bookmarks
  58.       if iTo < iFrom then
  59.       begin
  60.         iTmp := iTo;
  61.         iTo := iFrom;
  62.         iFrom := iTmp;
  63.         aDBGrid.SelectedRows.CurrentRowSelected := True;
  64.         aDataset.GotoBookmark(curPos);
  65.       end;
  66.  
  67.       //Stop after marking 255 rows (just in case recNo is not a reliable method of doing this.
  68.       //This is probably no longer an issue but it doesn't hurt to leave it here :-)
  69.       limiter := 255;
  70.  
  71.       repeat
  72.         //highlight current row
  73.         aDBGrid.SelectedRows.CurrentRowSelected := True;
  74.         aDataset.Next;
  75.  
  76.         iFrom := aDataset.recNo;
  77.         limiter := limiter - 1;
  78.  
  79.         //keep going until we reach the shift-clicked row
  80.       until
  81.         (limiter < 0) or (iFrom = iTo);
  82.     until
  83.       true;
  84.   finally
  85.     aDataset.FreeBookmark(curPos);
  86.     aDataset.EnableControls;
  87.   end;
  88. end;
  89.  

//Add this to the DBGrid's onCellClick method:
procedure TfrmTest.DBGrid1CellClick(Column: TColumn);
begin
  DBGridShiftSelect(DBGrid1, DBGridPriorBookmark);

  // save last selected bookmark
  DBGridPriorBookmark := DBGrid1.DataSource.DataSet.GetBookmark;
end;
« Last Edit: July 13, 2020, 02:44:28 am by rfwoolf »

emilt

  • New Member
  • *
  • Posts: 20
Re: Here is how to achieve shift-click (contiguous) select on TDBGrid
« Reply #2 on: July 15, 2020, 04:27:40 pm »
That is very nice, but it made me wonder - is there any special reason why the shift+click functionality is not built-in into the TDBGrid component by default? After all, you can use shift+arrows to do the same with the keyboard, why not with the mouse too?

 

TinyPortal © 2005-2018