-1

I have this code from the internet to drag a borderless form by holding the Left mouse button down:

procedure TForm6.Image1MouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState;X,Y: Integer);
const
  SC_DRAGMOVE = $F012;
begin
  if Button = mbLeft then
  begin
    ReleaseCapture;
    Perform(WM_SYSCOMMAND, SC_DRAGMOVE, 0);
  end;
end;

It works fine but I need to drag by Right mouse button. Which parameter must be changed for this?

AmigoJack
  • 5,234
  • 1
  • 15
  • 31
JimPapas
  • 715
  • 2
  • 12
  • 27
  • Even if you change `mbLeft` to `mbRight`, the `SC_DRAGMOVE` is asking the OS to perform the actual drag, and the right button isn't usually used for dragging. Haven't tested yet if this actually works as expected or not – Remy Lebeau Jul 09 '23 at 15:42
  • @silverWarior. I do not understand what you mean! Should I just change the control button = mbLeft to button = mbRight ? If yes then you are wrong because this doesn't work! – JimPapas Jul 09 '23 at 15:53
  • 1
    I don't understand why some people downvoted my question. I need the right mouse button for dragging because I use the left for other functions and the right not at all. If it is not possible I will have to make serious changes to the code and I try to avoid that. – JimPapas Jul 09 '23 at 16:01
  • I downvoted because of the most vague source description "_from internet_" without further link and for not including what you attempted so far yourself (which surprisingly is revealed only if you make comments). You also only write "_drag a borderless form_" without actually specifying that it must work on a visual component. That's all very lazy. – AmigoJack Jul 09 '23 at 17:25
  • @AmigoJack. Ok, my description wasn't what you wanted but the question is still valid and maybe someone else needs the answer. Wouldn't it be better to express your objections with a comment instead of a downvote? and maybe you contributed to the solution of the question? why this negative behavior? – JimPapas Jul 09 '23 at 17:50
  • I'm negative because your past questions and answers lack effort, too. You even almost never accept an answer and didn't want to improve from past comments. Your description was not not what I wanted - it was not what **anybody** wanted. On top this sounds like an [XY problem](https://en.wikipedia.org/wiki/XY_problem). – AmigoJack Jul 09 '23 at 19:29
  • It seems that Windows only supports dragging for windows only with the primary mouse button. So I'm afraid you won't be able to use right mouse button for dragging. Alternatively you could make use of Shift state and thus begin dragging of your form only when specific modifier key is being pressed. For instance by using `if (Button = mbLeft) and (ssAlt in Shift) then` user needs to use **ALT + LeftClick** in order to start dragging the form so you could still rely on left mouse button dragging. – SilverWarior Jul 09 '23 at 19:37

2 Answers2

1

How to move window by right mouse button using C++? has a solution which handles the dragging itself, instead of letting Windows do it. Projecting that work from MFC needs one to know what Delphi's Forms already handle, instead of overly calling WinApi functions.

One major issue is to incorporate a window's caption height, which can rely on multiple factors. In my example I used a normal one for a sizable window and it works as expected using Windows 7 without any theme (looks like Windows 95). Having no caption, or having a tool window, or having no border, or having a window which can't be sized needs the calls to GetSystemMetrics() adjusted.

I incorporated both: dragging by left mouse button and by right mouse button. Although I encourage still displaying a potential context menu at the end of the dragging (like the Explorer does so for dragging files), because it's still a right mouse button and every user expects a popup menu for that click.

My example also works for both: bound to either a TWinControl or to the TForm itself.

unit Unit1;

interface

uses
  Windows, Messages, Classes, Controls, Forms, ExtCtrls;

const
  SC_DRAGMOVE=         SC_MOVE or $0002;  // The four low-order bits of the wParam parameter are used internally by the system
  SM_CXPADDEDBORDER=   92;

type
  TForm1= class( TForm )
    Panel1: TPanel;
    procedure Panel1MouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
    procedure FormMouseMove( Sender: TObject; Shift: TShiftState; X, Y: Integer );
    procedure FormMouseUp( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
  private
    vStart: TPoint;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// Mouse button is pressed down and held
procedure TForm1.Panel1MouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
begin
  case Button of
    mbLeft: begin  // Dragging through left mouse button
      ReleaseCapture();  // Restore normal mouse input processing; self.MouseCapture is already FALSE at this point
      self.Perform( WM_SYSCOMMAND, SC_DRAGMOVE, 0 );  // Handles all the rest of dragging the window
    end;

    mbRight: begin  // Through right mouse button
      GetCursorPos( self.vStart );  // Remember position on form, relative to screen
      self.vStart:= self.ScreenToClient( self.vStart );
      Inc( self.vStart.Y, GetSystemMetrics( SM_CYCAPTION )  // Window title height
                        + GetSystemMetrics( SM_CXPADDEDBORDER )  // Width of potential border padding
                        + GetSystemMetrics( SM_CYSIZEFRAME )  // Height of a potential window border when sizable; SM_CYEDGE is not enough
      );

      self.MouseCapture:= TRUE;  // WinApi: SetCapture( Handle )
    end;
  end;
end;

// Mouse is moved, unrelated to button status; must be handled by form, not panel
procedure TForm1.FormMouseMove( Sender: TObject; Shift: TShiftState; X, Y: Integer );
var
  pt: TPoint;
begin
  if self.MouseCapture then begin  // WinApi: GetCapture()= Handle
    GetCursorPos( pt );  // Position on desktop

    Dec( pt.X, self.vStart.X );  // Subtract relative starting position
    Dec( pt.Y, self.vStart.Y );

    MoveWindow( self.Handle, pt.X, pt.Y, self.Width, self.Height, TRUE );  // Reposition window by horizontal and vertical deltas
  end;
end;

// Mouse button is released; must be handled by form, not panel
procedure TForm1.FormMouseUp( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
begin
  if Button= mbRight then self.MouseCapture:= FALSE;  // End dragging
end;

Note that initiating the dragging is bound to the control's OnMouseDown event, but handling and ending the dragging must be bound to the form's events:

object Form1: TForm1
  OnMouseMove = FormMouseMove
  OnMouseUp = FormMouseUp
  object Panel1: TPanel
    OnMouseDown = Panel1MouseDown
  end
end
AmigoJack
  • 5,234
  • 1
  • 15
  • 31
  • Yes! that was what I needed. I upvoted your solution but I don't know how to mark as accepted. – JimPapas Jul 09 '23 at 21:44
  • Have a read on [What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers) and [How does accepting an answer work?](https://meta.stackexchange.com/a/5235) on how to click on the ✅︎ check mark. Go trough your other questions to also accept answers there. [You already achieved this in January](https://stackoverflow.com/a/75127408/4299358) but forgot it again...? – AmigoJack Jul 09 '23 at 21:59
  • I've forgot it! I'm an enthusiastic weekend hobbyist and an old man, so please bear with my mistakes. Thanks again. – JimPapas Jul 10 '23 at 08:35
0

It could be done in another way.

In interface section:

  TMyForm = class(TForm)
  private
    procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;
  end;

In implementation section:

procedure TMyForm.WMNCHitTest(var Msg: TWMNCHitTest);
begin
    inherited;   
    Msg.Result := HTCAPTION;
end;
dwrbudr
  • 607
  • 4
  • 8
  • 2
    And that does work with the RIGHT mouse button as requested? – Uwe Raabe Jul 09 '23 at 12:26
  • @UweRaabe I doubt it (but haven't tested it) because the right button isn't usually tracked for dragging purposes – Remy Lebeau Jul 09 '23 at 15:37
  • It doesn't work either with left or right button if the mouse is over another component. It works only if I hit at the form's area. And of cοurse only with left button. – JimPapas Jul 09 '23 at 16:06