c++builder如何通过鼠标拖动改变无边框窗体的大小(bsnone)

来源:互联网 发布:软件系统集成文档范例 编辑:程序博客网 时间:2024/05/01 06:37

转自http://www.ccrun.com/article.asp?i=990&d=70jx1b

在C++Builder中,将Form的BorderStyle设为bsNone以后该窗体将没有边框,不能改变窗体大小,也不能拖动窗体。那么如何拖动及用鼠标改变无边框窗体大小呢?拖动无边框窗体的解决方法很多,例如:
1. 向窗体发送WM_NCLBUTTONDOWN消息,LParam = HTCAPTION
2. 向窗体发送WM_SYSCOMMAND消息,LParam = SC_MOVE | HTCAPTION;
3. 截获WM_NCHITTEST消息,返回HTCAPTION让系统认为鼠标正在标题栏上
等等。更改窗体大小可以用API:SetWindowPos,那么用拖动鼠标来改变无边框窗体大小呢?答案还是WM_NCHITTEST。

在Windows系统中所有鼠标消息都要靠WM_NCHITTEST来建立,任何鼠标动作都会触发WM_NCHITTEST,触发次数和鼠标驱动程序每秒钟派发多少消息有关。以下代码是在程序中截获WM_NCHITTEST,ccrun(老妖)用C++Builder的方法实现的,通过重载WndProc来截获窗体消息,当然,还可以通过消息映射或接管WindowProc等来实现。另外特别说明的是:麻烦抄袭本站文章不爱留名的人不要搞错了,这不是纯C++的方法,请不要在抄袭的文章中用类似“C++中如何拖动无边框窗口”这样的标题来误导别人。类似的事情发生的太多了,顺便BS一下天极网抄袭不但不留原作者名字还篡改作者名字以及代码中的版权注释。
本代码应用在Delphi中的话,将语法略改变一下就可以了。

在单元文件的.h文件中加入:

private:    // User declarations
    void __fastcall WndProc(TMessage &Msg);

在单元文件的.cpp文件中加入:
// 重载窗体的WndProc实现截获窗体消息
void __fastcall TForm1::WndProc(TMessage &Msg)
{
    switch(Msg.Msg)
    {
    case WM_NCHITTEST: //
    {
        // 分解当前鼠标的坐标
        int nPosX = LOWORD(Msg.LParam); 
        int nPosY = HIWORD(Msg.LParam);
        if(nPosX >= Left + Width - 2 && nPosY >= Top + Height - 2)
        {
            // 鼠标位置在窗体的右下角附近
            Msg.Result = HTBOTTOMRIGHT;
            return;
        }        
        else if(nPosX >= Left + Width -2)
        {
            // 鼠标位置在窗体右侧
            Msg.Result = HTRIGHT;
            return;
        }
        else if(nPosY >= Top + Height - 2)
        {
            // 鼠标位置在窗体下方
// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=990&d=70jx1b
            Msg.Result = HTBOTTOM;
            return;
        }
        // 以上只判断鼠标位置是否在右侧,右下角,下方,所以仅仅当鼠标指针在这三个位置时才会改变成改变大小的形状,拖动后可改变大小。
        break;
    }
    default:
        break;
    }
    TForm::WndProc(Msg);
}
效果如图,为了方便大家看的清楚一些,ccrun(老妖)在窗体上放了一个Align=alClient的TShape,边框黑色,背景灰色。


如果程序中有多个窗体都是无边框风格,但都想用鼠标拖动来改变窗体大小的话,建议new一个窗体,设成无边框,截获WM_NCHITTEST消息实现可鼠标拖动大小,然后其他的窗体统一从这个窗体继承就可以了。不必在每个窗体中都重载WndProc,那样效率太低了。这样的设计方法可以延伸到其他方面,比如窗体控件的自绘,在父窗体中将代码写好,然后继承就是了。

附录:
/*
 * WM_NCHITTEST and MOUSEHOOKSTRUCT Mouse Position Codes
 */

#define HTERROR             (-2)
#define HTTRANSPARENT       (-1)
#define HTNOWHERE           0
#define HTCLIENT            1
#define HTCAPTION           2
#define HTSYSMENU           3
#define HTGROWBOX           4
#define HTSIZE              HTGROWBOX
#define HTMENU              5
#define HTHSCROLL           6
#define HTVSCROLL           7
#define HTMINBUTTON         8
#define HTMAXBUTTON         9
#define HTLEFT              10
#define HTRIGHT             11
#define HTTOP               12
#define HTTOPLEFT           13
#define HTTOPRIGHT          14
#define HTBOTTOM            15
#define HTBOTTOMLEFT        16
#define HTBOTTOMRIGHT       17
#define HTBORDER            18
#define HTREDUCE            HTMINBUTTON
#define HTZOOM              HTMAXBUTTON
#define HTSIZEFIRST         HTLEFT
#define HTSIZELAST          HTBOTTOMRIGHT
#if(WINVER >= 0x0400)
#define HTOBJECT            19
#define HTCLOSE             20
#define HTHELP              21
#endif /* WINVER >= 0x0400 */


例子:

void __fastcall TForm1::WndProc(TMessage &Msg){    switch(Msg.Msg)    {    case WM_NCHITTEST: //    {        // 分解当前鼠标的坐标        int nPosX = LOWORD(Msg.LParam);        int nPosY = HIWORD(Msg.LParam);        if ((nPosY <= Top  + 20) && (nPosX <= Left + Width - 90))        {             Msg.Result = HTCAPTION;             return;        }        if(nPosX >= Left + Width - 2 && nPosY >= Top + Height - 2)        {            // 鼠标位置在窗体的右下角附近            Msg.Result = HTBOTTOMRIGHT;            return;        }        else if(nPosX >= Left + Width -2)        {            // 鼠标位置在窗体右侧            Msg.Result = HTRIGHT;            return;        }        else if(nPosY >= Top + Height - 2)        {            // 鼠标位置在窗体下方// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=990&d=70jx1b            Msg.Result = HTBOTTOM;            return;        }        // 以上只判断鼠标位置是否在右侧,右下角,下方,所以仅仅当鼠标指针在这三个位置时才会改变成改变大小的形状,拖动后可改变大小。        break;    }    default:        break;    }    TForm::WndProc(Msg);}private:// User declarations  void __fastcall WndProc(TMessage &Msg);


0 0