2011-12-23 17 views
5

La mia applicazione compilata con Delphi 2007 ha un trascinamento tra le griglie e funziona bene la maggior parte del tempo. Ma a volte casualmente ho avuto violazione di accesso. Ho eseguito il debug sul metodo Controls.pas DragTo in VCL.Bug in Delphi VCL Drag and Drop?

Comincia così:

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); 

L'eccezione avviene nell'ultima riga perché DragControl è nullo. DragControl è una variabile globale di tipo TControl. Ho provato a correggere questo metodo con un assigncheck e chiamare CancelDrag se DragControl = nil, ma fallisce anche perché DragObject è anche nullo.

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

Per scoprire perché DragControl è nil, ho ispezionato DragInitControl. Ci sono 2 righe che escono solo se DragControl è nullo.

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; 

Potrebbe essere la ragione ... Quindi la mia domanda.

  1. Qualcuno ha avuto problemi simili con il trascinamento della selezione?
  2. Se rilevo DragControl = nil come posso annullare il trascinamento corrente?

Edit: Attualmente ho alcuna soluzione a questo, ma posso aggiungere un po 'di informazioni su di esso. Le griglie si chiamano supergrid. Questo è un componente interno che abbiamo sviluppato per soddisfare le nostre esigenze. Eredita TcxGrid da Devexpress. Penso (ma non sono sicuro) che questo problema si presenti quando l'utente trascina una riga della griglia nello stesso momento in cui la griglia ricarica i dati. In qualche modo il riferimento alla riga corrente diventa nullo. A lungo termine abbiamo in programma di sostituire questa supergrid con una griglia Bold (come usiamo Bold for Delphi) che eredita anche da TcxGrid. Quindi la griglia viene aggiornata non appena i dati vengono modificati (nessun aggiornamento da parte dell'utente o nel codice) e si spera che questo risolva il problema.

+0

Hai considerato l'interazione con le estensioni della Shell? Ho affrontato problemi simili usando TOpenDialog. – menjaraz

+2

Ottima domanda. Non ho esperienza nell'uso del trascinamento della selezione VCL da controllo a controllo, ma se dovessi farlo, proverei il codice di A. Melander invece di VCL per questo argomento e vedrò se c'è una demo e alcuni inserisci qui più solido; http://melander.dk/delphi/dragdrop/ –

+0

Ho avuto problemi simili con il trascinamento della selezione (anche delphi 2007). ma stranamente questo tipo di problema compare solo (e frequentemente) quando si esegue il programma da remoto con "netviewer". – DamienD

risposta

3
  1. No, non ho mai avuto alcuna (di questo tipo di) problemi con il drag and drop per VCL, e ho un po 'di esperienza con esso.

  2. DragControl è locale all'unità di controllo, quindi come si rileva DragControl = nil all'interno del codice di produzione? Normalmente, non c'è bisogno di controllarlo, almeno non ho mai dovuto. Annullando un'operazione di trascinamento, l'altro, rilasciando il mouse su un target non accettato o premendo ESC, viene effettuato chiamando lo CancelDrag. E come ti sei già accorto, quella routine chiama DragDone solo quando DragObject <> nil. Quindi apparentemente DragObject essere nil sta già dicendo che non c'è alcuna operazione di trascinamento in corso (più).

Inoltre, la tua osservazione che la fonte del AV è da quella linea specifica Controls.DragTo sembra essere sbagliato. In una normale operazione di trascinamento della selezione, è nil non risulta in un AV. Tuttavia, a seguito di Controls.DragFindTarget, potrebbe essere problematico in un'operazione di trascinamento e caricamento, ma non si è detto di fare alcun attracco.

Potrebbe chiarire in quale situazione, o con quale codice viene visualizzato questo "bug"?