2011-12-23 7 views
5

Moja aplikacja skompilowana z Delphi 2007 ma funkcję przeciągania i upuszczania między siatkami i działa dobrze przez większość czasu. Ale czasami losowo dostałem naruszenie dostępu. I debugowałem go do metody Controls.pas DragTo w VCL.Błąd w Delphi VCL Drag and Drop?

Zaczyna się tak:

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

Wyjątkiem dzieje w ostatnim rzędzie, ponieważ DragControl jest zerowa. DragControl jest globalną zmienną typu TControl. Próbowałem łatać tę metodę przy pomocy polecenia assigncheck i wywołać CancelDrag jeśli DragControl = nil, ale to również się nie powiedzie, ponieważ DragObject również jest zerowe.

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

Aby dowiedzieć się, dlaczego DragControl jest zerowy Sprawdziłem DragInitControl. Istnieją 2 linie, które kończą się po usunięciu DragControl.

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; 

Może to być powodem ... Moje pytanie.

  1. Czy ktoś miał podobne problemy z przeciąganiem i upuszczaniem?
  2. Jeśli wykryję DragControl = zero, w jaki sposób mogę anulować bieżące przeciąganie i upuszczanie?

Edit: Obecnie nie mam na to rozwiązanie, ale można dodać trochę więcej informacji na ten temat. Siatki nazywa się supergrid. Jest to wewnętrzny komponent, który opracowaliśmy, aby odpowiadał naszym potrzebom. Dziedziczy TcxGrid z Devexpress. Myślę (ale nie jestem pewien), że problem ten pojawia się, gdy użytkownik przeciąga wiersz siatki w tym samym czasie, gdy dane przeładowują sieć. W jakiś sposób odniesienie do bieżącego wiersza staje się zerowe. W dłuższej perspektywie mamy zamiar zastąpić tę supergrid świadomą siatką Bold (jak używamy Bold dla Delphi), która również dziedziczy z TcxGrid. Następnie siatka jest aktualizowana natychmiast po zmianie danych (brak odświeżania przez użytkownika lub kod) i mam nadzieję, że to rozwiąże problem.

+0

Czy rozważałeś interakcję z rozszerzeniami Shell? Stawiłem czoła podobnemu problemowi używając TOpenDialog. – menjaraz

+2

Doskonałe pytanie. Nie mam doświadczenia z wykorzystaniem wbudowanego mechanizmu przeciągania i upuszczania VCL z kontroli do sterowania, ale gdybym tego potrzebował, wypróbowałbym kod A. Melandera zamiast gołego VCL dla tego obszaru tematycznego i sprawdziłbym, czy jest wersja demonstracyjna i niektóre kod tutaj, który jest bardziej solidny; http://melander.dk/delphi/dragdrop/ –

+0

Miałem podobne problemy z drag and drop (delphi 2007 też). ale dziwnie ten problem pojawia się tylko (i często) przy zdalnym uruchomieniu programu z "netviewer". – DamienD

Odpowiedz

3
  1. Nie, nigdy nie miałem żadnych (z tego rodzaju) problemy z przeciągania i upuszczania przez VCL i mam sporo doświadczenia z nim.

  2. DragControl jest lokalny dla jednostki sterującej, więc jak można wykryć kod DragControl = nil w kodzie produkcyjnym? Zwykle nie ma potrzeby sprawdzania go, przynajmniej nigdy nie musiałem. Anulowanie operacji przeciągania, inne niż zwolnienie myszy na celu bez akceptowania lub przez naciśnięcie klawisza ESC odbywa się przez wywołanie CancelDrag. I jak już zauważyłeś, ta procedura nazywa się DragDone tylko wtedy, gdy DragObject <> nil. W ten sposób wydaje się, że DragObject jest zerowe, to już mówimy, że nie ma już operacji przeciągania (więcej).

Również twój obserwacja, że ​​źródło AV jest od tej konkretnej linii w Controls.DragTo wydaje się być błędne. W normalnej operacji przeciągania i upuszczania DragControl jest nil nie powoduje AV. Jednak po Controls.DragFindTarget może to być problematyczne w operacji przeciągania i dokowania, ale nie wspomniano o wykonywaniu dokowania.

Czy mógłbyś wyjaśnić, w jakiej sytuacji lub z jakim kodem pojawia się ten "błąd"?