5

Delphi 2007 でコンパイルされた私のアプリケーションには、グリッド間でのドラッグ アンド ドロップがあり、ほとんどの場合正常に動作します。しかし、ランダムにアクセス違反が発生することがあります。VCL の Controls.pas メソッド DragTo にデバッグしました。

次のように始まります。

begin
  if (ActiveDrag <> dopNone) or (Abs(DragStartPos.X - Pos.X) >= DragThreshold) or
    (Abs(DragStartPos.Y - Pos.Y) >= DragThreshold) then
  begin
    Target := DragFindTarget(Pos, TargetHandle, DragControl.DragKind, DragControl);

DragControl が nil であるため、最後の行で例外が発生します。DragControl は、TControl 型のグローバル変数です。このメソッドに assigncheck をパッチして、DragControl = nil の場合は CancelDrag を呼び出そうとしましたが、DragObject も nil であるため、これも失敗します。

procedure CancelDrag;
begin
 if DragObject <> nil then DragDone(False);
 DragControl := nil;
end;

DragControl が nil である理由を調べるために、DragInitControl を調査しました。DragControl が nil の場合に終了する 2 行があります。

procedure DragInitControl(Control: TControl; Immediate: Boolean; Threshold: Integer);
var
  DragObject: TDragObject;
  StartPos: TPoint;
begin
  DragControl := Control;
  try
    DragObject := nil;
    DragInternalObject := False;    
    if Control.FDragKind = dkDrag then
    begin
      Control.DoStartDrag(DragObject);
      if DragControl = nil then Exit;
      if DragObject = nil then
      begin
        DragObject := TDragControlObjectEx.Create(Control);
        DragInternalObject := True;
      end
    end
    else
    begin
      Control.DoStartDock(DragObject);
      if DragControl = nil then Exit;
      if DragObject = nil then
      begin
        DragObject := TDragDockObjectEx.Create(Control);
        DragInternalObject := True;        
      end;
      with TDragDockObject(DragObject) do
      begin
        if Control is TWinControl then
          GetWindowRect(TWinControl(Control).Handle, FDockRect)
        else
        begin
          if (Control.Parent = nil) and not (Control is TWinControl) then
          begin
            GetCursorPos(StartPos);
            FDockRect.TopLeft := StartPos;
          end
          else
            FDockRect.TopLeft := Control.ClientToScreen(Point(0, 0));
          FDockRect.BottomRight := Point(FDockRect.Left + Control.Width,
            FDockRect.Top + Control.Height);
        end;
        FEraseDockRect := FDockRect;
      end;
    end;
    DragInit(DragObject, Immediate, Threshold);
  except
    DragControl := nil;
    raise;
  end;
end;

理由かもしれません...それで私の質問です。

  1. ドラッグアンドドロップで同様の問題が発生した人はいますか?
  2. DragControl = nil を検出した場合、現在のドラッグ アンド ドロップをキャンセルするにはどうすればよいですか?

編集: 現在、これに対する解決策はありませんが、それについてさらに情報を追加できます。グリッドはスーパーグリッドと呼ばれます。これは、当社のニーズに合わせて開発した内部コンポーネントです。Devexpress から TcxGrid を継承します。グリッドがデータをリロードすると同時に、ユーザーがグリッド行をドラッグすると、この問題が発生すると思います (確かではありません)。どういうわけか、現在の行への参照が nil になります。長期的には、このスーパーグリッドを TcxGrid から継承する Bold 対応グリッド (Delphi では Bold を使用しているため) に置き換える計画があります。次に、データが変更されるとすぐにグリッドが更新され (ユーザーまたはコードで更新されません)、これで問題が解決されることを願っています。

4

1 に答える 1

3
  1. いいえ、VCL によるドラッグ アンド ドロップで (この種の) 問題が発生したことはありません。また、かなりの経験があります。

  2. DragControlは Controls ユニットに対してローカルなのでDragControl = nil、製品コード内でどのように検出しますか? 通常、チェックする必要はありません。少なくとも、チェックする必要はありませんでした。ドラッグ操作のキャンセルは、受け入れられないターゲット上でマウスを放すか、 を押す以外に、ESCを呼び出すことによって行われCancelDragます。そして、すでに気付いているように、そのルーチンDragDoneDragObject <> nil. したがってDragObject、明らかに nil であることは、進行中のドラッグ操作が (もう) ないことをすでに示しています。

また、AVのソースがその特定の行からのものであるというあなたの観察はControls.DragTo間違っているようです. 通常のドラッグ アンド ドロップ操作でDragControlnil、AV にはなりません。ただし、以下Controls.DragFindTargetでは、ドラッグ アンド ドッキング操作で問題が発生する可能性がありますが、ドッキングを行うことについては言及していません。

この「バグ」がどのような状況で、またはどのコードで表示されるかを明確にしていただけますか?

于 2011-12-24T11:41:40.937 に答える