松鼠的博客

导航

统计

如何通过鼠标拖动改变无边框窗体的大小

在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)
        
{
            
// 鼠标位置在窗体下方
            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 */

解决拖动后未清除边框线的问题:如果边框是自绘的,那么在改变窗体大小的时侯,以前的边框仍然没有消失。
(1)增加OnResize消息处理函数
(2)在OnResize消息处理函数里面重绘背景

void __fastcall TMainForm::FormResize(TObject *Sender)
{
    
this->Repaint();
}

 

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

posted on   Xproer-松鼠  阅读(1148)  评论(0编辑  收藏  举报

编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示