在 Delphi 中用鼠标右键单击移动无边框表单

Move borderless form with right mouse button in Delphi

提问人:JimPapas 提问时间:7/9/2023 最后编辑:AmigoJackJimPapas 更新时间:7/10/2023 访问量:245

问:

我从互联网上有这个代码,可以通过按住鼠标按钮来拖动无边框表单:Left

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;

它工作正常,但我需要用鼠标按钮拖动。为此必须更改哪个参数?Right

Delphi 鼠标 动 MoveWindow

评论

0赞 Remy Lebeau 7/9/2023
即使更改为 ,也会要求操作系统执行实际的拖动,并且右键通常不用于拖动。尚未测试这是否真的按预期工作mbLeftmbRightSC_DRAGMOVE
0赞 JimPapas 7/9/2023
@silverWarior。我不明白你的意思!我应该将控制按钮 = mbLeft 更改为按钮 = mbRight 吗?如果是,那么你就错了,因为这不起作用!
1赞 JimPapas 7/10/2023
我不明白为什么有些人对我的问题投了反对票。我需要鼠标右键进行拖动,因为我使用左键进行其他功能,而右键根本不使用。如果不可能,我将不得不对代码进行重大更改,并尽量避免这种情况。
0赞 AmigoJack 7/10/2023
我投了反对票,因为最模糊的来源描述“来自互联网”,没有进一步的链接,也没有包括你自己到目前为止尝试的内容(令人惊讶的是,只有当你发表评论时才会显示)。您也只编写“拖动无边框窗体”,而没有实际指定它必须在可视组件上工作。这都是非常懒惰的。
0赞 JimPapas 7/10/2023
@AmigoJack。好吧,我的描述不是你想要的,但这个问题仍然有效,也许其他人需要答案。用评论而不是反对票来表达您的反对意见不是更好吗?也许你为这个问题的解决做出了贡献?为什么会有这种负面行为?

答:

0赞 dwrbudr 7/9/2023 #1

这可以通过另一种方式完成。

在界面部分:

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

在实施部分:

procedure TMyForm.WMNCHitTest(var Msg: TWMNCHitTest);
begin
    inherited;   
    Msg.Result := HTCAPTION;
end;

评论

2赞 Uwe Raabe 7/9/2023
这确实可以按照要求使用鼠标右键吗?
0赞 Remy Lebeau 7/9/2023
@UweRaabe 我对此表示怀疑(但尚未测试过),因为通常不会出于拖动目的跟踪右按钮
0赞 JimPapas 7/10/2023
如果鼠标放在另一个组件上,则它不适用于左键或右键。只有当我击中表单的区域时,它才有效。并且只有左按钮。
1赞 AmigoJack 7/10/2023 #2

如何使用C++通过鼠标右键单击移动窗口?有一个解决方案可以处理拖动本身,而不是让 Windows 来做。从 MFC 预测工作需要知道 Delphi 的 Forms 已经处理了什么,而不是过度调用 WinApi 函数。

一个主要问题是合并窗口的标题高度,这可能取决于多种因素。在我的示例中,我为一个相当大的窗口使用了一个普通的窗口,它使用没有任何主题的 Windows 7(看起来像 Windows 95)按预期工作。没有标题,或者有工具窗口,或者没有边框,或者有一个无法调整大小的窗口,需要调整对 GetSystemMetrics() 的调用。

我合并了两者:用鼠标左键和鼠标右键拖动。尽管我仍然鼓励在拖动结束时显示一个潜在的上下文菜单(就像资源管理器在拖动文件时所做的那样),因为它仍然是一个鼠标右键,并且每个用户都希望该单击有一个弹出菜单

我的示例也适用于两者:绑定到 a 或 本身。TWinControlTForm

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;

请注意,启动拖动绑定到控件的事件,但处理和结束拖动必须绑定到窗体的事件:OnMouseDown

object Form1: TForm1
  OnMouseMove = FormMouseMove
  OnMouseUp = FormMouseUp
  object Panel1: TPanel
    OnMouseDown = Panel1MouseDown
  end
end

评论

0赞 JimPapas 7/10/2023
是的!这就是我需要的。我支持您的解决方案,但我不知道如何标记为已接受。
0赞 AmigoJack 7/10/2023
阅读 当有人回答我的问题时,我该怎么办? 以及 接受答案如何运作? 关于如何单击 ✅︎ 复选标记。通过你的其他问题,也接受那里的答案。你在一月份就已经做到了,但又忘记了......?
0赞 JimPapas 7/10/2023
我忘了!我是一个狂热的周末爱好者,也是一个老人,所以请耐心等待我的错误。再次感谢。