DBCtrlGrid Drag and Drop - PullRequest
       2

DBCtrlGrid Drag and Drop

0 голосов
/ 13 марта 2020

Попытка безуспешно перетащить строку для переключения позиций (с использованием ClientDataSet в памяти)

Конкретный случай c: ClientDataSet с именами файлов изображений, которые приведут к упорядоченному списку это будет использоваться для создания экспорта в документ PDF, где каждое изображение является страницей (именно поэтому порядок важен). DbCtrlGrid используется для визуализации миниатюры изображения, и я пытался использовать перетаскивание для обмена их позициями, но я не мог получить информацию о строке, куда я упал в конце.

Это помогло бы методу получить информацию о строке, в которой находится мышь, когда срабатывает событие OnDragDrop или любая другая идея

пожалуйста

1 Ответ

1 голос
/ 14 марта 2020

Я полагаю, что ваше q вызвано тем фактом, что хотя TDBCtrlGrid имеет свойство PanelIndex, которое сообщает вам, какая из виртуальных панелей сетки активна (т. Е. Является той, для текущей строки в наборе данных), это не не меняйте при перемещении мыши, например, во время операции перетаскивания. Тем не менее, нетрудно рассчитать это самостоятельно, как показано ниже.

Height и Width TDBCtrlGrid являются точными кратными RowCount и ColCount. В простом случае ColCount = 1 несложно вычислить, какая строка содержит заданную координату Y в сетке:

function TForm1.PanelIndexFromYPos(Y : Integer) : Integer;
var
  PanelHeight : Integer;
begin
  PanelHeight := DBCtrlGrid1.ClientHeight div DBCtrlGrid1.RowCount;

  Result := Y div PanelHeight;
end;

(очевидно, это для простого случая одного столбца goVertical ориентированная сетка, но ее будет легко обобщить)

Теперь TBDCtrlGrid EndDragMouseOver) сообщает вам координату Y TPoint, где заканчивается операция перетаскивания, так что вы можете использовать эту PanelIndexFromYPos функция, чтобы сказать вам, на какой индекс строки пользователь уронил перетащенную строку. Как объяснил @KenWhite, вам необходимо изменить порядок расположения CDS, чтобы отразить новую позицию, в которой должна находиться перетаскиваемая строка. Это легко сделать, если в вашем CDS есть поле DisplayIndex, представляющее позицию строки данной записи в CDS и CDS имеет активный индекс в этом поле. Переупорядочение записей CDS представляет собой непростую задачу, как будет видно из следующего примера проекта.

TForm1 = class(TForm)
  CDS1: TClientDataSet;
  DataSource1: TDataSource;
  DBGrid1: TDBGrid;
  DBCtrlGrid1: TDBCtrlGrid;  //  Note: DragMode set to dmManual;
  DBText1: TDBText;  // In the DBCtrlGrid
  DBText2: TDBText;
  DBText3: TDBText;
  edSourceIndex: TEdit;
  edDestIndex: TEdit;
  btnTest: TButton;
  Memo1: TMemo;
  Label1: TLabel;
  procedure FormCreate(Sender: TObject);
  procedure DBCtrlGrid1MouseDown(Sender: TObject; Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer);
  procedure DBCtrlGrid1DragOver(Sender, Source: TObject; X, Y: Integer;
    State: TDragState; var Accept: Boolean);
  procedure DBCtrlGrid1DragDrop(Sender, Source: TObject; X, Y: Integer);
  procedure btnTestClick(Sender: TObject);
private
  procedure MoveRow(SourceIndex, DestIndex : Integer);
  procedure LogMove(OldValue, NewValue: Integer);
  procedure ShowPanelInfo(Y: Integer);
protected
  function PanelIndexFromYPos(Y : Integer) : Integer;
public
  SourceIndex : Integer; // the DbCtrlGrid PanelIndex of the row being dragged
  DestIndex : Integer;  // the PanelIndex where the row is dropped
end;
[...]

function TForm1.PanelIndexFromYPos(Y : Integer) : Integer;
var
  PanelHeight : Integer;
begin
  PanelHeight := DBCtrlGrid1.ClientHeight div DBCtrlGrid1.RowCount;

  Result := Y div PanelHeight;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  AField : TField;
begin
  //  Create the fields for the CDS
  AField := TIntegerField.Create(Self);
  AField.FieldName := 'ID';
  AField.DataSet := CDS1;

  //  This DisplayIndex field will be used to determine which row number in
  //  the DBCtrlGrid will occupy, by indexing the CDS on this field
  AField := TIntegerField.Create(Self);
  AField.FieldName := 'DisplayIndex';
  AField.DataSet := CDS1;

  AField := TStringField.Create(Self);
  AField.FieldName := 'Name';
  AField.Size := 20;
  AField.DataSet := CDS1;

  CDS1.CreateDataSet;

  //  Add some data which will appear in the grid in reverse-alphabetical order
  CDS1.InsertRecord([1, 3, 'A']);
  CDS1.InsertRecord([2, 2, 'B']);
  CDS1.InsertRecord([3, 1, 'C']);
  CDS1.InsertRecord([4, 0, 'D']);

  CDS1.IndexFieldNames := 'DisplayIndex';

end;

procedure TForm1.DBCtrlGrid1MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then begin
      SourceIndex := PanelIndexFromYPos(Y);
      DBCtrlGrid1.BeginDrag(False);
   end;
end;

procedure TForm1.DBCtrlGrid1DragOver(Sender, Source: TObject; X,
  Y: Integer; State: TDragState; var Accept: Boolean);
begin
  Accept := True;
end;

procedure TForm1.DBCtrlGrid1DragDrop(Sender, Source: TObject; X,
  Y: Integer);
begin
  ShowPanelInfo(Y);
  DestIndex := PanelIndexFromYPos(Y);
  MoveRow(SourceIndex, DestIndex);
end;

procedure TForm1.MoveRow(SourceIndex, DestIndex : Integer);
var
  BM : TBookMark;
  Index : Integer;

  procedure SetCDSIndex(Value : Integer);
  var
    OldValue : Integer;
  begin
    OldValue := CDS1.FieldByName('DisplayIndex').AsInteger;
    CDS1.Edit;
    CDS1.FieldByName('DisplayIndex').AsInteger := Value;
    CDS1.Post;
    LogMove(OldValue, Value);
  end;

begin
  if SourceIndex = DestIndex then exit;
  CDS1.DisableControls;
  try
    if CDS1.FindKey([SourceIndex]) then begin
      BM := CDS1.GetBookmark;  //  This is to keep track of the dragged row without needing to
                               //  keep track of its (changing) DisplayIndex
      if SourceIndex > DestIndex then begin
        //  i.e. we're moving the dragged row up in the grid
        //  so starting with the row above it we move the rows upwards
        //  eventually leaving a gap to drop the dragged row into
        Index := SourceIndex - 1;
        while Index >= DestIndex do begin
          if CDS1.FindKey([Index]) then begin
            SetCDSIndex(Index + 1);
          end;
          Dec(Index);
        end;
      end
      else begin
        //  i.e. we're moving the dragged row down in the grid
        //  so starting with the row below it we move the rows upwards
        //  eventually leaving a gap to drop the dragged row into
        Index := SourceIndex + 1;
        while Index <= DestIndex do begin
          if CDS1.FindKey([Index]) then begin
            SetCDSIndex(Index - 1);
          end;
          Inc(Index);
        end;
      end;
    end;
    CDS1.GotoBookMark(BM);
    if CDS1.FieldByName('DisplayIndex').AsInteger = SourceIndex then begin
      SetCDSIndex(DestIndex);
    end;
    CDS1.FreeBookmark(BM); //  should really have it's own try...finally but hey!
  finally
    CDS1.EnableControls;
  end;
end;

procedure TForm1.LogMove(OldValue, NewValue : Integer);
begin
  Memo1.Lines.Add(Format('Name: %s Old: %d  New: %d ', [CDS1.FieldByName('Name').AsString, OldValue, NewValue]));
end;

procedure TForm1.ShowPanelInfo(Y : Integer);
begin
  Label1.Caption := Format('y: %d panelindex: %d', [Y, PanelIndexFromYPos(Y)]);
end;

procedure TForm1.btnTestClick(Sender: TObject);
begin
  // For debugging, to test mving rows without needing to drag/drop
  MoveRow(StrToInt(edSourceIndex.Text), StrToInt(edDestIndex.Text));
end;

end.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...