Winfrom中From控件的重绘
重绘目的:
- 1. 满足非默认主题下的标题栏样式
- 2. 在保留停靠功能的同时进行重绘。
代码如下:
public partial class FormEx: Form
{
public FormEx()
{
InitializeComponent();
TitleBar.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(TitleBar, true, null);
Icon = Properties.Resources.shark;
CloseButtonImage = Properties.Resources.close;
MaximumButtonImage = Properties.Resources.window_max;
MaximumNormalButtonImage = Properties.Resources.window;
MinimumButtonImage = Properties.Resources.window_min;
CaptionBackgroundColor = Color.FromArgb(, , );
CaptionHeight = ;
BackColor = Color.White;
ControlBackColor = Color.Transparent;
this.TransparencyKey = boderColor;
ControlActivedColor = DrawHelper.GetNearColor(Color.White, , -, -, -); TitleBar.SendToBack(); base.SetStyle(
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.SupportsTransparentBackColor|
ControlStyles.DoubleBuffer, true);
base.AutoScaleMode = AutoScaleMode.None;
} #region 公开变量
[Category("标题栏"), Description("关闭按钮图片")]
public Image CloseButtonImage { get; set; } [Category("标题栏"), Description("最大化按钮图片")]
public Image MaximumButtonImage { get; set; } [Category("标题栏"), Description("最大化默认按钮图片")]
public Image MaximumNormalButtonImage { get; set; } [Category("标题栏"), Description("最小化按钮图片")]
public Image MinimumButtonImage { get; set; } [Category("标题栏"), Description("标题栏按钮鼠标悬浮背景色"), DefaultValue(typeof(Color), "#000000")]
public Color ControlActivedColor { get; set; } [Category("标题栏"), Description("标题栏按钮默认状态背景色"), DefaultValue(typeof(Color))]
public Color ControlBackColor { get; set; } private int captionHeight;
[Category("标题栏"), Description("标题栏高度"), DefaultValue(typeof(int), "")]
public int CaptionHeight { get { return captionHeight; } set { captionHeight = value; TitleBar.Height = value; } } [Category("标题栏"), Description("标题位置")]
public ContentAlignment TitleAlign { set; get; } = ContentAlignment.MiddleLeft; private Color captionBackgroundColor;
[Category("标题栏"), Description("标题栏背景颜色"), DefaultValue(typeof(Color), "White")]
public Color CaptionBackgroundColor
{
get { return captionBackgroundColor; }
set
{
captionBackgroundColor = value;
TitleBar.BackColor = captionBackgroundColor;
}
}
#endregion #region 私有变量 private MouseState _mouseState = MouseState.Out;
private Rectangle closeRect = Rectangle.Empty; //关闭按钮范围
private Rectangle maxRect = Rectangle.Empty; //最大化按钮范围
private Rectangle minRect = Rectangle.Empty; //最小化按钮范围
private Rectangle captionRect; //标题范围 private int btnH = ; //按钮大小
private int boderWidth = ; //边框宽度
private Color boderColor = Color.FromArgb(, , );
#endregion #region 重绘事件
private void TitleBar_Paint(object sender, PaintEventArgs e)
{
captionRect = new Rectangle(, , TitleBar.Width, TitleBar.Height);
DrawTitle(e.Graphics);
DrawControlButton(e.Graphics);
} protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
DrawBound(e.Graphics);
} /// <summary>
/// 绘制边框
/// </summary>
private void DrawBound(Graphics g)
{
Pen pen = new Pen(boderColor, boderWidth * );
Rectangle rectangle = new Rectangle(, , Width, Height);
g.DrawRectangle(pen, rectangle);
pen = new Pen(Color.Black, );
rectangle = new Rectangle(boderWidth - , boderWidth - , Width - boderWidth * + , Height - boderWidth * + );
g.DrawRectangle(pen, rectangle);
Padding = new Padding(boderWidth);
} /// <summary>
/// 绘制控制按钮
/// </summary>
private void DrawControlButton(Graphics g)
{
int x = ClientSize.Width - btnH - - boderWidth;
if (CloseButtonImage != null)
{
DrawButtonImage(ref closeRect, ref x, _mouseState == MouseState.CloseHover, g, CloseButtonImage);
}
if (MaximizeBox)
{
if (WindowState == FormWindowState.Maximized && MaximumNormalButtonImage != null)
DrawButtonImage(ref maxRect, ref x, _mouseState == MouseState.MaxHover, g, MaximumNormalButtonImage);
else if (MaximizeBox && WindowState != FormWindowState.Maximized && MaximumButtonImage != null)
DrawButtonImage(ref maxRect, ref x, _mouseState == MouseState.MaxHover, g, MaximumButtonImage);
}
if (MinimizeBox && MinimumButtonImage != null)
{
DrawButtonImage(ref minRect, ref x, _mouseState == MouseState.MinHover, g, MinimumButtonImage);
}
} private void DrawButtonImage(ref Rectangle rect, ref int x, bool isHover, Graphics g, Image image)
{
//rect = new Rectangle(x, (captionHeight - btnH) / 2, btnH, btnH);
rect = new Rectangle(x, , btnH, btnH);
Brush brush = new SolidBrush(isHover ? ControlActivedColor : ControlBackColor);
g.FillRectangle(brush, rect);
g.DrawImage(image, rect);
if (image == CloseButtonImage)
rect = new Rectangle(x, , btnH + boderWidth, btnH);
x -= btnH;
} /// <summary>
/// 绘制标题
/// </summary>
private void DrawTitle(Graphics g)
{
int x = ;
if (ShowIcon && Icon != null)
{
g.SmoothingMode = SmoothingMode.AntiAlias;
ImageAttributes image = new ImageAttributes();
image.SetWrapMode(WrapMode.TileFlipXY);
using (Bitmap bitmap = Icon.ToBitmap())
{
Rectangle rec = new Rectangle(x, (captionHeight - btnH) / , CaptionHeight - , CaptionHeight - );
g.DrawImage(bitmap, rec, , , bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, image);
}
x += ;
}
if (!string.IsNullOrEmpty(Text))
{
int fontHeight = Size.Ceiling(g.MeasureString("Text", TitleBar.Font)).Height;
int fontWidth = Size.Ceiling(g.MeasureString(Text, TitleBar.Font)).Width;
Brush brush = new SolidBrush(ForeColor);
if (TitleAlign == ContentAlignment.MiddleLeft)
g.DrawString(Text, TitleBar.Font, brush, x, (CaptionHeight - fontHeight) / );
else if (TitleAlign == ContentAlignment.TopCenter)
g.DrawString(Text, TitleBar.Font, brush, (Width - fontWidth)/, boderWidth); }
}
#endregion #region 其他事件
private void TitleBar_MouseClick(object sender, MouseEventArgs e)
{
if (e.Clicks != || e.Button != MouseButtons.Left)
return;
switch (_mouseState)
{
case MouseState.CloseHover:
Close();
break;
case MouseState.MaxHover:
WindowState = WindowState == FormWindowState.Maximized ? FormWindowState.Normal : FormWindowState.Maximized;
return;
case MouseState.MinHover:
WindowState = FormWindowState.Minimized;
return;
}
_mouseState = MouseState.Normal;
} private void TitleBar_MouseDown(object sender, MouseEventArgs e)
{
if (_mouseState != MouseState.CaptionHover)
return; if (e.Clicks == )
{
Win32API.ReleaseCapture();
Win32API.SendMessage(Handle, Win32API.WM_SYSCOMMAND, Win32API.SC_MOVE + Win32API.HTCAPTION, );
}
else if (e.Clicks == && e.Button == MouseButtons.Left)
{
WindowState = WindowState == FormWindowState.Maximized ? FormWindowState.Normal : FormWindowState.Maximized;
}
} private void TitleBar_MouseMove(object sender, MouseEventArgs e)
{
Point p = new Point(e.X, e.Y);
if (closeRect != Rectangle.Empty && closeRect.Contains(p))
_mouseState = MouseState.CloseHover;
else if (minRect != Rectangle.Empty && minRect.Contains(p))
_mouseState = MouseState.MinHover;
else if (maxRect != Rectangle.Empty && maxRect.Contains(p))
_mouseState = MouseState.MaxHover;
else if (captionRect != Rectangle.Empty && captionRect.Contains(p))
_mouseState = MouseState.CaptionHover;
else
_mouseState = MouseState.Normal; Invalidate(captionRect, true);
} private void TitleBar_MouseLeave(object sender, EventArgs e)
{
_mouseState = MouseState.Out;
Invalidate(captionRect, true);
} private void FormEx_SizeChanged(object sender, EventArgs e)
{
Invalidate(captionRect, true);
}
#endregion #region 调整窗口大小 protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
{
if (width == Width + )
return;
base.SetBoundsCore(x, y, width, height, specified);
} protected override void WndProc(ref Message m)
{
if (_mouseState == MouseState.CloseHover || _mouseState == MouseState.MinHover)
{
base.WndProc(ref m);
return;
}
switch (m.Msg)
{
case 0x0084:
base.WndProc(ref m);
Point vPoint = new Point((int)m.LParam & 0xFFFF,
(int)m.LParam >> & 0xFFFF);
vPoint = PointToClient(vPoint);
if (vPoint.X <= )
if (vPoint.Y <= )
m.Result = (IntPtr)Win32API.Guying_HTTOPLEFT;
else if (vPoint.Y >= ClientSize.Height - )
m.Result = (IntPtr)Win32API.Guying_HTBOTTOMLEFT;
else m.Result = (IntPtr)Win32API.Guying_HTLEFT;
else if (vPoint.X >= ClientSize.Width - )
if (vPoint.Y <= )
m.Result = (IntPtr)Win32API.Guying_HTTOPRIGHT;
else if (vPoint.Y >= ClientSize.Height - )
m.Result = (IntPtr)Win32API.Guying_HTBOTTOMRIGHT;
else m.Result = (IntPtr)Win32API.Guying_HTRIGHT;
else if (vPoint.Y <= )
m.Result = (IntPtr)Win32API.Guying_HTTOP;
else if (vPoint.Y >= ClientSize.Height - )
m.Result = (IntPtr)Win32API.Guying_HTBOTTOM;
break;
case 0x0201: //鼠标左键按下的消息
m.Msg = 0x00A1; //更改消息为非客户区按下鼠标
m.LParam = IntPtr.Zero; //默认值
m.WParam = new IntPtr(); //鼠标放在标题栏内
base.WndProc(ref m);
break;
case 0x0083:
if (m.WParam != IntPtr.Zero)
{
NCCALCSIZE_PARAMS rcsize = (NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALCSIZE_PARAMS));
Marshal.StructureToPtr(rcsize, m.LParam, false);
}
m.Result = new IntPtr();
break;
default:
base.WndProc(ref m);
break;
}
}
#endregion
} public enum MouseState
{
Normal,
MaxHover,
MinHover,
CloseHover,
CaptionHover,
Out,
}
因为主要目的是为了保留窗体是停靠功能,所以不能使用无边框然后直接重绘标题栏。拦截了window绘制有效区域标题栏的消息,仍然存在很多不完善的地方,如拦截边框消息后没有重新绘制原边框位置的图形,导致了原区域的透明等等。
Winfrom中From控件的重绘的更多相关文章
- 玩转控件:重绘DEVEXPRESS中DateEdit控件 —— 让DateEdit支持只选择年月 (提供源码下载)
前言 上一篇博文<玩转控件:重绘ComboBox —— 让ComboBox多列显示>中,根据大家的回馈,ComboBox已经支持筛选了,更新见博文最后最后最后面. 奇葩 这两天遇到 ...
- 玩转控件:重写/重绘Dev中MessageBox弹窗控件
很久没有更新博客了,本想着直接发一篇<手撕ERP>系列,从控件重写.重绘,到框架搭建,再到部分模块实现+业务的.但是每次动手的时候,都觉得难以下手.直接从数据库设计开始吧,模块设计还没定下 ...
- winfrom中pictureBox控件的部分使用方法
一.后台属性 1.pictureBox1.Image显示图片 2.pictureBox1.ImageLocation存储和提取图片路径 二.面板属性 1.Picturebox控件SizeMode属性 ...
- VC++中关于控件重绘函数/消息 OnPaint,OnDraw,OnDrawItem,DrawItem的区别
而OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息. OnDraw()是CVIEW的成员函数,并且没有响应消息的功能.这就是为什么你用VC成的程序代码时,在视图类只有OnDraw ...
- ArcGIS Engine开发之旅03--ArcGIS Engine中的控件
原文:ArcGIS Engine开发之旅03--ArcGIS Engine中的控件 制图控件,如MapControl.PageLayoutControl,其中MapControl控件主要用于地理数据的 ...
- 玩转控件:对Dev中GridControl控件的封装和扩展
又是一年清明节至,细雨绵绵犹如泪光,树叶随风摆动.... 转眼间,一年又过去了三分之一,疫情的严峻让不少企业就跟清明时节的树叶一样,摇摇欲坠.裁员的裁员,降薪的降薪,996的996~~说起来都是泪,以 ...
- CSharpGL(26)在opengl中实现控件布局/渲染文字
CSharpGL(26)在opengl中实现控件布局/渲染文字 效果图 如图所示,可以将文字.坐标轴固定在窗口的一角. 下载 CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入( ...
- WPF中Ribbon控件的使用
这篇博客将分享如何在WPF程序中使用Ribbon控件.Ribbon可以很大的提高软件的便捷性. 上面截图使Outlook 2010的界面,在Home标签页中,将所属的Menu都平铺的布局,非常容易的可 ...
- Android线程中设置控件
在Android中经常出现多线程中设置控件的值报错的情况,今天教大家封装一个简单的类避免这样的问题,同样也调用实现也非常的方便. 自定义类: /** * Created by wade on 2016 ...
随机推荐
- 04--Java--使用eclipse创建开发java项目步骤
eclipse创建开发java步骤 1.三种创建java项目 1)方式一:在包资源管理器(package explorer)窗口中鼠标右击任意位置选择New --> Java Project,如 ...
- springboot整合elasticJob实战(纯代码开发三种任务类型用法)以及分片系统,事件追踪详解
一 springboot整合 介绍就不多说了,只有这个框架是当当网开源的,支持分布式调度,分布式系统中非常合适(两个服务同时跑不会重复,并且可灵活配置分开分批处理数据,贼方便)! 这里主要还是用到zo ...
- kubernetes secret 和 serviceaccount删除
背景 今天通过配置创建了一个serviceaccounts和secret,后面由于某种原因想再次创建发现已存在一个serviceaccounts和rolebindings.rbac.authoriza ...
- 第四次作业:使用Packet Tracer理解RIP路由协议及ICMP协议
0 个人信息 张樱姿 201821121038 计算1812 1 实验目的 理解RIP路由表的建立与更新 感受RIP坏消息传得慢 2 实验内容 使用Packet Tracer,正确配置网络参数,使用命 ...
- CCNA的基础知识及要点
一.CCNA中的基础知识及要点: 2.网线的制作:568B:橙白,橙,绿白,蓝,蓝白,绿,棕白,棕 568A的排线顺序从左到右依次为:白绿.绿.白橙.蓝.白蓝.橙.白棕.棕.实验目的:初学者常为做网线 ...
- 让Android模拟器速度飞起来_Eclipse+BlueStacks调试Android应用【2012-10-30】
谨将此文献给无真机进行调试的各位同仁们,有真机的幸运儿请自觉飘过 原文地址:http://www.cnblogs.com/hbbbs/archive/2012/10/30/2746950.html 长 ...
- 目标检测之RCNN,fast RCNN,faster RCNN
RCNN: 候选区生成(Selective Search). 分割成2000左右的候选小区域 合并规则:颜色.纹理相近,尺度均匀,合并后形状规则 特征提取. 归一候选区尺寸为227×227,归一方法. ...
- CCF_201509-1_数列分段
水. #include<iostream> #include<cstdio> using namespace std; int main() { ]; cin >> ...
- HDU_5045_状态压缩dp
http://acm.hdu.edu.cn/showproblem.php?pid=5045 i从1到m依次更新,dp[i][j]表示更新到i题时,j表示每个人的答题状态,分别用0和1表示(因为每个人 ...
- 高软期末考试 B2C模式
一.软件工程知识点 简要总结 1.软件基础知识 瀑布模型: 我感觉整个<软件工程>书的布局就是按照瀑布模型来的,上面右图少个运维. 2.UML图 2.1 用例图 UseCase Diagr ...