zoukankan      html  css  js  c++  java
  • WinForms形成皮肤

    介绍 SkinForm类允许您创建自定义皮肤。net WinForms表单对象,对象多达你想补充道,并处理许多事件(如鼠标、键盘和油漆)对你的皮肤像你使用标准的控制。 背景 很多WinForms应用程序有自己的皮肤有更好的外观和感觉与标准相比WinForms的皮肤。也少的WinForms应用程序有用我们的应用程序中,这是地方放置表单的文本和系统按钮(在我的环境中,我称之为酒吧形式)。此外,改善我们的外观和感觉,更好地利用屏幕的面积可以给我们一个特殊的点。所以,我们为什么不尝试创建更好的自己吗? 预览 自定义皮肤(AiSkin): 自定义皮肤(AiSkin)额外的自定义按钮放置在系统按钮: 自定义皮肤(AiSkin)额外的自定义按钮放置在系统按钮,和选项卡: 主要的对象 有几类皮肤(在Ai。控制命名空间): 主要课程: SkinForm类。 这是主要的类来管理皮肤和皮肤之间的联系形式。 FormHook类。 从NativeWindow继承类。定意把消息处理通过指向剥皮的形式。这个类包含在SkinForm类。 SkinBase类。 基类皮肤管理。这个类包含皮肤的变量信息,被FormHook类和函数来处理消息。 BarFormButton类。 类代表一个按钮将被放置在酒吧的形式。 MinimizeButton类。 继承自BarFormButton,代表了最小化按钮的形式。 MaximizeButton类。 继承自BarFormButton,表示表单的最大化按钮。 CloseButton类。 继承BarFormButton,代表了关闭按钮的形式。 其他类: CustomButton类。 继承自BarFormButton,代表了一个自定义按钮的形式。 TabFormButton类。 类代表一个选项卡按钮,将放在吧台形式。BarFormButtonCollection类。 代表BarFormButton对象的集合。这个集合不能包含MinimizeButton之一,MaximizeButton或CloseButton。 TabFormButtonCollection类。 代表TabFormButton对象的集合。 Win32API类。 封装结构、外部函数和常量用于win32 API调用。 示例类: AiSkin类。 SkinBase的实现类,支持标签和自定义按钮。 创建和使用自己的自定义皮肤,创建一个类,继承SkinBase类,创建一个SkinForm类的实例并定制皮肤类在WinForms表单对象,并设置形式和皮肤SkinForm实例的属性的实例WinForms形式和定制皮肤的实例,如下: 隐藏,复制Code

    public class YourSkin : SkinBase
    {
    	// your implementation here
    }
    
    public class YourForm : System.Windows.Forms.Form
    {
    	public YourForm()
    	{
    		// Create an instance of SkinForm class.
    		SkinForm sf = new SkinForm();
    		// Create an instance of YourSkin class.
    		YourSkin skin = new YourSkin();
    		// Sets both Form and Skin property of sf.
    		sf.Skin = skin;
    		sf.Form = this;
    	}
    }

    简要描述 以下是简短的解释重要的事情来开发定制的皮肤。 FormHook 这个类的目的是把剥了皮的窗口消息处理形式通过其指向功能。这个类将提供皮肤所需的任何事件的过程。对于键盘消息处理,这类使用windows原始输入功能。剥了皮的形式将注册接收原始表单的输入消息HandleCreated事件时触发。 隐藏,复制Code

    private class FormHook : NativeWindow
    {
    	// ...
    	/// <summary>
    	/// Called when the handle of the form is created.
    	/// </summary>
    	private void form_HandleCreated(object sender, EventArgs e)
    	{
    		AssignHandle(((Form)sender).Handle);
    		// Registering form for raw input
    		Win32API.RAWINPUTDEVICE[] rid = new Win32API.RAWINPUTDEVICE[1];
    		rid[0].usUsagePage = 0x01;
    		rid[0].usUsage = 0x06;
    		rid[0].dwFlags = Win32API.RIDEV_INPUTSINK;
    		rid[0].hwndTarget = ((Form)sender).Handle;
    		_RIDRegistered = Win32API.RegisterRawInputDevices
                            (rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]));
    		if (isProcessNCArea()) 
    		{
    			updateStyle();
    			updateCaption();
    		}
    	}
    }

    窗口消息连接过程发生在指向这个类的函数。 隐藏,收缩,复制Code

    private class FormHook : NativeWindow
    {
    	// ...
    
    	/// <summary>
    	/// Invokes the default window procedure associated with this window.
    	/// </summary>
    	[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    	protected override void WndProc(ref Message m) {
    		bool suppressOriginalMessage = false;
    		switch (m.Msg) { 
    			case Win32API.WM_STYLECHANGED:
    				updateStyle();
    				if (_owner._skin != null) _owner._skin.setRegion(_owner._form.Size);
    				break;
    			#region Form Activation
    			case Win32API.WM_ACTIVATEAPP:
    				if (_owner._skin != null) _owner._skin.FormIsActive = (int)m.WParam != 0;
    				onNCPaint(true);
    				break;
    			case Win32API.WM_ACTIVATE:
    				if (_owner._skin != null) _owner._skin.FormIsActive = 
                             ((int)Win32API.WA_ACTIVE == (int)m.WParam || 
                                     (int)Win32API.WA_CLICKACTIVE == (int)m.WParam);
    				onNCPaint(true);
    				break;
    			case Win32API.WM_MDIACTIVATE:
    				if (m.WParam == _owner._form.Handle) {
    					if (_owner._skin != null) _owner._skin.FormIsActive = false;
    				} else if (m.LParam == _owner._form.Handle) {
    					if (_owner._skin != null) _owner._skin.FormIsActive = true;
    				}
    				onNCPaint(true);
    				break;
    			#endregion
    			#region Mouse Events
    			case Win32API.WM_NCLBUTTONDOWN:
    			case Win32API.WM_NCRBUTTONDOWN:
    			case Win32API.WM_NCMBUTTONDOWN:
    				suppressOriginalMessage = onNCMouseDown(ref m);
    				break;
    			case Win32API.WM_NCLBUTTONUP:
    			case Win32API.WM_NCMBUTTONUP:
    			case Win32API.WM_NCRBUTTONUP:
    				suppressOriginalMessage = onNCMouseUp(ref m);
    				break;
    			case Win32API.WM_NCMOUSEMOVE:
    				suppressOriginalMessage = onNCMouseMove(ref m);
    				break;
    			case Win32API.WM_NCMOUSELEAVE:
    			case Win32API.WM_MOUSELEAVE:
    			case Win32API.WM_MOUSEHOVER:
    				_owner._skin.onMouseLeave();
    				break;
    			case Win32API.WM_NCLBUTTONDBLCLK:
    				suppressOriginalMessage = onNCDoubleClick(ref m);
    				break;
    			#endregion
    			#region Non-client Hit Test
    			case Win32API.WM_NCHITTEST:
    				suppressOriginalMessage = onNCHitTest(ref m);
    				break;
    			#endregion
    			#region Painting and sizing operation
    			case Win32API.WM_NCPAINT:
    				if (onNCPaint(true)) {
    					m.Result = (IntPtr)1;
    					suppressOriginalMessage = true;
    				}
    				break;
    			case Win32API.WM_NCCALCSIZE:
    				if (m.WParam == (IntPtr)1) {
    					if (!isProcessNCArea()) break;
    					Win32API.NCCALCSIZE_PARAMS p = (Win32API.NCCALCSIZE_PARAMS)m.GetLParam
                                                       (typeof(Win32API.NCCALCSIZE_PARAMS));
    					if (_owner._skin != null) p = _owner._skin.calculateNonClient(p);
    					Marshal.StructureToPtr(p, m.LParam, true);
    					suppressOriginalMessage = true;
    				}
    				break;
    			case Win32API.WM_SHOWWINDOW:
    				if (_owner._skin != null) _owner._skin.setRegion(_owner._form.Size);
    				break;
    			case Win32API.WM_SIZE:
    				onResize(m);
    				break;
    			case Win32API.WM_GETMINMAXINFO:
    				suppressOriginalMessage = calculateMaximumSize(ref m);
    				break;
    			case Win32API.WM_WINDOWPOSCHANGING:
    				Win32API.WINDOWPOS wndPos = (Win32API.WINDOWPOS)m.GetLParam
                                                (typeof(Win32API.WINDOWPOS));
    				if ((wndPos.flags & Win32API.SWP_NOSIZE) == 0) {
    					if (_owner._skin != null) _owner._skin.setRegion
                                            (new Size(wndPos.cx, wndPos.cy));
    				}
    				break;
    			case Win32API.WM_WINDOWPOSCHANGED:
    				if (_owner._form.WindowState == FormWindowState.Maximized) 
                                                         _owner._form.Region = null;
    				Win32API.WINDOWPOS wndPos2 = (Win32API.WINDOWPOS)m.GetLParam
                                                         (typeof(Win32API.WINDOWPOS));
    				if ((wndPos2.flags & (int)Win32API.SWP_NOSIZE) == 0) {
    					updateCaption();
    					onNCPaint(true);
    				}
    				break;
    			#endregion
    			#region Raw Input
    			case Win32API.WM_INPUT:
    				if (_owner._skin != null) {
    					if (_owner._skin.FormIsActive) {
    						uint dwSize = 0, receivedBytes;
    						uint szRIHeader = 
                               (uint)Marshal.SizeOf(typeof(Win32API.RAWINPUTHEADER));
    						int res = Win32API.GetRawInputData(m.LParam, 
                                      Win32API.RID_INPUT, IntPtr.Zero, ref dwSize, szRIHeader);
    						if (res == 0) {
    							IntPtr buffer = Marshal.AllocHGlobal((int)dwSize);
    							if (buffer != IntPtr.Zero) {
    								receivedBytes = (uint)Win32API.GetRawInputData
                                    (m.LParam, Win32API.RID_INPUT, buffer, ref dwSize, szRIHeader);
    								Win32API.RAWINPUT raw = (Win32API.RAWINPUT)
                                    Marshal.PtrToStructure(buffer, typeof(Win32API.RAWINPUT));
    								if (raw.header.dwType == Win32API.RIM_TYPEKEYBOARD) {
    									// Process keyboard event.
    									if (raw.keyboard.Message == Win32API.WM_KEYDOWN || 
                                            raw.keyboard.Message == Win32API.WM_SYSKEYDOWN) {
    										ushort key = raw.keyboard.VKey;
    										Keys kd = (Keys)Enum.Parse(typeof(Keys), 
                                                      Enum.GetName(typeof(Keys), key));
    										if (kd != System.Windows.Forms.Control.ModifierKeys) 
                                            kd = kd | System.Windows.Forms.Control.ModifierKeys;
    										// Call skin's onKeyDown function.
    										KeyEventArgs ke = new KeyEventArgs(kd);
    										suppressOriginalMessage = _owner._skin.onKeyDown(ke);
    									}
    								}
    							}
    						}
    					}
    				}
    				break;
    			#endregion
    		}
    		if(!suppressOriginalMessage) base.WndProc(ref m);
    	}
    }

    SkinBase 这个类封装了基本组件和功能需要构建自己的皮肤。 3系统的基本组件包括按钮(最小化、最大化、关闭),矩形对持有非客户区信息。 隐藏,复制Code

    public abstract class SkinBase : IDisposable {
    	// ...
    	#region Protected Fields
    	protected MinimizeButton _minimizeButton = new MinimizeButton();
    	protected MaximizeButton _maximizeButton = new MaximizeButton();
    	protected CloseButton _closeButton = new CloseButton();
    	protected bool _formIsActive = true;
    	#region Standard Rectangle for Non-client area
    	protected Rectangle _rectClient;
    	protected Rectangle _rectIcon;
    	protected internal Rectangle _rectBar;
    	protected Rectangle _rectBorderTop;
    	protected internal Rectangle _rectBorderLeft;
    	protected internal Rectangle _rectBorderBottom;
    	protected internal Rectangle _rectBorderRight;
    	protected Rectangle _rectBorderTopLeft;
    	protected Rectangle _rectBorderTopRight;
    	protected Rectangle _rectBorderBottomLeft;
    	protected Rectangle _rectBorderBottomRight;
    	#endregion
    	#endregion
    }

    基本功能对皮肤形成消息处理,封面激活/失活,碰撞测试,形成大小/状态改变/文本变化,非客户区鼠标事件(鼠标,鼠标,下双击),和按键按下。鼠标事件和碰撞测试,鼠标指针的位置是相对于表单的左上角,而不是屏幕。 隐藏,收缩,复制Code

    public abstract class SkinBase : IDisposable {
    	// ...
    	/// <summary>
    	/// Called when the text property of the form has been changed.
    	/// </summary>
    	protected internal abstract void onFormTextChanged();
    	/// <summary>
    	/// Called when the left button of the mouse is double-clicked on the 
        /// non-client area of the form.
    	/// </summary>
    	protected internal abstract bool onDoubleClick();
    	/// <summary>
    	/// Called when the mouse pointer is moved over the non-client area of the form.
    	/// </summary>
    	protected internal abstract bool onMouseMove(MouseEventArgs e);
    	/// <summary>
    	/// Called when the mouse pointer is over the non-client area of the form 
        /// and a mouse button is pressed.
    	/// </summary>
    	protected internal abstract bool onMouseDown(MouseEventArgs e);
    	/// <summary>
    	/// Called when the mouse pointer is over the non-client area of the form 
        /// and a mouse button is released.
    	/// </summary>
    	protected internal abstract bool onMouseUp(MouseEventArgs e);
    	/// <summary>
    	/// Called when the mouse pointer is leaving the non-client area of the form.
    	/// </summary>
    	protected internal abstract bool onMouseLeave();
    	/// <summary>
    	/// Called when the non-client area of the form is redrawn
    	/// </summary>
    	protected internal abstract bool onPaint(PaintEventArgs e);
    	/// <summary>
    	/// Called when one of the registered keys of the skin is pressed.
    	/// </summary>
    	protected internal abstract bool onKeyDown(KeyEventArgs e);
    	/// <summary>
    	/// Called when the form need to set its region.
    	/// </summary>
    	protected internal abstract bool setRegion(Size size);
    	/// <summary>
    	/// Called when the non-client are of the form need to be calculated.
    	/// </summary>
    	protected internal abstract Win32API.NCCALCSIZE_PARAMS 
                           calculateNonClient(Win32API.NCCALCSIZE_PARAMS p);
    	/// <summary>
    	/// Called when the bar of the form is updated.
    	/// </summary>
    	protected internal abstract void updateBar(Rectangle rect);
    	/// <summary>
    	/// Called when the hit-test is performed on the non-client area of the form.
    	/// </summary>
    	protected internal abstract int nonClientHitTest(Point p);
    }

    在创建定制皮肤通过继承SkinBase类时,重要的事情我们需要注意calculateNonClient和nonClientHitTest功能。 calculateNonClient函数是函数,你必须决定的大小非客户区域的形式通过修改p。rect0值: 减少p.rect0的价值。你领域的高度酒吧形式。减少p.rect0的价值。离开字段的表单的左边框的宽度。减少p.rect0的价值。正确的字段的表单的右边框的宽度。减少p.rect0的价值。底部高度字段的表单的底部边框。 Hide,收缩,复制Code

    protected internal override Win32API.NCCALCSIZE_PARAMS calculateNonClient
         (Win32API.NCCALCSIZE_PARAMS p) {
    	// Check if we don't need to calculate the client area.
    	if (Form == null || Form.WindowState == FormWindowState.Minimized || 
    		(Form.WindowState == FormWindowState.Minimized && Form.MdiParent != null)) return p;
    	// Calculate the valid client area of the form here, that is stored 
        // in rect0 of the p parameter.
    	p.rect0.Top += _rectBar.Height;
    	_rectClient.Y = _rectBar.Height + 1;
    	if (Form.WindowState == FormWindowState.Maximized) { 
    		// The form is maximized, thus the borders will not be calculated 
            // and the status bar only will be calculated.
    		//p.rect0.Bottom -= _rectStatus.Height;
    		_rectClient.X = 0;
    		_rectClient.Width = p.rect0.Right - (p.rect0.Left + 1);
    		_rectClient.Height = p.rect0.Bottom - (p.rect0.Top + 1);
    	} else { 
    		// Deflate the left, right, and bottom of the rect0 by the left border width,
    		// right border width, and sum of the status and bottom border height.
    		p.rect0.Left += _rectBorderLeft.Width;
    		p.rect0.Right -= _rectBorderRight.Width;
    		p.rect0.Bottom -= _rectBorderBottom.Height;
    		_rectClient.X = _rectBorderLeft.Width + 1;
    		_rectClient.Width = p.rect0.Right - (p.rect0.Left + 2);
    		_rectClient.Height = p.rect0.Bottom - (p.rect0.Top + 2);
    	}
    	return p;
    }

    nonClientHitTest函数是告诉系统鼠标指针指向了非客户区的哪一部分。传递给此函数的Point p参数相对于已蒙皮表单的左上角。此函数的结果必须是hit-test结果常量之一,这些常量前缀为HT。在我的实现中,当鼠标指针指向最小化、最大化或关闭按钮时,我返回HTOBJECT,而不是返回HTMINBUTTON、HTMAXBUTTON或HTCLOSE,因为我宁愿使用自己的工具提示,而不是系统工具提示:D。 隐藏,收缩,复制Code

    protected internal override int nonClientHitTest(Point p) {
    	if (_rectClient.Contains(p)) return Win32API.HTCLIENT;
    	if (_rectIcon.Contains(p)) return Win32API.HTMENU;
    	// Always return HTOBJECT instead of the corresponding hittest value, 
        // to prevent the default tooltip to be shown.
    	if (_minimizeButton.Enabled && _minimizeButton.Visible) {
    		if (_minHost.Bounds.Contains(p)) return Win32API.HTOBJECT;
    	}
    	if (_maximizeButton.Enabled && _maximizeButton.Visible) {
    		if (_maxHost.Bounds.Contains(p)) return Win32API.HTOBJECT;
    	}
    	if (_closeButton.Enabled && _closeButton.Visible) {
    		if (_closeHost.Bounds.Contains(p)) return Win32API.HTOBJECT;
    	}
    	// Test for custom bar button, if any of them, then return the HTOBJECT
    	if (Form.FormBorderStyle == FormBorderStyle.Sizable || 
            Form.FormBorderStyle == FormBorderStyle.SizableToolWindow 
    		&& Form.WindowState != FormWindowState.Maximized) { 
    		// Test for borders.
    		// Corners
    		if (_rectBorderTopLeft.Contains(p)) return Win32API.HTTOPLEFT;
    		if (_rectBorderTopRight.Contains(p)) return Win32API.HTTOPRIGHT;
    		if (_rectBorderBottomLeft.Contains(p)) return Win32API.HTBOTTOMLEFT;
    		if (_rectBorderBottomRight.Contains(p)) return Win32API.HTBOTTOMRIGHT;
    		// vertical and horizontal
    		if (_rectBorderTop.Contains(p)) return Win32API.HTTOP;
    		if (_rectBorderLeft.Contains(p)) return Win32API.HTLEFT;
    		if (_rectBorderRight.Contains(p)) return Win32API.HTRIGHT;
    		if (_rectBorderBottom.Contains(p)) return Win32API.HTBOTTOM;
    	}
    	if (Form.WindowState != FormWindowState.Maximized) {
    		// Test for bar form.
    		if (_rectBar.Contains(p)) return Win32API.HTCAPTION;
    	}
    	// Default return value.
    	return Win32API.HTNOWHERE;
    }

    历史 2012年7月4日:初版 本文转载于:http://www.diyabc.com/frontweb/news12034.html

  • 相关阅读:
    我的WCF之旅(1):创建一个简单的WCF程序
    c#自定义类型的转换方式operator,以及implicit(隐式)和explicit (显示)声明的区别
    Linux 系统时间设置
    Redis入门
    线程安全的单例模式
    redis-Sentinel配置
    openpose
    Qt5.11参考文档
    opencv3.3
    opencv3.4 win10 visual studio2017 opencv_contrib 编译
  • 原文地址:https://www.cnblogs.com/Dincat/p/13473480.html
Copyright © 2011-2022 走看看