Выберите несколько строк при Shift+ клик в DBGrid
Мне нужно написать код для выбора нескольких строк на Shift+MouseClick, чтобы я мог заполнить значения. Есть ли способ, которым я могу это сделать? Мои параметры DBGrid следующие:
dbGrid1.Options = [dgEditing, dgAlwaysShowEditor, dgTitles, dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit, dgMultiSelect]
2 ответа
Первоначально я думал, что проблема, с которой вы, вероятно, столкнетесь, заключается в том, что Shift + Click обрабатывается самой сеткой, поэтому во время срабатывания OnMouseUp сетки сетка уже переместила курсор набора данных в строку, которая была нажата с помощью Shift, Поэтому расширение выделения сетки с того места, где оно находилось до нажатия на клавишу Shift, не будет простым, поскольку вам не хватит информации о том, где ранее находился курсор ds.
Тем не менее, это оказывается довольно просто сделать. Я добавил несколько комментариев к приведенному ниже коду, чтобы объяснить, как он работает.
Для простоты я реализовал это с помощью ClientDataSet с полем целочисленного идентификатора. Смысл использования поля идентификатора состоит в том, что код использует текущие и предыдущие значения идентификатора, что-то вроде ручной передачи, когда набор данных прокручивается, для своей работы. Делать подобное с использованием закладок было бы сложнее из-за необходимости постоянно выделять и освобождать их, поэтому я оставляю это как упражнение для читателя.
Код:
// Form variables
SettingBookmarkRange : Boolean;
CurrentRowID,
PreviousRowID: Integer;
procedure TForm1.CDS1AfterScroll(DataSet: TDataSet);
begin
if SettingBookmarkRange then exit;
PreviousRowID := CurrentRowID;
CurrentRowID := CDS1.FieldByName('ID').AsInteger;
Caption := Format('Current %d, prior %d', [CurrentRowID, PreviousRowID]);
end;
procedure TForm1.SetBookmarkRange;
var
BM,
TempBM : TBookmark;
NewBM : TBookmarkStr;
FoundPrevious : Boolean;
begin
// This code is called after the user does a Shift-Click in the grid
// First we set a flag to temporarily prevent the CurrrentRowID and
// PreviousrowID from being updated during the dataset's OnScroll event
SettingBookmarkRange := True;
BM := CDS1.GetBookmark;
// Set a flag to keep track of whether we've found the row with the PreviousRowID
FoundPrevious := False;
try
CDS1.DisableControls;
// First, search forwards to see if we can find the the row with the PreviousRowID
// In other words, we're first checking that the Shift-Click was on a row *above*
// the previous row
CDS1.Next;
while not FoundPrevious and not CDS1.Eof do begin
if CDS1.FieldByName('ID').AsInteger = PreviousRowID then begin
FoundPrevious := True;
// We found the row with the PreviousRowID, so now get the Grid to add it, and
// all the rows back to where we started, in its SelectedRows list
while not CDS1.Bof and (CDS1.FieldByName('ID').AsInteger <> CurrentRowID) do begin
DBGrid1.SelectedRows.CurrentRowSelected := True;
CDS1.Prior;
end;
end
else
CDS1.Next;
end;
if not FoundPrevious then begin
// If we get here, the Shift-Click must have been in a row further down the
// grid than the previously-current one
while not FoundPrevious and not CDS1.Bof do begin
if CDS1.FieldByName('ID').AsInteger = PreviousRowID then begin
FoundPrevious := True;
// We found the row with the PreviousRowID, so now get the Grid to add it, and
// all the rows back to where we started, in its SelectedRows list
while not CDS1.Eof and (CDS1.FieldByName('ID').AsInteger <> CurrentRowID) do begin
DBGrid1.SelectedRows.CurrentRowSelected := True;
CDS1.Next;
end;
end
else
CDS1.Prior;
end;
end;
finally
CDS1.GotoBookmark(BM);
CDS1.FreeBookmark(BM);
CDS1.EnableControls;
SettingBookmarkRange := False;
end;
end;
procedure TForm1.DBGrid1MouseUp(Sender: TObject; Button: TMouseButton; Shift:
TShiftState; X, Y: Integer);
begin
Caption := IntToStr(CDS1.Fields[0].Value);
if ssShift in Shift then
SetBookMarkRange;
end;
Я использовал вставку для TDBGrid class
, Работает с клавишами Ctrl+Shift:
type
TDBGrid = class(Vcl.DBGrids.TDBGrid)
private
procedure SelectRange;
protected
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); override;
end;
{...}
implementation
{...}
procedure TDBGrid.SelectRange;
var
CurrentBookMark, CursorBookMark, FirstBookMark, LastBookMark: TBookmark;
Dir: integer;
begin
if SelectedRows.Count <= 1 then
exit;
DataSource.DataSet.DisableControls;
try
FirstBookMark := SelectedRows.Items[0];
LastBookMark := SelectedRows.Items[SelectedRows.Count - 1];
SelectedRows.Clear;
CurrentBookMark := DataSource.DataSet.GetBookmark;
Dir := DataSource.DataSet.CompareBookmarks(FirstBookMark, CurrentBookMark);
if Dir = 0 then
Dir := DataSource.DataSet.CompareBookmarks(LastBookMark, CurrentBookMark);
if Dir > 0 then
DataSource.DataSet.GotoBookmark(LastBookMark)
else if Dir < 0 then
DataSource.DataSet.GotoBookmark(FirstBookMark)
else
Exit;
while not DataSource.DataSet.eof do
begin
CursorBookMark := DataSource.DataSet.GetBookmark;
SelectedRows.CurrentRowSelected := true;
if DataSource.DataSet.CompareBookmarks(CurrentBookMark, CursorBookMark) = 0 then
begin
DataSource.DataSet.FreeBookMark(CursorBookMark);
break;
end;
DataSource.DataSet.FreeBookMark(CursorBookMark);
if Dir < 0 then
DataSource.DataSet.Next
else
DataSource.DataSet.Prior;
end;
DataSource.DataSet.FreeBookMark(CurrentBookMark);
finally
DataSource.DataSet.EnableControls;
end;
end;
{ TDBGrid }
procedure TDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
inherited;
if Shift = [ssCtrl, ssShift, ssLeft] then
SelectRange;
end;
Поведение выбора по умолчанию для сетки с несколькими выборками -Ctrl-Click, а не Shift-Click. Для его использования не требуется никаких специальных обработчиков щелчков мышью.
Чтобы реализовать Shift-Click вместо этого, вы должны отменить / реализовать обработчики щелчков мыши в сетке.