2011-12-23 18 views
5

Mi aplicación compilada con Delphi 2007 tiene arrastrar y soltar entre cuadrículas y funciona bien la mayor parte del tiempo. Pero a veces al azar recibí una infracción de acceso. Lo depuré al método Controls.pas DragTo en VCL.Error en Delphi VCL Arrastrar y soltar?

Comienza así:

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

La excepción ocurre en la última fila porque DragControl es nula. DragControl es una variable global de tipo TControl. He intentado aplicar un parche a este método con una comprobación de asignación y llamar a CancelDrag si DragControl = nil, pero eso también falla porque DragObject también es nulo.

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

Para averiguar por qué DragControl es nulo, inspeccioné DragInitControl. Hay 2 líneas que simplemente salen si DragControl es nulo.

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; 

Podría ser el motivo ... Así que mi pregunta.

  1. tienen a nadie tenido problemas similares con arrastrar y soltar?
  2. Si detecto DragControl = nil, ¿cómo puedo cancelar la acción de arrastrar y soltar actual?

Editar: Actualmente tengo ninguna solución para esto, pero puede añadir un poco de más información al respecto. Las cuadrículas se llaman supergrid. Este es un componente interno que desarrollamos para satisfacer nuestras necesidades. Hereda TcxGrid de Devexpress. Creo (pero no estoy seguro) que este problema se produce cuando el usuario arrastra una fila de la grilla al mismo tiempo que la grilla recarga datos. De alguna manera, la referencia a la fila actual se vuelve nula. A largo plazo, tenemos planes para reemplazar esta superred con una grilla Bold aware (como usamos Bold para Delphi) que también hereda de TcxGrid. A continuación, la cuadrícula se actualiza tan pronto como se modifican los datos (sin actualización por el usuario o en el código) y con suerte esto soluciona el problema.

+0

¿Ha considerado la interacción con las extensiones de Shell? Me enfrenté a un problema similar con TOpenDialog. – menjaraz

+2

Excelente pregunta. No tengo experiencia en usar el arrastre incorporado de VCL y soltarlo de control en control, pero si tuviera que hacerlo, probaría el código de A. Melander en lugar de la VCL desnuda para este tema y veré si hay una demo y alguna código aquí que es más sólido; http://melander.dk/delphi/dragdrop/ –

+0

Tuve problemas similares con arrastrar y soltar (delphi 2007 también). pero, curiosamente, este tipo de problema aparece solo (y con frecuencia) cuando se ejecuta el programa de forma remota con "netviewer". – DamienD

Respuesta

3
  1. No, nunca he tenido ninguna (de este tipo de) problemas con arrastrar y soltar por VCL, y tengo bastante experiencia con ella.

  2. DragControl es local a la unidad de controles, por lo que ¿Cómo se detecta DragControl = nil dentro de su código de producción? Normalmente, no hay necesidad de verificarlo, al menos nunca tuve que hacerlo. La cancelación de una operación de arrastre, aparte de soltar el mouse sobre un objetivo que no acepta o al presionar ESC, se realiza llamando al CancelDrag. Y como ya se dio cuenta, esa rutina llama al DragDone solo cuando DragObject <> nil. Así aparentemente DragObject siendo nil ya está diciendo que no hay operación de arrastre en progreso (más).

Además, su observación de que la fuente de la AV es de esa línea específica en Controls.DragTo parece estar mal. En una operación normal de arrastrar y soltar, DragControl siendo nil no da como resultado un AV. Sin embargo, después de Controls.DragFindTarget, podría ser problemático en una operación de arrastre y dock, pero no mencionó hacer ningún acoplamiento.

¿Podría aclarar en qué situación o con qué código aparece este 'error'?