Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi einfaches Drag & Drop und MouseUp (https://www.delphipraxis.net/193040-einfaches-drag-drop-und-mouseup.html)

Alex_ITA01 13. Jun 2017 14:50

einfaches Drag & Drop und MouseUp
 
Hallo,
ich habe schon zum Drag&Drop einiges gelesen und mitbekommen, dass es dann Probleme mit dem MouseUp gibt, wenn man dieses auch benötigt.

Delphi-Quellcode:
type
  TForm1 = class(TForm)
    Label1: TLabel;
    ListBox1: TListBox;
    procedure Label1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Label1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
    StartDragging: Boolean;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  StartDragging := False;
end;

procedure TForm1.Label1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  StartDragging := True;
  Label1.BeginDrag(False, 8);
  StartDragging := False;
end;

procedure TForm1.Label1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if StartDragging then
  begin
    ShowMessage('StartDragging=True');
    Exit;
  end;

  if Button = mbRight then
    ShowMessage('mbRight');

  if Button = mbLeft then
    ShowMessage('mbLeft');
end;

procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
  if Sender is TLabel then
  begin
    ListBox1.Items.Add(TLabel(Sender).Caption);
  end;
end;

procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
  if Sender is TLabel then
    Accept := True
  else
    Accept := False;
end;
Hier mal ein ganz einfaches Beispiel mit einem Label und einer ListBox.
Ich möchte eigentlich, die entsprechende ShowMessage erhalten wenn ich mit der linken oder rechten Maustaste drauf drücke bzw. das entsprechende DragEvent wenn ich es in die ListBox ziehe.

Hat jemand eine Idee wie man das hinbekommt?

SneakyBagels 13. Jun 2017 14:59

AW: einfaches Drag & Drop und MouseUp
 
Ich weiß nicht genau was dein Ziel ist. Aber das sieht doch mehr als kompliziert aus.

Versuchs mal hiermit:
Delphi-Quellcode:
// FormCreate
DragAcceptFiles(ListBox1.Handle, Accept);

function IsDirectory(const aFileName: string): Boolean;
var
 R: DWORD;
begin
 R := GetFileAttributes(PChar(aFileName));
 Result := (R <> DWORD(-1)) and ((R and FILE_ATTRIBUTE_DIRECTORY) <> 0);
end;

procedure DragDropHandleProcess(Wnd: HWND; aPath: string);
var
 bIsPath: Boolean;
begin
 bIsPath := IsDirectory(aPath);

 if bIsPath and (Wnd = ListBox1.Handle) then
  FListBox1.Items.Add(aPath);
end;

// ApplicationEvents aufs Form packen und OnMessage nutzen
const
 BufferLength = 255;
var
 QtyDroppedFiles, FileIndex: Integer;
 pDroppedFilename: array [0 .. BufferLength] of Char;
begin
WM_DROPFILES:
   begin
    QtyDroppedFiles := DragQueryFile(Msg.WParam, Cardinal(-1), nil, 0);

    try
     for FileIndex := 0 to QtyDroppedFiles - 1 do
      begin
       DragQueryFile(Msg.WParam, FileIndex, @pDroppedFilename, BufferLength);
       DragDropHandleProcess(Msg.HWND, PChar(@pDroppedFilename));
       Break;
      end;
    finally
     DragFinish(Msg.WParam);
     Handled := True;
    end;
   end;
end;

Alex_ITA01 13. Jun 2017 21:43

AW: einfaches Drag & Drop und MouseUp
 
Ich will keine Dateien irgendwo hin schieben sondern ein Drag Event von einer Komponente A zu einer Kompenente B realisieren und dabei muss A und B jeweils noch auf sein MouseUp reagieren können wenn die Maus auch tatsächlich losgelassen wurde. Dein Beispiel ist glaube ich nicht das was ich möchte. Hat noch jemand eine Idee?

Das mit dem Label und der Listbox ist nur ein Beispiel und könnte genauso gut etwas anderes sein was vom Typ TControl ist

Fritzew 13. Jun 2017 22:07

AW: einfaches Drag & Drop und MouseUp
 
Irgendwie verstehe ich das nicht...
1. Dein Beispiel kann nicht funktionieren da Du Source und Sender vertauschst.
2. Was willst Du wirklich erreichen? Ist mir nicht klar. Deine Variable StartDragging ist nutzlos, ich verstehe den Sinn nicht.

himitsu 13. Jun 2017 22:09

AW: einfaches Drag & Drop und MouseUp
 
MSDN-Library durchsuchenSetCapture

Aber eigentlich macht Windows das automatisch, für die Komponente, in in welcher die Maustaste runtergedrückt wurde,
womit dann die MouseMove und MouseButtonUp bei jener Komponente landen, auch wenn man die Maus aus der Komponente rausgeschoben hat.

Fritzew 13. Jun 2017 22:14

AW: einfaches Drag & Drop und MouseUp
 
Zitat:

Zitat von himitsu (Beitrag 1374453)
MSDN-Library durchsuchenSetCapture

Aber eigentlich macht Windows das automatisch, für die Komponente, in in welcher die Maustaste runtergedrückt wurde,
womit dann die MouseMove und MouseButtonUp bei jener Komponente landen, auch wenn man die Maus aus der Komponente rausgeschoben hat.

In der VCL? Das macht dieVCL selber, komplett unabhängig von Windows. Hier geht es nur um Vcl DragundDrop.
Das ist schon seit D1 so.

himitsu 13. Jun 2017 22:19

AW: einfaches Drag & Drop und MouseUp
 
VCL setzt auf Windows auf.
Wenn das VCL-D&D nicht mit ReleaseCapture dazwischenfunkt, dann bleibt das Verhalten ja so.
Mit SetCapture kann man selber einer oder keiner anderen Komponente den "MausFokus" geben, bzw. der Quellkomponente "wieder" den Fokus verpassen ... falls man damit dann das D&D der VCL nicht stört.

Und natürlich kann man ein Drag&Drop aus selber implementieren, ohne das "uralte" System der VCL zu nutzen.

Oder mit etwas Aufwand könnte man das Drag&Drop vom Windows auch nur programmintern nutzen.

Fritzew 13. Jun 2017 22:28

AW: einfaches Drag & Drop und MouseUp
 
Zitat:

Zitat von himitsu (Beitrag 1374455)
VCL setzt auf Windows auf.
Wenn das VCL-D&D nicht mit ReleaseCapture dazwischenfunkt, dann bleibt das Verhalten ja so.
Mit SetCapture kann man selber einer oder keiner anderen Komponente den "MausFokus" geben, bzw. der Quellkomponente "wieder" den Fokus verpassen ... falls man damit dann das D&D der VCL nicht stört.

Und natürlich kann man ein Drag&Drop aus selber implementieren, ohne das "uralte" System der VCL zu nutzen.

Da gebe ich Dir Recht, nur sollten wir vielleicht mal dem TE mitteilen dass er während dem Drag & Drop nicht auf eine andere Maustaste reagieren kann. Und ich denke nicht dass man SetCapture in dem Zusammenhang überhaupt erwähnen sollte.

Das kann richtig lustig werden... Ich habe hier eine 3D-Mouse mit 12!!! Tasten könnte ein neuer Anwendungsfall werden, mit Taste 1 starten und je nach Taste loslassen anders reagieren.

Alex_ITA01 14. Jun 2017 07:05

AW: einfaches Drag & Drop und MouseUp
 
Wieso vertausche ich Source und Sender?

Was ich erreichen will?
Ich habe eine Komponente A und will diese per Drag&Drop auf Komponente B verschieben. Natürlich will ich nicht die Komponente A auf B drauf schieben aber ich will bei dem Drop von B wissen ob der Sender=A war und natürlich auf alle Eigenschaften vom Sender (A) zugreifen. Gleichzeitig soll aber das MouseUp wirklich getriggert werden, wenn ich nur mit der linken oder rechten Maustaste auf Komponente A drücke.

Die Variable StartDragging ist dafür da, da das BeginDrag sofort ein MouseUp feuert aber die Maus ja gar nicht losgelassen wurde. Damit will ich nur sicherstellen, dass es sich in dem MouseUp Event nicht um das Standard-Event des BeginDrag geht.

Soweit verstanden?

Ich will einfach in diesem konkreten Beispiel, das das Label im MouseUp auf die linke und rechte Maustaste reagiert und gleichzeit ein Drag&Drop in die ListBox möglich ist und ich dort einfach die Caption des Labels adde...

Zitat:

Da gebe ich Dir Recht, nur sollten wir vielleicht mal dem TE mitteilen dass er während dem Drag & Drop nicht auf eine andere Maustaste reagieren kann.
Das ist mir klar, ich möchte ja am besten auch erst, dass das Drag&Drop startet, wenn ich die linke Maustaste drücke, gedrückt halte und die Maus verschiebe. Dann ist alles gut. Wenn ich aber die Linke/Rechte Maustaste drücke und sofort wieder loslasse, dann will ich natürlich das normale MouseUp mit der entsprechenden Übergabe der gedrückten Maustaste

jaenicke 14. Jun 2017 07:39

AW: einfaches Drag & Drop und MouseUp
 
Das ganze ist im Grunde recht einfach:
Du darfst nicht beim Drücken der Maustaste sofort einen Dragvorgang beginnen, denn das löst sofort das MouseUp aus. Stattdessen musst du das MouseMove benutzen und erst nach einer Bewegung mit gedrückter Maustaste (ggf. mit Toleranz von ein paar Pixeln) den Dragvorgang auslösen.

Außerdem benutzt du in ListBox1DragDrop und ListBox1DragOver wie schon genannt Sender (die Ereignisquelle für die Mausaktion, also die Listbox) statt Source (der Dragquelle, also das Label).

// EDIT:
Sprich:
Delphi-Quellcode:
procedure TForm1.Label1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  if ssLeft in Shift then // ggf. noch beim MouseDown die X- und Y-Koordinaten speichern und hier die Differenz ermitteln
  begin
    StartDragging := True;
    Label1.BeginDrag(False, 8);
    StartDragging := False;
  end;
end;

procedure TForm1.Label1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if not StartDragging then
  begin
    if Button = mbRight then
      ShowMessage('mbRight');

    if Button = mbLeft then
      ShowMessage('mbLeft');
  end;
end;

procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
  if Source is TLabel then
  begin
    ListBox1.Items.Add(TLabel(Source).Caption);
  end;
end;

procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
  if Source is TLabel then
    Accept := True
  else
    Accept := False;
end;

Alex_ITA01 14. Jun 2017 07:46

AW: einfaches Drag & Drop und MouseUp
 
Oh jetzt sehe ich was ihr meintet mit der Vertauschung. Stimmt habe Sender mit Source vertauscht, mein Fehler.
Ich versuche das mal mit dem MouseMove, dachte es würde für diesen Fall noch "Bordmittel" geben ;-)

Danke für deine Änderung, habe Sie erst jetzt gesehen ;-)

Fritzew 14. Jun 2017 07:59

AW: einfaches Drag & Drop und MouseUp
 
Aus der Hilfe:
Zitat:

Mit BeginDrag kann das Ziehen eines Steuerelements gestartet werden. Die Methode wird in einer Anwendung nur explizit aufgerufen, wenn die Eigenschaft DragMode des betreffenden Steuerelements den Wert dmManual hat. Bei der Einstellung dmAutomatic wird BeginDrag automatisch aufgerufen.

Wenn der Parameter Immediate true ist, wird dem Mauszeiger die Cursorform der Eigenschaft DragCursor zugewiesen und der Ziehvorgang umgehend gestartet. Hat Immediate den Wert false, wird die Form des Mauszeigers nicht geändert und das Ziehen erst begonnen, wenn der Benutzer den Mauszeiger um die in Threshold angegebene Pixelanzahl verschiebt. Ist Threshold kleiner als 0, wird der Wert aus der Eigenschaft DragThreshold der globalen Variable Mouse gelesen.

Durch Setzen von Immediate auf false kann das Steuerelement Mausklicks entgegennehmen, ohne dass eine Drag&Drop- oder Drag&Dock-Operation begonnen wird.
Es reicht also wenn Du Threshold setzt. Allerdings wird von BeginDrag sofort ein WM_LBUTTONUP an das Label geschickt siehe:

in BeginDrag:

Delphi-Quellcode:
  if csLButtonDown in ControlState then
    begin
      GetCursorPos(P);
      Perform(WM_LBUTTONUP, 0, PointToLParam(ScreenToClient(P)));
    end;
Dadurch wird Dein Flag StartDragging immer true sein im MouseUp.

Alex_ITA01 14. Jun 2017 08:28

AW: einfaches Drag & Drop und MouseUp
 
Nicht wenn ich im MouseMove das so mache:

Delphi-Quellcode:
if (ssLeft in Shift) and
   ((Abs(LastPoint.X - X) > 6) or
    (Abs(LastPoint.Y - Y) > 6)) then
begin
  StartDragging := True;
  Label1.BeginDrag(False, 8);
  StartDragging := False;
end;
LastPoint wurde im MouseDown gesetzt.
Damit ist StartDragging nicht immer True im MouseUp

Fritzew 14. Jun 2017 08:39

AW: einfaches Drag & Drop und MouseUp
 
Delphi-Quellcode:
if (ssLeft in Shift) and
   ((Abs(LastPoint.X - X) > 6) or
    (Abs(LastPoint.Y - Y) > 6)) then
begin
  StartDragging := True;
  Label1.BeginDrag(False, 8);
  StartDragging := False;
end;
Ich würde aber in dem Fall
Delphi-Quellcode:
 Label1.BeginDrag(true);
aufrufen. Sonst muss der User noch mal um 8 pixel verschieben :-)

Alex_ITA01 14. Jun 2017 08:41

AW: einfaches Drag & Drop und MouseUp
 
Eine Frage hätte ich dennoch:
Im Windows kann man ja während man ein Ordner oder ähnliches gedraggt hat (noch nicht losgelassen!) mit der STRG Taste umschalten zwischen verschieben oder kopieren. Das müsste ja dann beim DragDropEvent abgefragt werden können. Wisst ihr wie ich da ran komme an die Info, ob das DragDropEvent mit gedrückter oder nicht gedrückter STRG Taste durchgeführt wurde?

Edit:
Fritzew: Da hast du Recht :-D

Fritzew 14. Jun 2017 08:57

AW: einfaches Drag & Drop und MouseUp
 
Zitat:

Eine Frage hätte ich dennoch:
Im Windows kann man ja während man ein Ordner oder ähnliches gedraggt hat (noch nicht losgelassen!) mit der STRG Taste umschalten zwischen verschieben oder kopieren. Das müsste ja dann beim DragDropEvent abgefragt werden können. Wisst ihr wie ich da ran komme an die Info, ob das DragDropEvent mit gedrückter oder nicht gedrückter STRG Taste durchgeführt wurde?
Kannst Du abfragen mit
Delphi-Quellcode:
if GetKeyState(VK_CONTROL) < 0 then

Alex_ITA01 14. Jun 2017 09:14

AW: einfaches Drag & Drop und MouseUp
 
Geht, vielen Dank!


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:14 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz