C# 无边框异型窗体制作
我是一个C#的初学者 只要涉及到windows窗体编程 都希望窗体的外观比较好看 不是系统默认的那样
对于C# 更改窗体外观感觉并不那么轻松 更改窗体外观涉及到使用GDI+ 我所知道的有两种方法:
- 有系统边框的窗体 处理窗体的Paint方法,在paint方法中 参数e.Graphics属性将返回一个对象 用来作画 但是这个画布的区域是窗体的客户区 所以无法修改到窗体的标题栏 边框等位置的。要更改标题栏只有获取整个窗口的句柄 这样创建的画布是整个窗体区域 但是对于我这样的初学者来说 对于句柄 windowsAPI还很不熟悉 我相信大多数的初学者或者学生都和我有相同的困惑 所以我使用了第二种办法 无边框窗体
- 无边框的窗体 把FormBorderStyle的属性设置为none 就去掉了边框 剩下的窗体客户区和和整个窗体大小是相同的 再使用e.Graphics作画就是在整个窗体上作画 我主要也是描述这样的一种方法 相信对很多和我一样的人有很多帮助
对于一个窗体 它除了外观以外还有2个主要特征:1.可以拖动 可以拖拽大小 2.具有控制按钮 关闭 最大化 最小化。我主要描述第二种方法
题外话:在网上随便一搜C#自定义窗体之类的 总是出现一大片的文章 以无边框的为例 什么都说得很详细了 但是关键的拖动拖拽大小确没有 总是少掉了关键部分。不止是窗体的代码是这样 其它各类源代码也是如此 很难在网上下载到关键的代码和高质量的代码 个人觉得好多人喜欢学习别人的东西 确不愿意把自己会的 关键的东西拿出来和别人分享。导致现在网上的充斥着大量重复的无用的代码
回到主题 介绍处理无边框窗体的经验,下面是最终效果:
这就是一个无边框窗体 可以注意到它的外观 四个角是圆的 有控制按钮 并且还可以拖拽,当鼠标移动到窗体的四个角和边缘的时候可以拖拽大小
这个窗体没有标题栏和边框的限制 控件可以放在窗体上任何地方
下面就是直奔主题了:
先说一说制作这个窗体的思路(窗体集成自System.Windows.Forms.Form):
1.设置FormBorderStyle属性为none 让它成为一个无边框窗体
2.设置窗体的Region属性 该属性设置窗体的有效区域 而我们把窗体的有效区域设置为圆角矩形 窗体就变成圆角的了
3.自定义控件 3个按钮 控制窗体的最大化 最小化 还原 关闭
4.使窗体可以拖动 在边缘按下鼠标可以拖拽大小
主要涉及GDI+中两个重要的类 Graphics和GraphicsPath类 分别位于System.Drawing和System.Drawing.Drawing2D
首先我们创建一个C# windows窗体应用程序项目 将默认的Form1改名成MainForm 设置FormBorderStyle属性为none 让它成为一个无边框窗体
接着我们需要这样一个函数 private void SetWindowRegion() 此函数设置窗体有效区域为圆角矩形,以及一个辅助函数 private GraphicsPath GetRoundedRectPath(Rectangle rect, int radius)此函数用来创建圆角矩形路径,将在SetWindowRegion()中调用它
public void SetWindowRegion()
{
System.Drawing.Drawing2D.GraphicsPath FormPath;
FormPath = new System.Drawing.Drawing2D.GraphicsPath();
Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
FormPath = GetRoundedRectPath(rect, 10);
this.Region = new Region(FormPath); }
private GraphicsPath GetRoundedRectPath(Rectangle rect, int radius)
{
int diameter = radius;
Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
GraphicsPath path = new GraphicsPath(); // 左上角
path.AddArc(arcRect, 180, 90); // 右上角
arcRect.X = rect.Right - diameter;
path.AddArc(arcRect, 270, 90); // 右下角
arcRect.Y = rect.Bottom - diameter;
path.AddArc(arcRect, 0, 90); // 左下角
arcRect.X = rect.Left;
path.AddArc(arcRect, 90, 90);
path.CloseFigure();//闭合曲线
return path;
}
在窗体尺寸改变的时候我们需要调用SetWindowRegion()将窗体变成圆角的
private void MainForm_Resize(object sender, EventArgs e)
{
SetWindowRegion();
}
到此 窗体的形状部分就完成了 通过创建不同的GraphicsPath对象 可以将窗体设置为任意形状 三角形 六边形 椭圆 以及任何不规则图形来制作不规则窗体
然后可以通过给窗体设置背景图片或者在窗体上作画来更改外观 无论图片是什么形状只要超过了窗体有效区域的部分都会被裁掉 这样给换皮肤带来了极大的方便 只需要换一张背景图而已 不需要去做圆角图片 就像迅雷7那样 换皮肤就换一张背景图片
然后是自定义控件 3个按钮 通过GDI+可以绘制比较漂亮的按钮 这部分相对简单很多 就不叙述了,这方面的资料也很好找
将这3个按钮控件拖到窗体右上角设置它们的Anchor属性为top right 让它们的位置始终相对于窗体右上角改变 并编写它们的单击事件处理代码 模拟窗体的最大化最小化和关闭
这里需要注意一点的就是 最大化的时候直接使用this.WindowState = FormWindowState.Maximized会遮盖任务栏 在执行这行代码前先限制窗体的最大尺寸为屏幕的工作区
this.MaximumSize = new Size(Screen.PrimaryScreen.WorkingArea.Width, Screen.PrimaryScreen.WorkingArea.Height);
this.WindowState = FormWindowState.Maximized;
接下再运行的时候 窗体就是圆角 并且具有控制按钮了 只差拖动和拖拽大小了 下面完成最后一部分
实现这部分只能通过处理windows消息来完成 使用windows系统的功能来完成窗体的拖拽大小和移动 我们只需要处理WM_NCHITTEST消息就可以完成这部分功能 WM_NCHITTEST是告知鼠标事件位置的消息 是很常用的一个消息。查询MSDN API可以找到这些常量 WM_NCHITTEST常量地址http://msdn.microsoft.com/zh-cn/library/ms645618(en-us,VS.85).aspx
这里我们需要使用10个常量 1个WM_NCHITTEST 9个WM_NCHITTEST消息结果
按 Ctrl+C 复制代码 按 Ctrl+C 复制代码
定义好这些常量之后 就需要处理windows消息了 C#处理 windows消息就重写WndProc(ref Message Msg)函数
protected override void WndProc(ref Message Msg)
{
if (Msg.Msg == WM_NCHITTEST)
{
//获取鼠标位置
int nPosX = (Msg.LParam.ToInt32() & 65535);
int nPosY = (Msg.LParam.ToInt32() >> 16);
//右下角
if (nPosX >= this.Right - 6 && nPosY >= this.Bottom - 6)
{
Msg.Result = new IntPtr(HT_BOTTOMRIGHT);
return;
}
//左上角
else if (nPosX <= this.Left + 6 && nPosY <= this.Top + 6)
{
Msg.Result = new IntPtr(HT_TOPLEFT);
return;
}
//左下角
else if (nPosX <= this.Left + 6 && nPosY >= this.Bottom - 6)
{
Msg.Result = new IntPtr(HT_BOTTOMLEFT);
return;
}
//右上角
else if (nPosX >= this.Right - 6 && nPosY <= this.Top + 6)
{
Msg.Result = new IntPtr(HT_TOPRIGHT);
return;
}
else if (nPosX >= this.Right - 2)
{
Msg.Result = new IntPtr(HT_RIGHT);
return;
}
else if (nPosY >= this.Bottom - 2)
{
Msg.Result = new IntPtr(HT_BOTTOM);
return;
}
else if (nPosX <= this.Left + 2)
{
Msg.Result = new IntPtr(HT_LEFT);
return;
}
else if (nPosY <= this.Top + 2)
{
Msg.Result = new IntPtr(HT_TOP);
return;
}
else
{
Msg.Result = new IntPtr(HT_CAPTION);
return;
}
}
base.WndProc(ref Msg);
}
最后 为了使窗体不会出现闪烁 可以使用双缓存 在重绘的时候进行双缓存 在窗体的Resize事件中重绘并使用双缓存
private void MainForm_Resize(object sender, EventArgs e)
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
this.Refresh();
SetWindowRegion();
}
这可以有效消除窗体控制按钮的闪烁情况
C# 无边框异型窗体制作的更多相关文章
- C#自定义无边框MessageBox窗体
C#自定义无边框MessageBox窗体 本例子中制作一个无边框的MessageBox窗体 展示效果: 窗体设计 1.添加一个窗体继承原生Form public partial class Messa ...
- C# .net WPF无边框移动窗体
转自 http://download.csdn.net/detail/xiang348352/3095084 WPF无边框移动窗体,先在<Window>里添加 MouseLeftButto ...
- Qt中实现无边框的窗体
1 自定义窗体类继承自QWidget 2 在构造函数中设置无边框效果 setWindowFlags(Qt::FramelessWindowHint);//无边框 setAttribute(Qt::WA ...
- WPF无边框移动窗体
WPF无边框移动窗体,先在<Window>里添加 MouseLeftButtonDown=”Window_MouseLeftButtonDown” 然后导航到事件,在事件里添加 if (e ...
- WPF 无边框透明窗体
WindowStyle="None"--无边框,如果需要其它按钮,如缩小.放大.收缩.关闭按钮,可以自定义 AllowsTransparency="True"- ...
- 做个无边框winform窗体,并美化界面
今天下午程序写完,有些时间就搞下界面美化,做个无框窗体.首先把窗体的FormBorderStyle设置为None,就变成无框的啦,不过你会发现这样窗体上就没有原来的最大最小化和关闭按钮了哦,所以要自己 ...
- winform学习(9)无边框拖动窗体
去除边框 选中窗体,在属性中找到FormBorderStyle,设置为None 实现无边框拖动 [DllImport("user32.dll")] public st ...
- 【CITE】 C#中实现拖动无边框Form窗体
首先建一个Windows应用程序 将Form1的 FormBorderStyle属性设置为None 主要是在Form1窗体触发三个事件:Form4_MouseDown,Form4_MouseMove, ...
- 无边框WPF窗体——允许拖动
https://blog.csdn.net/zjcxhswill/article/details/38646525
随机推荐
- IOS中实现图片点击全屏预览
//// ViewController.m// XWZoomImageView//// Created by xiao on 15/11/13.// Copyright © 2015年 xiao. A ...
- 用 React 编写SVG图表
1.代码 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="U ...
- CentOS环境下Java开发环境的搭建
------------------------------------------------------- 安装Jdk 1.查询系统默认JDK CentOS系统默认会安装JDK,一般建议卸载后安装 ...
- C++:String类
String类 1.使用String类必须在程序的开始包括头文件string,即要有如下语句:#include<string> 2.string类字符串对象的使用方法与其他对象一样stri ...
- jps
jps(Java Virtual Machine Process Status Tool)是JDK 1.5提供的一个显示当前所有java进程pid的命令,简单实用,非常适合在linux/unix平台上 ...
- NYOJ-253 凸包
LK的旅行 时间限制:2000 ms | 内存限制:65535 KB 难度:5 描述 LK最近要去某几个地方旅行,她从地图上计划了几个点,并且用笔点了出来,准备在五一假期去这几个城市旅行.现在 ...
- Pig简单入门
pig是hadoop客户端,使用类似于SQL的面向数据流的语言pig latin,这个语言可以完成排序,过滤,求和,关联等操作,可以支持自定义函数.Pig自动把pig latin 映射为Map-Red ...
- hadoop2 环境的搭建(手动HA)
1.手工切换ha的环境的搭建(比hadoop1多出来journalnode的配置) namenode:hadoop110和hadoop111 datanode:hadoop112.hadoop113. ...
- mysql 行列动态转换(列联表,交叉表)
mysql 行列动态转换(列联表,交叉表) (1)动态,适用于列不确定情况 create table table_name( id int primary key, col1 char(2), col ...
- STL源码中map和set中key值不能修改的实现
前言 最近正好刚刚看完,<stl源码剖析>这本书的map和set的源码部分.但是看完之后又突然发现,之前怎么没有注意到map和set容器中key不能修改是怎么实现的.故,特此整理如下. s ...