【问题标题】:C++Builder: Create a TForm with BorderStyle bsNone that is nevertheless movable and resizableC++Builder:创建一个带有 BorderStyle bsNone 的 TForm,它仍然可以移动和调整大小
【发布时间】:2011-11-02 22:19:21
【问题描述】:

我想要一个带有 BorderStyle = bsNone(无边框,无标题)的 TForm,但它是可调整大小和可移动的。我已经想出了如何做可调整大小的部分,但我坚持让它可移动。

/**
*   Overrides standard CreateParams method to create a TForm with BorderStyle
*    bsNone but is nevertheless movable and resizable
**/
void __fastcall CreateParams(TCreateParams &Params)
{
    BorderStyle = bsNone;
    TForm::CreateParams(Params);
    //set flag WS_EX_STATICEDGE
    //for more details on this flag, see http://msdn.microsoft.com/en-us/library/ms632680(v=vs.85).aspx
    Params.ExStyle = Params.ExStyle ^ 0x00020000L;
    //set flag WS_SIZEBOX
    //for more details on this flag, see http://msdn.microsoft.com/en-us/library/ff700543(v=VS.85).aspx
    Params.Style = Params.Style ^ 0x00040000L;
}

这可能只是找到正确标志的问题。有什么想法吗?

【问题讨论】:

    标签: winapi c++builder vcl


    【解决方案1】:

    允许表单移动的最佳方式是模拟当您单击并拖动标题栏时表单的移动方式。由于您的窗口没有标题栏,因此当 Windows 需要知道鼠标光标在表单的哪个部分时,您会说谎并告诉 Windows 它确实在标题栏上方。之后,由于默认行为开始,移动正常工作。

    为此,您可以回复WM_NCHITTEST message,这很容易由overriding the form's WndProc method 完成。此消息在多种情况下发送(不仅仅是鼠标单击或移动),因此当您收到此消息时,不要假设用户在做什么。通过将消息结果设置为HTCAPTION来处理它,该值指示位置在标题栏上方。

    需要注意的重要事项有:

    • 表单收到的每条消息都会调用此方法;不要在这里做任何缓慢或复杂的事情。
    • 始终让WndProc 的默认继承实现处理消息。这对于大多数消息都是必不可少的,因为您只想更改此消息的行为,并且如果您不调用继承的植入,则消息根本不会发生任何事情,但这对于此消息也很重要,因为您不知道这条消息需要发送什么代码。即,您想添加程序对此的响应方式,而不是替换它。这是您拦截/添加的所有消息处理的一般良好指南。 WndProc 文档也提到了这一点。
    • 您可以通过检查鼠标坐标将表单的一个区域设置为可拖动位。在下面的代码中,只有窗体的前 100 个像素是可拖动的。

    示例代码:

    void __fastcall TForm1::WndProc(Messages::TMessage& Message) {
        TForm::WndProc(Message); // Inherited implementation
        if (Message.Msg == WM_NCHITTEST) {
            TWMNCHitTest& oMsg = reinterpret_cast<TWMNCHitTest&>(Message);
            TPoint oPoint(oMsg.XPos, oMsg.YPos); // Screen coordinates
            oPoint = ScreenToClient(oPoint); // Now in form-local coordinates
            // It's in the title bar (caption) if it's in a rectangle at the top of the form
            if ((oPoint.x > 0 && oPoint.x < ClientWidth) &&
                (oPoint.y > 0 && oPoint.y < 100))
            {
                oMsg.Result = HTCAPTION;
            }
        }
    }
    

    【讨论】:

    • 非常感谢!这是一个我真的很想奖励的答案,而不是赞成和接受!
    【解决方案2】:

    尝试将此代码放置到 Form OnMouseDown 事件处理程序中:

    ReleaseCapture();
    this->Perform(WM_SYSCOMMAND, 0xF012, 0);
    

    【讨论】:

    • 最好提供一个 WM_NCHITTEST 处理程序返回 HTCAPTION 表单应该是可移动的,而不是一个未记录的技巧。
    • @Sertac Akyuz:好的,请提供更多关于您的想法的信息?我真的不明白你的想法。
    • @mort - 查看this page 上的 WM_NCHITTEST 处理程序示例。在Dispatch 之后,您可以执行例如if(Pt.y&lt;21)Msg.Result=HTCAPTION;,其中Pt 是转换为客户端坐标的TPoint,ScreenToClient 在从Msg.LParam 分配的点上(低位字是x,高位字是y)。另请参阅this page,其中使用MapWindowPoints 代替 ScreenToClient。
    • @Sertac:我正要发布这个作为答案:) 我不想抓住你的观点,所以请添加你的评论作为答案(可能带有代码示例或其他东西。 )
    • @David - 请发布答案,AAMOF 我不是 C++ 人,甚至没有编译器,这就是我首先发表评论的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    • 2018-07-26
    • 2017-12-11
    • 1970-01-01
    相关资源
    最近更新 更多