Einzelnen Beitrag anzeigen

Aviator

Registriert seit: 3. Jun 2010
1.611 Beiträge
 
Delphi 10.3 Rio
 
#8

AW: VirtualStringTree Drag & Drop

  Alt 3. Mär 2017, 14:33
Hallo Towmuz,

habe mich jetzt mal etwas länger durch den VST Source geklickt und gedebuggt. Hat erst noch etwas gedauert, bis ich dein Problem richtig nachvollziehen konnte.

Schlussendlich habe ich aber deinen Übeltäter gefunden und kann nur sagen, dass ist as designed. Warum? Kein Ahnung. Eventuell kannst du ja was daraus bauen.

Die von dir gedachte HitInfo macht dir das Problem eher nicht. Der Fehler tritt schon früher auf.

Folgende Methode macht dir einen Strich durch die Rechnung:

Delphi-Quellcode:
function TCustomVirtualStringTree.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer;

// Returns the text width of the given node in pixels.
// This width is stored in the node's data member to increase access speed.

var
  Data: PInteger;

begin
  if (Column > NoColumn) and (vsMultiline in Node.States) then /////// HIER IST DEIN PROBLEM
    Result := FHeader.Columns[Column].Width /////// DIE ZURÜCKGEGEBENE TEXTBREITE ENTSPRICHT IMMER DER BREITE DER AKTUELLEN COLUMN
  else
  begin
    if Canvas = nil then
      Canvas := Self.Canvas;

    if Column = FHeader.MainColumn then
    begin
      // Primary column or no columns.
      Data := InternalData(Node);
      if Assigned(Data) then
      begin
        Result := Data^;
        if Result = 0 then
        begin
          Data^ := CalculateTextWidth(Canvas, Node, Column, Text[Node, Column]);
          Result := Data^;
        end;
      end
      else
        Result := 0;
    end
    else
      // any other column
      Result := CalculateTextWidth(Canvas, Node, Column, Text[Node, Column]);
  end;
end;

Die Folge daraus ist, dass in der Procedure TBaseVirtualTree.DetermineHitPositionLTR(var HitInfo: THitInfo; Offset, Right: Integer; Alignment: TAlignment); das Flag hiOnItemLabel gesetzt wird:

Delphi-Quellcode:
TextWidth := DoGetNodeWidth(HitInfo.HitNode, HitInfo.HitColumn);

// Check if the text can be aligned at all. This is only possible if there is enough room
// in the remaining text rectangle.
if TextWidth > Right - ImageOffset then
  Include(HitInfo.HitPositions, hiOnItemLabel)
else
begin
  ...
end;
Und in der function TBaseVirtualTree.DetermineDropMode(const P: TPoint; var HitInfo: THitInfo; var NodeRect: TRect): TDropMode; wird dann der entsprechende DropMode gesetzt. Bitte die Kommentare hinter den Code Zeilen beachten!

Delphi-Quellcode:
function TBaseVirtualTree.DetermineDropMode(const P: TPoint; var HitInfo: THitInfo; var NodeRect: TRect): TDropMode;
// Determine the DropMode.

var
  ImageHit: Boolean;
  LabelHit: Boolean;
  ItemHit: Boolean;

begin
  ImageHit := HitInfo.HitPositions * [hiOnNormalIcon, hiOnStateIcon] <> [];
  LabelHit := hiOnItemLabel in HitInfo.HitPositions; /////// Hier wird dann LabelHit auf true gesetzt
  ItemHit := ((hiOnItem in HitInfo.HitPositions) and
             ((toFullRowDrag in FOptions.FMiscOptions) or (toFullRowSelect in FOptions.FSelectionOptions)));

  // In report mode only direct hits of the node captions/images in the main column are accepted as hits.
  if (toReportMode in FOptions.FMiscOptions) and not (ItemHit or ((LabelHit or ImageHit) and
    (HitInfo.HitColumn = FHeader.MainColumn))) then
    HitInfo.HitNode := nil;

  if Assigned(HitInfo.HitNode) then
  begin
    if LabelHit or ImageHit or not (toShowDropmark in FOptions.FPaintOptions) then /// Hier springt er dann immer auf DropMode dmOnNode
      Result := dmOnNode
    else
      if ((NodeRect.Top + NodeRect.Bottom) div 2) > P.Y then
        Result := dmAbove
      else
        Result := dmBelow;
  end
  else
    Result := dmNowhere;
end;

Ich hoffe ich konnte dir mit dieser Info weiterhelfen.
  Mit Zitat antworten Zitat