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.
- tienen a nadie tenido problemas similares con arrastrar y soltar?
- 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.
¿Ha considerado la interacción con las extensiones de Shell? Me enfrenté a un problema similar con TOpenDialog. – menjaraz
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/ –
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