Winapi C++;生成器:使用BorderStyle bsNone创建一个可移动且可调整大小的TForm

Winapi C++;生成器:使用BorderStyle bsNone创建一个可移动且可调整大小的TForm,winapi,c++builder,vcl,Winapi,C++builder,Vcl,我想要一个BorderStyle=bsNone(无边框,无标题)的TForm,它仍然可以调整大小和移动。我已经想出了如何做可调整大小的部分,但我坚持让它可移动 /** * Overrides standard CreateParams method to create a TForm with BorderStyle * bsNone but is nevertheless movable and resizable **/ void __fastcall CreateParams(T

我想要一个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;
}

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

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

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

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

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

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

要做到这一点,您需要响应,这是很容易做到的。此消息在多种情况下发送(不仅仅是鼠标单击或移动),因此不要假设用户在收到此消息时正在做什么。通过将消息结果设置为
HTCAPTION
,该值指示位置位于标题栏上方,来处理该消息

需要注意的重要事项是:

  • 该方法将为表单获取的每条消息调用;不要在这里做任何缓慢或复杂的事情
  • 始终让
    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;
        }
    }
}
void\uu fastcall TForm1::WndProc(Messages::TMessage&Message){
TForm::WndProc(Message);//继承的实现
如果(Message.Msg==WM\u NCHITTEST){
TWMNCHitTest&oMsg=重新解释广播(消息);
TPoint oPoint(oMsg.XPos,oMsg.YPos);//屏幕坐标
oPoint=ScreenToClient(oPoint);//现在以局部坐标的形式出现
//如果它位于表单顶部的矩形中,则它位于标题栏(标题)中
if((oPoint.x>0&&oPoint.x0&&oPoint.y<100))
{
oMsg.Result=HTCAPTION;
}
}
}

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

要做到这一点,您需要响应,这是很容易做到的。此消息在多种情况下发送(不仅仅是鼠标单击或移动),因此不要假设用户在收到此消息时正在做什么。通过将消息结果设置为
HTCAPTION
,该值指示位置位于标题栏上方,来处理该消息

需要注意的重要事项是:

  • 该方法将为表单获取的每条消息调用;不要在这里做任何缓慢或复杂的事情
  • 始终让
    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;
        }
    }
}
void\uu fastcall TForm1::WndProc(Messages::TMessage&Message){
TForm::WndProc(Message);//继承的实现
如果(Message.Msg==WM\u NCHITTEST){
TWMNCHitTest&oMsg=重新解释广播(消息);
TPoint oPoint(oMsg.XPos,oMsg.YPos);//屏幕坐标
oPoint=ScreenToClient(oPoint);//现在以局部坐标的形式出现
//如果它位于表单顶部的矩形中,则它位于标题栏(标题)中
if((oPoint.x>0&&oPoint.x0&&oPoint.y<100))
{
oMsg.Result=HTCAPTION;
}
}
}

最好提供一个
WM_NCHITTEST
处理程序,在其中表单应该是可移动的,而不是一个未记录的把戏。@Sertac Akyuz:好的,请提供更多关于您想法的信息?我真的不明白你的意思。@mort-看一个关于WM_NCHITTEST handler的例子。在
分派之后
可以执行,例如,
if(Pt。y@Sertac我想把这个问题作为一个答案来回答:“我不想打断你的观点,所以请把你的评论作为答案(也许是用代码例子或其他东西)。)戴维-请发表答案,AOFF我不是C++的人,甚至没有编译器。这就是我首先评论的原因。最好提供一个
WM_NCHITTEST
处理程序,在其中表单应该是可移动的,而不是一个未记录的技巧。@Sertac Akyuz:好的,请您提供一些关于您想法的更多信息?我真的不知道你的身份