2011-12-23 9 views
5

Delphi 2007でコンパイルした私のアプリケーションには、グリッド間にドラッグアンドドロップがあり、ほとんどの場合うまく機能します。しかし、時々ランダムに私はアクセス違反を持っています。私はVCLでControls.pasメソッドDragToにデバッグしました。Delphi VCLドラッグアンドドロップのバグ?

それはこのように始まる:

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型のグローバル変数です。 DragControl = nilの場合、assigncheckでこのメソッドにパッチを当てて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を継承します。私は、グリッドをデータを再読み込みすると同時にグリッドの行をドラッグすると、この問題が発生すると考えています(しかしわかりません)。どういうわけか、現在の行への参照はゼロになります。長期的には、このスーパーグリッドを、TcxGridから継承するBold対応のグリッド(DelphiのBoldを使用している)と置き換える予定です。次に、データが変更されると(ユーザーまたはコードによってリフレッシュされない場合)、グリッドが更新され、うまくいけば問題が解決されます。

+0

シェル拡張機能との対話を考えましたか? TOpenDialogを使用して同様の問題に直面しました。 – menjaraz

+2

優秀な質問です。私はVCL組み込みのドラッグ&ドロップを使ってコントロールからコントロールに移動する経験はありませんが、もしこれを行う必要があれば、この分野のVCLの代わりにA. Melanderのコードを試してみてください。ここのコードはより強固です。 http://melander.dk/delphi/dragdrop/ –

+0

私はドラッグアンドドロップ(デルファイ2007も同様)に関する同様の問題を抱えていました。しかし、間違いなく、この種の問題は "netviewer"を使ってリモートでプログラムを実行している場合にのみ(そして頻繁に)現れます。 – DamienD

答えて

3
  1. いいえ、VCLによるドラッグアンドドロップの問題は一度もありませんでした。私はかなりの経験があります。

  2. DragControlはコントロールユニットにローカルなので、プロダクションコード内でどのようにDragControl = nilを検出しますか?通常、少なくともそれをチェックする必要はありません、少なくとも私はしなければならなかった。ドラッグ操作を取り消し、それ以外の場合は受諾対象外にマウスを放すか、ESCを打つことは、CancelDragを呼び出して行います。そしてあなたがすでに気づいたように、そのルーチンはのときにのみDragDoneを呼び出します。したがって、現状ではDragObjectがnilであることは、すでにドラッグ操作が進行中ではないことを既に指摘しています(これ以上)。

また、AVのソースはControls.DragToにその特定の行からのものであることを、あなたの観察が間違っているように見えます。通常のドラッグ・アンド・ドロップ操作では、DragControlnilであり、AVにはなりません。しかし、Controls.DragFindTargetの後には、ドラッグ&ドック操作で問題があるかもしれませんが、ドッキングを行うことは言及していません。

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

関連する問題