接着上文:这里写链接内容
我们来说说一个比较复杂的实现,
效果如图:

注意为了能够凸显没有NC(NotClient)区域,我们额外用了3个panel分别放在窗体的左右和下部。用来模拟客户自己的控件。
下面我们说下这种真正的无边框Form的实现方法
下面先无责任的贴下代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;using norlib;
using norlib.Controls;
using norlib.Error;
using norlib.Native;
using norlib.SystemExtension;namespace norlib.Controls
{public partial class BorderlessForm:Form{public BorderlessForm(){InitializeComponent();_caption = 0;_mp = new MousePreview(this);#region 初始化_dtCursor_dtCursor.Add(HT.HTBOTTOM, Cursors.SizeNS);_dtCursor.Add(HT.HTTOP, Cursors.SizeNS);_dtCursor.Add(HT.HTLEFT, Cursors.SizeWE);_dtCursor.Add(HT.HTRIGHT, Cursors.SizeWE);_dtCursor.Add(HT.HTTOPLEFT, Cursors.SizeNWSE);_dtCursor.Add(HT.HTTOPRIGHT, Cursors.SizeNESW);_dtCursor.Add(HT.HTBOTTOMLEFT, Cursors.SizeNESW);_dtCursor.Add(HT.HTBOTTOMRIGHT, Cursors.SizeNWSE);#endregion_mp.AddMouseMessage(WM.WM_LBUTTONDOWN, mp_LButtonDownPreview);_mp.AddMouseMessage(WM.WM_MOUSEMOVE, mp_MouseMovePreview);//不能选这个//this.Capture = true;         }public int Border{get { return _border; }set{if (value <= 0)return;_border = value;}}public int Caption{get { return _caption; }set { _caption = value; }}eMPResult mp_LButtonDownPreview(WM arg_wm, ref MOUSEHOOKSTRUCT argr_stInfo){var p = argr_stInfo.pt;var cp = this.PointToClient(new Point(p.x, p.y));var hc = _GetHT(cp, _border, _caption);if (hc != HT.HTERROR && hc != HT.HTCLIENT){Task.Factory.StartNew(() =>{this.BeginInvoke(new Action(()=>{NativeMethods.ReleaseCapture();NativeMethods.SendMessage(this.Handle, WM.WM_NCLBUTTONDOWN, (UIntPtr)hc, (IntPtr)0);}));});return eMPResult.CutOffMessage;}else{return eMPResult.ContinueHook;}}eMPResult mp_MouseMovePreview(WM arg_wm, ref MOUSEHOOKSTRUCT argr_stInfo){var p = argr_stInfo.pt;var cp = this.PointToClient(new Point(p.x, p.y));var hc = _GetHT(cp, _border, _caption);if (hc != HT.HTCLIENT && hc != HT.HTERROR){var c = _GetCursor(hc);if (Cursor != c)Cursor = c;return eMPResult.ContinueHook;}else{Cursor = Cursors.Default;return eMPResult.ContinueHook;}}HT _GetHT(Point arg_p, int arg_border, int arg_caption){var pos = arg_p;var border = arg_border;var caption = arg_caption;if (pos.X < 0 || pos.Y < 0){////非法位置//return HT.HTERROR;}else if (pos.X <= border){////左侧//if (pos.Y <= border){//左上侧return HT.HTTOPLEFT;}else if (pos.Y >= this.Height - border){//左下侧return HT.HTBOTTOMLEFT;}else{//左侧return HT.HTLEFT;}}else if (pos.X >= this.Width - border){////右侧//if (pos.Y <= border){//右上侧return HT.HTTOPRIGHT;}else if (pos.Y >= this.Height - border){//右下侧return HT.HTBOTTOMRIGHT;}else{//右侧return HT.HTRIGHT;}}else{////中部//if (pos.Y <= border){//上中侧return HT.HTTOP;}else if (pos.Y >= this.Height - border){//下中侧return HT.HTBOTTOM;}else if (pos.Y <= caption){return HT.HTCAPTION;}else{return HT.HTCLIENT;}}}Cursor _GetCursor(HT arg_ht){var cursor = (Cursor)null;if (_dtCursor.TryGetValue(arg_ht, out cursor)){return cursor;}else{return Cursors.Default;}}MousePreview _mp;readonly Dictionary<HT, Cursor> _dtCursor = new Dictionary<HT, Cursor>();int _border = 5;int _caption = 20;}
}

其主要思想是通过设置SetWindowsHookEx的WH_MOUSE来截获当前应用程序的鼠标事件。
随后我们对WM_LBUTTONDOWN的消息加点料

   var p = argr_stInfo.pt;var cp = this.PointToClient(new Point(p.x, p.y));var hc = _GetHT(cp, _border, _caption);if (hc != HT.HTERROR && hc != HT.HTCLIENT){Task.Factory.StartNew(() =>{this.BeginInvoke(new Action(()=>{NativeMethods.ReleaseCapture();NativeMethods.SendMessage(this.Handle, WM.WM_NCLBUTTONDOWN, (UIntPtr)hc, (IntPtr)0);}));});return eMPResult.CutOffMessage;}else{return eMPResult.ContinueHook;}
  • _GetHT函数用于计算客户点(cp)是属于哪一个区域,包括但不限于HT_CAPTION,HT_CLIENT,HT_HTLEFT.
    此函数主要通过给定的边框宽度border和给定的标题栏高度caption来确定NC(Not Client)区域的范围。(这里说一句题外话,如果你的border和caption设置的过大, 导致你的控件位于NC区域的部分将无法响应鼠标信息-_-#)

  • 接着说下去,点击区域位于我们认为的NC区域,我们截断此消息(Cut off message),否则放过此消息。截获消息的同时,异步发送WM_NCLBUTTONDOWN消息给窗体的消息处理函数,要求窗体处理NC消息

  • 这样初步完成了Broderless的效果。为了进一步完善鼠标显示的效果,可以截获WM.WM_MOUSEMOVE消息,随后显示对应的光标

说一下实际使用中,强烈不推荐使用Caption这个属性,建议这个属性设置为0,然后自己实现一个Caption的控件,捕获MouseDown,然后自己发送NC消息。因为如果你使用Caption的话,你都没法在Caption上弄个关闭按钮,所以我其实是这么搞得:

    public partial class FormBorderless2 : BorderlessForm{public FormBorderless2(){InitializeComponent();Border = 0;panelCaption.MouseDown += panelCaption_MouseDown;btnClose.Click += btnClose_Click;}void btnClose_Click(object sender, EventArgs e){this.Close();}void panelCaption_MouseDown(object sender, MouseEventArgs e){           if(e.Button == MouseButtons.Left){NativeMethods.ReleaseCapture();NativeMethods.SendMessage(this.Handle, WM.WM_NCLBUTTONDOWN, (UIntPtr)HT.HTCAPTION, (IntPtr)0);}}   }

我另外搞了一个panelCaption,来实现各种按钮以及Caption的效果。

最后贴一下MousePreivew的实现

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;using NM = norlib.Native.NativeMethods;
using norlib.Native;
using norlib.SystemExtension;namespace norlib.Controls
{    /// <summary>/// 精简的 NM.HOOKMOUSEPROC/// 1.去掉了HC nCode///   因为只响应HC.HC_ACTION/// 2.将UIntPtr wParam直接转化为WM///    方便用户使用/// 3.返回值的作用不同于NM.HOOKMOUSEPROC /// </summary>/// <param name="arg_wm"></param>/// <param name="stHookStruct"></param>/// <returns></returns>public delegate eMPResult MPMOUSEPROC(WM wm, ref MOUSEHOOKSTRUCT stHookStruct);public class MousePreview{                  /// <summary>/// 把相关的鼠标消息发送给此(控件/窗体)/// </summary>/// <param name="arg_parent">     /// </param>public MousePreview(Control arg_parent){if (null == arg_parent)throw new NotSupportedException(string.Format("{0}的构造函数不接受参数arg_parent为Null", typeof(MousePreview).Name));_hookProc = new NM.HOOKMOUSEPROC(_MyMouseProc);_hookHandler = NM.SetWindowsHookEx(WH.WH_MOUSE, _hookProc, 0, NM.GetCurrentThreadId());_parent = arg_parent;           }~MousePreview(){ReleasePreview();}      /// <summary>/// 将截获的消息改造,计算为适合此(控件/窗体)的正确格式后,/// 发送给此(控件/窗体)/// </summary>/// <param name="msg"></param>/// <param name="arg_mpc">/// 截获子(控件/窗体)或者仅截获顶层窗体的消息/// </param>/// <returns></returns>public bool AddMouseMessage(WM msg, eMPCategory arg_mpc = eMPCategory.Sub){try{if (null == _parent)return false;_dtCategory.Add(msg, arg_mpc);_dtWM.Add(msg, _DefaultMPMouseProc);return true;}catch (System.Exception ex){return false;}}public bool AddMouseMessage(WM msg, MPMOUSEPROC mouseProc, eMPCategory arg_mpc = eMPCategory.Sub){try{_dtCategory.Add(msg, arg_mpc);_dtWM.Add(msg, mouseProc);return true;}catch (System.Exception ex){return false;}}public void ReleasePreview(){if(_hookHandler != IntPtr.Zero){NM.UnhookWindowsHookEx(_hookHandler);_hookHandler = IntPtr.Zero;}}/// <summary>/// /// </summary>/// <param name="nCode"></param>/// <param name="wParam">/// 将要被传递的消息Id/// </param>/// <param name="stHookStruct"></param>/// <returns></returns>IntPtr _MyMouseProc(HC nCode, UIntPtr wParam, ref MOUSEHOOKSTRUCT stHookStruct){            if(nCode != HC.HC_ACTION)return NM.CallNextHookEx(_hookHandler, nCode, wParam, ref stHookStruct);var msg = (WM)wParam;var fn = (MPMOUSEPROC)null;if(!_dtWM.TryGetValue(msg, out fn))return NM.CallNextHookEx(_hookHandler, nCode, wParam, ref stHookStruct);var e = _dtCategory[msg];if(_parent != null && !_Belong(_parent, ref stHookStruct, e))return NM.CallNextHookEx(_hookHandler, nCode, wParam, ref stHookStruct);var r = fn(msg, ref stHookStruct);if (eMPResult.ContinueHook == r)return NM.CallNextHookEx(_hookHandler, nCode, wParam, ref stHookStruct);else if (eMPResult.CutOffMessage == r){               return (IntPtr)(int)-1;}else if (eMPResult.CutOffNextHook == r){return (IntPtr)0;}else{throw new NotImplementedException();}}     bool _Belong(Control arg_control, ref MOUSEHOOKSTRUCT stHookStruct, eMPCategory arg_e){var b = false;if(arg_e.HasFlag(eMPCategory.Sub)){b = b | ((IntPtr)stHookStruct.hWnd).Belong(arg_control, arg_e.HasFlag(eMPCategory.Myself)/*false*/);               }if (arg_e.HasFlag(eMPCategory.InRangeNoFocus)){var form = arg_control.GetRootForm();               if (!arg_control.IsDisposed &&stHookStruct.hWnd == arg_control.Handle &&(form.GetFocusedControl()==null) &&stHookStruct.pt.ToPoint().IsIn(arg_control, true)){                 b = b | true;}else{b = b | false;}}return b;}eMPResult _DefaultMPMouseProc(WM msg, ref MOUSEHOOKSTRUCT stHookStruct){var wParam = (UIntPtr)_GetKeyStates();var st = stHookStruct;      _parent.BeginInvoke(new Action(() =>{var p = _parent.PointToClient(new Point(st.pt.x, st.pt.y));var lParam = (IntPtr)(p.X + (p.Y << 16));                            Native.NativeMethods.SendMessage(_parent.Handle, msg, wParam, lParam);}));return eMPResult.ContinueHook;}int _GetKeyStates(){int retval = 0;if (NM.HIWORD(NM.GetKeyState(VK.VK_LBUTTON))> 0)retval += 1;if (NM.HIWORD(NM.GetKeyState(VK.VK_RBUTTON)) > 0)retval += 2;if (NM.HIWORD(NM.GetKeyState(VK.VK_SHIFT)) > 0)retval += 4;if (NM.HIWORD(NM.GetKeyState(VK.VK_CONTROL)) > 0)retval += 8;if (NM.HIWORD(NM.GetKeyState(VK.VK_MBUTTON)) > 0)retval += 16;if (NM.HIWORD(NM.GetKeyState(VK.VK_XBUTTON1)) > 0)retval += 32;if (NM.HIWORD(NM.GetKeyState(VK.VK_XBUTTON2)) > 0)retval += 64;return retval;}/// <summary>/// 把此(控件/窗体)的子控件消息传递给此父窗体/// </summary>Control _parent;NM.HOOKMOUSEPROC _hookProc;IntPtr _hookHandler;readonly Dictionary<WM, MPMOUSEPROC> _dtWM = new Dictionary<WM, MPMOUSEPROC>();readonly Dictionary<WM, eMPCategory> _dtCategory = new Dictionary<WM, eMPCategory>();}public enum eMPCategory:int{/// <summary>/// 所有子(控件/窗体)的消息发送给目标(控件/窗体)/// </summary>Sub = 1,/// <summary>/// 消息来源是没有Focus的Form下的目标(控件/窗体)的子控件/// 例如一个没有焦点的Form被客户点击了此Form中的子控件/// 一般用于捕获窗体的自定义Caption区域( 没有焦点的Form的子控件第一次被单击时,子控件没有OnMouseDown消息)/// InRange表示鼠标点击在目标(控件/窗体)/// NoFocus表示目标(控件/窗体)所在的Form没有焦点/// </summary>InRangeNoFocus = 2,/// <summary>/// Hook得到的消息是目标(控件/窗体)本身发送的数据是否也做进一步处理/// </summary>Myself = 4,All = Sub|InRangeNoFocus|Myself,}public enum eMPResult: int{/// <summary>/// 要求MousePreview不调用CallNextHookEx,直接返回-1,/// 告诉Windows不要将消息传递到stHookStruct.hWnd去/// </summary>CutOffMessage =-1,/// <summary>/// 0:要求MousePreview不调用CallNextHookEx, 直接返回0, /// Windows要将消息传递到stHookStruct.hWnd/// </summary>CutOffNextHook = 0,/// <summary>/// 要求MousePreview调用CallNextHookEx/// </summary>ContinueHook = 1,   }
}

转载于:https://www.cnblogs.com/norsd/p/6359304.html

如何实现一个无边框Form的移动和改变大小(二)相关推荐

  1. 2021-06-06 一个无边框可置顶的倒计时软件

    倒计时软件 显示效果如下,无边框,可置顶 通过设置程序生成的config.ini文件来修改显示的文字和deadline,也支持修改文字颜色.字体.字号.窗口显示的位置等要素. 倒计时结束后播放铃声提醒 ...

  2. css笔记:用css定义一个无边框的按钮

    测试代码 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8 ...

  3. C# 无边框异型窗体制作

    对于C# 更改窗体外观感觉并不那么轻松 更改窗体外观涉及到使用GDI+ 我所知道的有两种方法: 有系统边框的窗体  处理窗体的Paint方法,在paint方法中 参数e.Graphics属性将返回一个 ...

  4. 01.WPF中制作无边框窗体

    [引用:]http://blog.csdn.net/johnsuna/article/details/1893319 众所周知,在WinForm中,如果要制作一个无边框窗体,可以将窗体的FormBor ...

  5. PotPlayer 高逼格无边框的本地播放器

    PotPlayer 安装以及设置 可以在官网下载安装包:http://potplayer.daum.net 然后安装--运行-- 嗯,是的,PotPlayer的官方皮肤界面就是这么样貌平平,一点都不逼 ...

  6. Electron无边框窗口(最小化、最大化、关闭、拖动)以及动态改变窗口大小

    文章目录 一.目标原型 1. 目标 2. 原型设计 3. 原型初步实现 二.无边框窗口 1. 要点 2. 改造 三.可拖拽区 1. 要点 2. 改造 四.最小化.最大化.关闭 1. 要点 2. 改造 ...

  7. A7:Unity窗口化无边框模式

    将下面代码复制进入脚本里,然后随便放到一个物体上即可实现窗口化启动无边框哦~ using System; using System.Collections; using System.Runtime. ...

  8. QT 创建一个 可移动、可拉伸的无边框窗体

    在使用QT创建窗体的时候,为了使窗口美化,通常不使用QT自带的边框.会调用下面函数去除窗体边框. setWindowFlags(Qt::FramelessWindowHint) 但是有个问题,当去除了 ...

  9. Simple WPF:实现一个透明、无边框、鼠标穿透的WPF窗体

    WPF 透明窗体和鼠标事件穿透 一个自定义WPF窗体的解决方案,借鉴了吕毅老师的WPF制作高性能的透明背景的异形窗口一文,并在此基础上增加了鼠标穿透的功能.可以使得透明窗体的鼠标事件穿透到下层,在下层 ...

最新文章

  1. python安装win32api pywin32 后出现 ImportError: DLL load failed
  2. linux-压缩与解压缩(gz,zip,tar,jar,war)
  3. Python基础——PyCharm版本——第八章、文件I/O(核心3、csv和excel解析)
  4. https://cwiki.apache.org/confluence/display/FLINK/FLIP-24+-+SQL+Client
  5. 很全的路由器默认初始密码集合.txt_UpSet——集合关系可视化神器
  6. youcans 的 OpenCV 学习课—10. 图像复原与重建
  7. const 修饰函数参数,返回值,函数体,保护数据
  8. 计算机机房新风机管道布置要求,新风系统管道布置—新风系统管道布置连接方法介绍...
  9. IE、Firefox和 Chrome长时间打开后内存都会变很大。
  10. 系统分析师和系统架构设计师的主要区别是什么?
  11. Matlab中的画图函数
  12. 语义分割网络-Segnet
  13. OBS视频采集流程分析
  14. python 中 websocket实现消息定时推送
  15. vue在调用摄像头扫码(vue-qrcode-reader)
  16. 制作你软盘镜像_codestorm_新浪博客
  17. 在NS2 AODV协议中添加blackhole attacker(黑洞攻击) [转载]
  18. Linux查看流量情况以及关闭流量端口
  19. 亲测-分享最新微信付费进群收费进群系统源码-附带搭建教
  20. 加快MATLAB运行速度的三个方法

热门文章

  1. Theme与Style
  2. (二十四)解释器模式详解
  3. 启动fcgi处理进程
  4. bat脚本对文件目录的复制和移动
  5. 计算机显示器闪烁,电脑液晶显示器闪烁的解决办法 | Running Snail
  6. 31. phpstudy无法解析php2、php3、phtml等文件
  7. National Day meets Mid-autumn Festival
  8. 网络编程1 TCP服务器
  9. 06. 识别验证码逻辑
  10. 2022年Landsat8/9 Collection2数据 ENVI5.3打开(暴力打开,亲测有效)