C# GDI+绘图高级编程
C# GDI+绘图高级编程(二) 作者:无尘空间 文章来源:hi.baidu.com 发布日期:2009-01-14 使用OnPaint()绘制图形 http://www.tzwhx.com/NewShow/newBodyShow/Csharp%B1%E0%B3%CC_16814.html Windows会利用Paint事件通知应用程序完成重新绘制的要求。Paint事件的Form1处理程序处理虚方法OnPaint()的调用,同时传给他一个参数PaintEventArgs。也就是说只要重写OnPaint()执行画图操作。 下面创建一个Windows应用程序DrawShapes来完成这个操作。 protected override void OnPaint(PaintEventarges e) { base.OnPaint(e); Graphics dc = e.Graphics; Pen bluePen = new Pen(Color.Blue,3); dc.DrawRectangle(bluePen,0,0,50,50); Pen redpen = new Pen(Color.Red,2); dc.DrawEllipse(redPen,0,50,80.60); } PaintEventArgs是一个派生自EventArgs的类,一般用于传送有关事件的信息。PaintEventArgs有另外两个属性,其中一个比较重要的是Graphics实例,它们主要用于优化绘制窗口中需要绘制的部分。这样就不必调用CreateGraphics(),在OnPaint()方法中获取DC。 在完成我们的绘图后,还要调用基类OnPaint()方法,因为Windows在绘图过程中可能会执行一些他自己的工作。 这段代码的结果与前面的示例结果相同,但当最小化或隐藏它时,应用程序会正确执行。 使用剪切区域 DrawShapes示例说明了在窗口中绘制的主要规则,但它并不是很高效。原因是它试图绘制窗口中的所有内容,而没有考虑需要绘制多少内容。如下图所示,运行DrawShapes示例,当该示例在屏幕上绘制时,打开一个窗口,把它移动到DrawShapes窗体上,使之隐藏一部分窗体。 到现在为止一切正常。但移动上面的窗口时,DrawShapes窗口会再次全部显示出来,WIndows通常会给窗体发送一个Paint事件,要求它重新绘制本身。矩形和椭圆都位于客户区域的左上角,所以在任何时候都是可见的。在本例中不需要重新绘制这部分,而只要重新绘制白色背景区域。但是,Windows并不知道这一点,他认为应引发Paint事件,调用OnPaint()方法的执行代码。OnPiant()不必重新绘制矩形和椭圆。 在本例中,没有重新绘制图形。原因是我们使用了设备环境。Windows将利用重新绘制某些区域所需要的信息预先初始化设备环境。在GDI中,被标记出来的重绘区域称为无效区域,但在GDI+中,该术语改为剪切区域,设备环境知道这个区域的内容,它截取在这个区域外部的绘图操作,且不把相关的绘图命令传送给显卡。这听起来不错,但仍有一个潜在的性能损失。在确定是在无效区域外部绘图前,我们不知道必须进行多少设备环境处理。在某些情况下,要处理的任务比较多,因为计算哪些像素需要改变什么颜色,将会占用许多处理器时间。 其底线是让Graphics实例完成在无效区域外部的绘图工作,肯定会浪费处理器时间,减慢应用程序的运行。在设计优良的应用程序中,代码将执行一些检查,以查看需要进行哪些绘图工作,然后调用相关的Graphics实例方法。下面将编写一个示例DrawShapesClipping,修改DisplayShapes示例,只完成需要的重新绘制工作。在OnPaint()代码中,进行一个简单的测试,看看无效区域是否需要绘制的区域重叠,如果是就调用绘图方法。 首先,需要获得剪切区域的信息。这需要使用PaintEventArgs的另一个属性。这个属性叫做ClipRectangle,包含要重绘区域的坐标,并包装在一个结构实例System.Drawing.Rectangle中。Rectangle是一个相当简单的结构,包含4个属性:Top、Bottom、Left、Right。它们分别含矩形的上下的垂直坐标,左右的水平坐标。 接着,需要确定进行什么测试,以决定是否进行绘制。这里进行一个简单的测试。注意,在我们的绘图过程中,矩形和椭圆完全包含在(0,0)到(80,130)的矩形客户区域中,实际上,点(82,132)就已经在安全区域中了,因为线条大约偏离这个区域一个像素。所以我们要看看剪切区域的左上角是否在这个矩形区域内。如果是,就重新绘制如果不是就不必麻烦了。 protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics dc = e.Graphics; if (e.ClipRectangle.Top < 32 && e.ClipRectangle.Left < 82) { Pen bluePen = new Pen(Color.Blue,3); dc.DrawRectangle(bluePen,0,0,50,50); Pen redPen = new Pen(Color.Red,2); dc.DrawEllipse(redPen,0,50,80,60); } } 注意:这个结果和前一个结果完全相同,只是进行了早期测试,确定不需要重绘制的区域,提高了性能。还要注意这个是否进行绘图测试是非常粗略的。还可以进行更精细的测试,确定矩形和椭圆是否要重新绘制。这里有一个平衡。可以在OnPaint()中进行更复杂的测试,以提高性能,也可以使OnPaint()代码复杂一些。进行一些测试总是值得的,因为编写一些代码,可以更多的解除Graphics实例之外的会址内容,Graphics实例只是盲目地执行绘图命令。 <注:>本文参考文献 《C#高级编程》第4版 清华大学出版社
C# WinForm 圆角无边窗体 为什么文本框变透明
//=======================C# WinForm 圆角无边窗体================= protected override void OnResize(System.EventArgs e) { this.Region = null; 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); //NVRClientLib.Class.frmResizeClass frmRsize = new NVRClientLib.Class.frmResizeClass(); //FormPath = frmRsize.WinGetRoundedRectPath(rect, 30); //this.Region = new Region(FormPath); //frmRsize.WinAngleType(this, 26, 0.1); FormPath = WinGetRoundedRectPath(rect, 30); this.Region = new Region(FormPath); } private GraphicsPath WinGetRoundedRectPath(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; } C# WinForm 圆角无边窗体 为什么文本框变透明?????????
C# windewsFrom怎样捕捉鼠标进入绘制的区域
C# windewsFrom怎样捕捉鼠标进入绘制的区域 [ 标签:c#, 鼠标, 区域 ] 測試1 2010-01-01 23:07 我在tabControl的选项卡上已经绘制了一个关闭区域,但是怎么捕捉鼠标是否进入该区域呢,我想在鼠标进入该区域的时候跟换一个图片 private void tabControl1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e) { Graphics g = e.Graphics; using (Pen p = new Pen(Color.Red)) { Rectangle myTabRect = tabControl1.GetTabRect(e.Index); //把字写上 g.DrawString(tabControl1.TabPages[e.Index].Text , this.Font , SystemBrushes.ControlText , myTabRect.X+2, myTabRect.Y + 5); //模拟绘制一个区域表示关闭的的地方(是一个红色的方块区域) myTabRect.Offset(myTabRect.Width - (10 + 3), 6); myTabRect.Width = 8; myTabRect.Height = 8; g.DrawRectangle(p, myTabRect); g.FillRectangle(Brushes.White, myTabRect); g.DrawImage(icon, new Point(myTabRect.X, myTabRect.Y)); //ioon是一个图片 } } 满意答案 针对你的代码写了判断进入的程序. 可以判断进入了哪个选项卡头. 测试成功... private void tabControl1_MouseMove(object sender, MouseEventArgs e) { Rectangle myTabRect = tabControl1.GetTabRect(0); if (e.Y < myTabRect.Width) { for (int i = 0; i < tabControl1.TabCount; i++) { int Left = tabControl1.GetTabRect(i).Left; int Width = tabControl1.GetTabRect(i).Width; if (e.X >= Left && e.X <= Left + Width) { this.Text = "测试: 鼠标了进入了选项卡" + i.ToString(); break; } } } } 原来的回答=========================================================== 1. 如果这个闭合区域是一个控件, 那么直接使用这个控件的MouseEnter事件判断进入. 2. 如果这个闭合区域不是一个控件(我感觉这个符合你的程序). 那么就应在绘制这个区域的控件(对于你的程序, 我想应该是tabControl的选项卡上的Panel容器)上添加MouseMove事件 2.1 在事件中通过传入的参数e, 获得鼠标位置e.X, e.Y. 2.2 根据你绘制区域的函数, 手动判断是否进入区域. 我想你还得写这部分的代码, 比较麻烦. 所以我建议你, 如果你这个区域可以被一个外接长方形覆盖, 那么你可以通过一个比较容易绘图的控件(如PictureBox)绘制这个区域. 在通过它的MouseEnter事件判断进入. 希望对你有帮助.
C# 创建圆角窗体代码
public void SetWindowRegion() { System.Drawing.Drawing2D.GraphicsPath FormPath; FormPath = new System.Drawing.Drawing2D.GraphicsPath(); Rectangle rect = new Rectangle(0, 5, this.Width, this.Height - 5);//this.Left-10,this.Top-10,this.Width-10,this.Height-10); FormPath = GetRoundedRectPath(rect, 3); 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; arcRect.X = rect.Right - diameter; path.AddArc(arcRect, 270, 90); // 右下角 //arcRect.Y = rect.Bottom; arcRect.Y = rect.Bottom - diameter; path.AddArc(arcRect, 0, 90); // 左下角 arcRect.X = rect.Left; path.AddArc(arcRect, 90, 90); path.CloseFigure(); return path; } protected override void OnResize(System.EventArgs e) { this.Region = null; SetWindowRegion(); }
C# 利用HOOK实现自绘窗体系统菜单(续)-解决闪烁问题
上一次实现自绘菜单的时候(查看),闪烁的问题没有解决,后来认真的分析了一下,发现是由于一个疏忽照成的,所以小小的改动了一下代码。 主要改动了以下两个地方: 1、 去掉WM_KEYDOWM和0x1e5的消息处理。 2、 RenderBackgroundInternal方法。 闪烁的主要原因是由于RenderBackgroundInternal绘制的时候没有设置区域,会把其他菜单项的部分遮掩了,所以需要处理WM_KEYDOWM和0x1e5的消息处理,刷新整个菜单,造成闪烁。 更改后的RenderBackgroundInternal方法如下: internal static void RenderBackgroundInternal( Graphics g, Rectangle rect, Color baseColor, Color borderColor, Color innerBorderColor, RoundStyle style, int roundWidth, float basePosition, bool drawBorder, bool drawGlass, LinearGradientMode mode) { if (drawBorder) { rect.Width--; rect.Height--; } using (LinearGradientBrush brush = new LinearGradientBrush( rect, Color.Transparent, Color.Transparent, mode)) { Color[] colors = new Color[4]; colors[0] = GetColor(baseColor, 0, 35, 24, 9); colors[1] = GetColor(baseColor, 0, 13, 8, 3); colors[2] = baseColor; colors[3] = GetColor(baseColor, 0, 35, 24, 9); ColorBlend blend = new ColorBlend(); blend.Positions = new float[] { 0.0f, basePosition, basePosition + 0.05f, 1.0f }; blend.Colors = colors; brush.InterpolationColors = blend; if (style != RoundStyle.None) { using (GraphicsPath path = GraphicsPathHelper.CreatePath( rect, roundWidth, style, false)) { g.FillPath(brush, path); } if (baseColor.A > 80) { Rectangle rectTop = rect; if (mode == LinearGradientMode.Vertical) { rectTop.Height = (int)(rectTop.Height * basePosition); } else { rectTop.Width = (int)(rect.Width * basePosition); } using (GraphicsPath pathTop = GraphicsPathHelper.CreatePath( rectTop, roundWidth, RoundStyle.Top, false)) { using (SolidBrush brushAlpha = new SolidBrush( Color.FromArgb(128, 255, 255, 255))) { g.FillPath(brushAlpha, pathTop); } } } if (drawGlass) { RectangleF glassRect = rect; if (mode == LinearGradientMode.Vertical) { glassRect.Y = rect.Y + rect.Height * basePosition; glassRect.Height = (rect.Height - rect.Height * basePosition) * 2; } else { glassRect.X = rect.X + rect.Width * basePosition; glassRect.Width = (rect.Width - rect.Width * basePosition) * 2; } GraphicsState gState = g.Save(); g.SetClip(rect); ControlPaintEx.DrawGlass(g, glassRect, 200, 0); g.Restore(gState); } if (drawBorder) { using (GraphicsPath path = GraphicsPathHelper.CreatePath( rect, roundWidth, style, false)) { using (Pen pen = new Pen(borderColor)) { g.DrawPath(pen, path); } } rect.Inflate(-1, -1); using (GraphicsPath path = GraphicsPathHelper.CreatePath( rect, roundWidth, style, false)) { using (Pen pen = new Pen(innerBorderColor)) { g.DrawPath(pen, path); } } } } else { g.FillRectangle(brush, rect); if (baseColor.A > 80) { Rectangle rectTop = rect; if (mode == LinearGradientMode.Vertical) { rectTop.Height = (int)(rectTop.Height * basePosition); } else { rectTop.Width = (int)(rect.Width * basePosition); } using (SolidBrush brushAlpha = new SolidBrush( Color.FromArgb(128, 255, 255, 255))) { g.FillRectangle(brushAlpha, rectTop); } } if (drawGlass) { RectangleF glassRect = rect; if (mode == LinearGradientMode.Vertical) { glassRect.Y = rect.Y + rect.Height * basePosition; glassRect.Height = (rect.Height - rect.Height * basePosition) * 2; } else { glassRect.X = rect.X + rect.Width * basePosition; glassRect.Width = (rect.Width - rect.Width * basePosition) * 2; } GraphicsState gState = g.Save(); g.SetClip(rect); ControlPaintEx.DrawGlass(g, glassRect, 200, 0); g.Restore(gState); } if (drawBorder) { using (Pen pen = new Pen(borderColor)) { g.DrawRectangle(pen, rect); } rect.Inflate(-1, -1); using (Pen pen = new Pen(innerBorderColor)) { g.DrawRectangle(pen, rect); } } } } } 声明: 本文版权归作者和CS 程序员之窗所有,欢迎转载,转载必须保留以下版权信息,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 作者:Starts_2000 出处:CS 程序员之窗 http://www.csharpwin.com。 你可以免费使用或修改提供的源代码,但请保留源代码中的版权信息,详情请查看: CS程序员之窗开源协议 http://www.csharpwin.com/csol.html。
C# 移动无边框的窗体
const int WM_NCHITTEST = 0x0084; const int HTLEFT = 10; const int HTRIGHT = 11; const int HTTOP = 12; const int HTTOPLEFT = 13; const int HTTOPRIGHT = 14; const int HTBOTTOM = 15; const int HTBOTTOMLEFT = 0x10; const int HTBOTTOMRIGHT = 17; protected override void WndProc(ref Message m) { base.WndProc(ref m); switch (m.Msg) { case WM_NCHITTEST: Point vPoint = new Point((int)m.LParam & 0xFFFF, (int)m.LParam >> 16 & 0xFFFF); vPoint = PointToClient(vPoint); if (vPoint.X <= 5) if (vPoint.Y <= 5) m.Result = (IntPtr)HTTOPLEFT; else if (vPoint.Y >= ClientSize.Height - 5) m.Result = (IntPtr)HTBOTTOMLEFT; else m.Result = (IntPtr)HTLEFT; else if (vPoint.X >= ClientSize.Width - 5) if (vPoint.Y <= 5) m.Result = (IntPtr)HTTOPRIGHT; else if (vPoint.Y >= ClientSize.Height - 5) m.Result = (IntPtr)HTBOTTOMRIGHT; else m.Result = (IntPtr)HTRIGHT; else if (vPoint.Y <= 5) m.Result = (IntPtr)HTTOP; else if (vPoint.Y >= ClientSize.Height - 5) m.Result = (IntPtr)HTBOTTOM; break; } } 多少也要注释一下吧 首先,要用到一个WimdowsAPI函数,因此必须引入 using System.Runtime.InteropServices; 命名空间; 然后,这里有两种方法,一种使用API, 一种不用,重写WndProc窗口过程的方式不需要API函数。另一个方法需要两个: SendMessage 像指定窗口过程发送消息 ReleaseCapture 释放鼠标捕获 最后是一些必要的常数声明,这些声明可以在MSDN或者CPP头文件中找到: private const int WM_SYSCOMMAND = 0x0112;//点击窗口左上角那个图标时的系统信息 private const int SC_MOVE = 0xF010;//移动信息 private const int HTCAPTION = 0x0002;//表示鼠标在窗口标题栏时的系统信息 private const int WM_NCHITTEST = 0x84;//鼠标在窗体客户区(除了标题栏和边框以外的部分)时发送的消息 private const int HTCLIENT = 0x1;//表示鼠标在窗口客户区的系统消息 private const int SC_MAXIMIZE = 0xF030;//最大化信息 private const int SC_MINIMIZE = 0xF020;//最小化信息 Here we go。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace WindowsApplicationTestNoBoarderAndMove { public partial class Form1 : Form { public Form1() { InitializeComponent(); } [DllImport("user32.dll")] public static extern bool ReleaseCapture(); [DllImport("user32.dll")] public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); private const int WM_SYSCOMMAND = 0x0112;//点击窗口左上角那个图标时的系统信息 private const int SC_MOVE = 0xF010;//移动信息 private const int HTCAPTION = 0x0002;//表示鼠标在窗口标题栏时的系统信息 private const int WM_NCHITTEST = 0x84;//鼠标在窗体客户区(除了标题栏和边框以外的部分)时发送的消息 private const int HTCLIENT = 0x1;//表示鼠标在窗口客户区的系统消息 private const int SC_MAXIMIZE = 0xF030;//最大化信息 private const int SC_MINIMIZE = 0xF020;//最小化信息 private void closeToolStripMenuItem_Click(object sender, EventArgs e) { Application.Exit(); } //下面的代码我用//注释了一下,这是两种实现方法 //private void Form1_MouseDown(object sender, MouseEventArgs e) //{ // ReleaseCapture();//首先释放鼠标焦点捕获,这样就不会再发出WM_NCHITTEST消息 // SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);//然后向当前窗体发送消息,消息是移动+表示鼠标在标题栏上 //} //如果用这种重写的方法,就把上面的部分注释掉…… /**/ protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_SYSCOMMAND: if (m.WParam == (IntPtr)SC_MAXIMIZE) { m.WParam = (IntPtr)SC_MINIMIZE; } break; case WM_NCHITTEST: //如果鼠标移动或单击 base.WndProc(ref m);//调用基类的窗口过程——WndProc方法处理这个消息 if (m.Result == (IntPtr)HTCLIENT)//如果返回的是HTCLIENT { m.Result = (IntPtr)HTCAPTION;//把它改为HTCAPTION return;//直接返回退出方法 } break; } base.WndProc(ref m);//如果不是鼠标移动或单击消息就调用基类的窗口过程进行处理 } //用后面这个重写的方法有个问题~~~ //你猜,如果你在窗体上双击鼠标,会发生什么?呵呵,窗体会最大化…… } }
C# 中双击标题栏关闭WinForm程序
很简单的一个C#中双击标题栏关闭WinForm程序,估计很多人在写程序的时候用的着,程序代码只有段段的几行。 public const int WM_NCLBUTTONDBLCLK = 0xA3; protected override void WndProc(ref Message m) { if (m.Msg == WM_NCLBUTTONDBLCLK) { this.Close(); } base.WndProc(ref m); }
C# 中重载窗体关闭事件
protected override void OnFormClosing(FormClosingEventArgs e) { if (MessageBox.Show("你确认要退出该程序吗?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes) base.OnFormClosing(e); else e.Cancel = true; }
C#winform圆角窗体绘制
一、下面是一个绘制方法的静态类 废话不说直接上代码: using System; using System.Collections.Generic; using System.Text; //其它命名空间 using System.Windows.Forms; using System.Drawing; using System.Drawing.Drawing2D; namespace Tools.UserClass { public static class RoundFormPainter { public static void Paint(this object sender, PaintEventArgs e) { Form form = ((Form)sender); List<Point> list = new List<Point>(); int width = form.Width; int height = form.Height; //左上 list.Add(new Point(0, 5)); list.Add(new Point(1, 5)); list.Add(new Point(1, 3)); list.Add(new Point(2, 3)); list.Add(new Point(2, 2)); list.Add(new Point(3, 2)); list.Add(new Point(3, 1)); list.Add(new Point(5, 1)); list.Add(new Point(5, 0)); //右上 list.Add(new Point(width - 5, 0)); list.Add(new Point(width - 5, 1)); list.Add(new Point(width - 3, 1)); list.Add(new Point(width - 3, 2)); list.Add(new Point(width - 2, 2)); list.Add(new Point(width - 2, 3)); list.Add(new Point(width - 1, 3)); list.Add(new Point(width - 1, 5)); list.Add(new Point(width - 0, 5)); //右下 list.Add(new Point(width - 0, height - 5)); list.Add(new Point(width - 1, height - 5)); list.Add(new Point(width - 1, height - 3)); list.Add(new Point(width - 2, height - 3)); list.Add(new Point(width - 2, height - 2)); list.Add(new Point(width - 3, height - 2)); list.Add(new Point(width - 3, height - 1)); list.Add(new Point(width - 5, height - 1)); list.Add(new Point(width - 5, height - 0)); //左下 list.Add(new Point(5, height - 0)); list.Add(new Point(5, height - 1)); list.Add(new Point(3, height - 1)); list.Add(new Point(3, height - 2)); list.Add(new Point(2, height - 2)); list.Add(new Point(2, height - 3)); list.Add(new Point(1, height - 3)); list.Add(new Point(1, height - 5)); list.Add(new Point(0, height - 5)); Point[] points = list.ToArray(); GraphicsPath shape = new GraphicsPath(); shape.AddPolygon(points); //将窗体的显示区域设为GraphicsPath的实例 form.Region = new System.Drawing.Region(shape); } } } 二、调用 1窗体的FormBorderStyle属性设置为None 2在窗体Paint事件中加入以下代码 Tools.UserClass.RoundFormPainter.Paint(sender, e);
C#窗体阴影
C#窗体阴影 using System.Runtime.InteropServices; 然后再窗口类的随便哪个地方加上: const int CS_DROPSHADOW = 0x20000; const int GCL_STYLE = (-26); //声明Win32 API [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern int SetClassLong(IntPtr hwnd,int nIndex,int dwNewLong); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern int GetClassLong(IntPtr hwnd, int nIndex); 最后在窗体的构造函数中加上: SetClassLong(this.Handle, GCL_STYLE, GetClassLong(this.Handle, GCL_STYLE) | CS_DROPSHADOW);
using System.Runtime.InteropServices; 然后再窗口类的随便哪个地方加上: const int CS_DROPSHADOW = 0x20000; const int GCL_STYLE = (-26); //声明Win32 API [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern int SetClassLong(IntPtr hwnd,int nIndex,int dwNewLong); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern int GetClassLong(IntPtr hwnd, int nIndex); 最后在窗体的构造函数中加上: SetClassLong(this.Handle, GCL_STYLE, GetClassLong(this.Handle, GCL_STYLE) | CS_DROPSHADOW);
C#调用API函数给Winform窗体添加动态特效
想让你的Winform窗体美化得更炫、更美丽,光是有漂亮的C#皮肤、背景贴图等这些静态的部分是远远不够的,还需要有一些动态部分的加持才能让你的程序界面有更好的用户体验。 这里要介绍的是调用user32.dll中的API函数来给Winform界面添加动态特效。user32.dll是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息。与C++一样,在C#中同样可以利用user32里面的一些API函数来开发WINFORM程序。 1.导入user32.dll并声明API函数AnimateWindow //导入user32.dll [System.Runtime.InteropServices.DllImport("user32")] //声明API函数 private static extern bool AnimateWindow(IntPtr hwnd, int dwTime, int dwFlags); AnimateWindow函数里面的3个传参的说明如下: hwnd 界面上控件的句柄 dwTime 窗体特效执行的持续时间(1=1毫秒、1000=1秒) dwFlags 窗体特效的值 2.dwFlags要传的参数是一些INT类型的常量,这些常量定义了该特效具体有哪些动作。 //正面_水平方向 const int AW_HOR_POSITIVE = 0x0001; //负面_水平方向 const int AW_HOR_NEGATIVE = 0x0002; //正面_垂直方向 const int AW_VER_POSITIVE = 0x0004; //负面_垂直方向 const int AW_VER_NEGATIVE = 0x0008; //由中间四周展开或由四周向中间缩小 const int AW_CENTER = 0x0010; //隐藏对象 const int AW_HIDE = 0x10000; //显示对象 const int AW_ACTIVATE = 0x20000; //拉幕滑动效果 const int AW_SLIDE = 0x40000; //淡入淡出渐变效果 const int AW_BLEND = 0x80000; 当然编写代码的时候可以将这些INT值全部放含在一个枚举类中,这样在程序里引用起来会更方便 3.在程序事件中调用AnimateWindow方法,执行窗体特效。 //动画——窗体由四周向中心缩小直至消失 //AW_CENTER | AW_HIDE | AW_HOR_NEGATIVE表示三种特效状态的集合,以“|”间隔,这和C++上调用API函数差不多 //this.Handle为主窗体的句柄,用其他控件的句柄亦可 AnimateWindow(this.Handle, 1000, AW_CENTER | AW_HIDE | AW_HOR_NEGATIVE); 4.这里给个为Winform窗体添加动态特效的程序例子:Sample
C#获取动态代码的值
通过字符串对控件属性赋值 例如:"BackColor=Color.FromArgb(100,100,100);BackGroundimage=Image.FromFile(\"XXX\")" 其中最关键的部分算是获取动态代码的值.以下为获取动态代码值的类,不足之处还请指正. ------------------------------------------------ usingMicrosoft.CSharp; usingSystem.Reflection; using System.CodeDom.Compiler; public static class CSharpCodeValueHelper<T> { /// <summary> /// 编译器实例 /// </summary> private static CSharpCodeProvider CSharpCodeProvider { get; set; } /// <summary> /// 编译器参数 /// </summary> private static CompilerParameters CompilerParameters { get; set; } /// <summary> /// 构造函数 /// </summary> static CSharpCodeValueHelper() { CSharpCodeProvider = new CSharpCodeProvider(); CompilerParameters = new CompilerParameters(); CompilerParameters.ReferencedAssemblies.Add("System.dll"); CompilerParameters.ReferencedAssemblies.Add("System.Data.dll"); CompilerParameters.ReferencedAssemblies.Add("System.Deployment.dll"); CompilerParameters.ReferencedAssemblies.Add("System.Drawing.dll"); CompilerParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll"); CompilerParameters.ReferencedAssemblies.Add("System.Xml.dll"); CompilerParameters.GenerateExecutable = false; CompilerParameters.GenerateInMemory = true; } /// <summary> /// 获取代码的值 /// </summary> /// <param name="CSharpCode">CSharpCode代码</param> /// <returns>动态CSharpCode代码的值</returns> public static T GetCodeValue(string CSharpCode) { CompilerResults compilerResults = CSharpCodeProvider.CompileAssemblyFromSource(CompilerParameters, CreateCode(CSharpCode)); if (compilerResults.Errors.HasErrors) { string errorString = string.Empty; errorString += "编译错误:\n"; foreach (CompilerError err in compilerResults.Errors) { errorString += err.ErrorText + "\n"; } throw new Exception(errorString); } else { // 通过反射,调用动态类DynamicClass实例 Assembly assembly = compilerResults.CompiledAssembly; object dynamicClass = assembly.CreateInstance("DynamicNamespace.DynamicClass"); MethodInfo methodInfo = dynamicClass.GetType().GetMethod("GetValue"); return (T)methodInfo.Invoke(dynamicClass, null); } } /// <summary> /// 创建代码 /// </summary> /// <param name="CSharpCode">CSharpCode代码</param> /// <returns>创建完成的代码</returns> private static string CreateCode(string CSharpCode) { StringBuilder strBuilder = new StringBuilder(); strBuilder.AppendLine("using System;"); strBuilder.AppendLine("using System.Collections.Generic;"); strBuilder.AppendLine("using System.ComponentModel;"); strBuilder.AppendLine("using System.Data;"); strBuilder.AppendLine("using System.Drawing;"); strBuilder.AppendLine("using System.Text;"); strBuilder.AppendLine("using System.Windows.Forms;"); strBuilder.AppendLine("namespace DynamicNamespace"); strBuilder.AppendLine("{"); strBuilder.AppendLine(" public class DynamicClass"); strBuilder.AppendLine(" {"); strBuilder.AppendLine(" public object GetValue()"); strBuilder.AppendLine(" {"); strBuilder.AppendLine(" return " + CSharpCode + ";"); strBuilder.AppendLine(" }"); strBuilder.AppendLine(" }"); strBuilder.AppendLine("}"); string code = strBuilder.ToString(); return code; } } 下面是调用(注意调用时特殊字符的转义) 1 Color coor = CSharpCodeValueHelper<Color>.GetCodeValue("Color.FromArgb(100,100,100)"); 2 3 4 Image img = CSharpCodeValueHelper<Image>.GetCodeValue("Image.FromFile(\"C:\\\\tu.jpg\")");
C#实现FORM界面美化
C#实现FORM界面美化 分类: 乱写写 2010-05-22 20:50 438人阅读 评论(0) 收藏 举报 原创作者:『DYlike』 引用『DYlike』老兄写的类基础上,加上几行代码就可以美化windowsform界面... 再找几张png格式的图片 首先下载和引用:『DYlike』写的类地址:http://www.dylike-soft.com/upfile/2009/8/2009817235113385.RAR, 然后在要实现美化的界面的load事件里面写如下代码: Form1 f1 = new Form1(); f1.Load += new EventHandler(Form1_Load); string path; path = "D://照片//1.png";//path图片地址 Bitmap png; png = new Bitmap(path); DYD.DYD dyd = new DYD.DYD(); dyd.UserKey = "D";//授权码 dyd.DrawBP(this, png, 255);//DrawBP(要显示的目标窗体,PNG图,透明度) 添加如下方法: protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle = cp.ExStyle | 0x80000; return cp; } } 就可以实现以下效果:
C#实现FORM界面美化 分类: 乱写写 2010-05-22 20:50 438人阅读 评论(0) 收藏 举报 原创作者:『DYlike』 引用『DYlike』老兄写的类基础上,加上几行代码就可以美化windowsform界面... 再找几张png格式的图片 首先下载和引用:『DYlike』写的类地址:http://www.dylike-soft.com/upfile/2009/8/2009817235113385.RAR, 然后在要实现美化的界面的load事件里面写如下代码: Form1 f1 = new Form1(); f1.Load += new EventHandler(Form1_Load); string path; path = "D://照片//1.png";//path图片地址 Bitmap png; png = new Bitmap(path); DYD.DYD dyd = new DYD.DYD(); dyd.UserKey = "D";//授权码 dyd.DrawBP(this, png, 255);//DrawBP(要显示的目标窗体,PNG图,透明度) 添加如下方法: protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle = cp.ExStyle | 0x80000; return cp; } } 就可以实现以下效果:
C#实现窗体圆角的一种方法
public void SetWindowRegion() { GraphicsPath FormPath; FormPath = new System.Drawing.Drawing2D.GraphicsPath(); Rectangle rect = new Rectangle(-1, -1, this.Width + 1, this.Height); FormPath = GetRoundedRectPath(rect, 24); 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, 185, 90); // 右上角 arcRect.X = rect.Right - diameter; path.AddArc(arcRect, 275, 90); // 右下角 arcRect.Y = rect.Bottom - diameter; path.AddArc(arcRect, 356, 90); // 左下角 arcRect.X = rect.Left; arcRect.Width += 2; arcRect.Height += 2; path.AddArc(arcRect, 90, 90); path.CloseFigure(); return path; }
C#圆角矩形窗体的绘制
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Drawing.Drawing2D; namespace TestFrm { public partial class TestFrm : Form { //定义鼠标消息常量 private const int WM_NCHITTEST = 0X0084; private const int HT_LEFT = 10; private const int HT_RIGHT = 11; private const int HT_TOP = 12; private const int HT_TOPLEFT = 13; private const int HT_TOPRIGHT = 14; private const int HT_BOTTOM = 15; private const int HT_BOTTOMLEFT = 16; private const int HT_BOTTOMRIGHT = 17; private const int HT_CAPTION = 2; //处理Windows消息 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); } public TestFrm() { InitializeComponent(); } 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; } private void Form1_Resize(object sender, EventArgs e) { //采用界面二重缓冲 SetStyle(ControlStyles.SupportsTransparentBackColor, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.DoubleBuffer, true); this.Refresh(); SetWindowRegion(); } string curFileName=""; Bitmap curBitmap; private void btnOpen_Click(object sender, EventArgs e) { } private void labOpfile_Click(object sender, EventArgs e) { OpenFileDialog opfile = new OpenFileDialog(); opfile.Title = "请选择一个图像"; opfile.Multiselect = true; opfile.Filter = "所有图像文件|*.jpg;*.png;*.bmp;*.gif"; if (opfile.ShowDialog() == DialogResult.OK) { try { curFileName = opfile.FileName; curBitmap = (Bitmap)Image.FromFile(curFileName); this.BackgroundImage = (Image)curBitmap; } catch (Exception ex) { MessageBox.Show(ex.Message); } } } } }
c#边框窗体阴影效果
public void SetWindowRegion() { GraphicsPath FormPath; FormPath = new System.Drawing.Drawing2D.GraphicsPath(); Rectangle rect = new Rectangle(-1, -1, this.Width + 1, this.Height); FormPath = GetRoundedRectPath(rect, 24); 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, 185, 90); 右上角 arcRect.X = rect.Right - diameter; path.AddArc(arcRect, 275, 90); 右下角 arcRect.Y = rect.Bottom - diameter; path.AddArc(arcRect, 356, 90); 左下角 arcRect.X = rect.Left; arcRect.Width += 2; arcRect.Height += 2; path.AddArc(arcRect, 90, 90); path.CloseFigure(); return path; }
创建无边框窗体并可调大小
本例创建一个无边框窗体,并加入鼠标事件,通过操纵PictureBox调整窗体大小,程序运行如下图所示。 窗体程序如下所示。 using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; namespace eg35_noborderApp{ public partial class MainForm : Form { static int frmLastWidth=0; static int frmLastHeight=0; static int frmWidth; static int frmHeight; static bool frmIsResizing=false; System.Drawing.Rectangle frmRectangle=new System.Drawing.Rectangle(); public MainForm() { InitializeComponent(); } void Button1Click(object sender, EventArgs e) { this.Close(); } void PictureBox1MouseDown(object sender, MouseEventArgs e) { frmRectangle.Location=new System.Drawing.Point(this.Left,this.Top); frmRectangle.Size=new System.Drawing.Size(frmWidth,frmHeight); ControlPaint.DrawReversibleFrame(frmRectangle,Color.Empty,System.Windows.Forms.FrameStyle.Thick); } void PictureBox1MouseUp(object sender, MouseEventArgs e) { frmIsResizing=false; frmRectangle.Location=new System.Drawing.Point(this.Left,this.Top); frmRectangle.Size=new System.Drawing.Size(frmWidth,frmHeight); ControlPaint.DrawReversibleFrame(frmRectangle,Color.Empty,System.Windows.Forms.FrameStyle.Thick); this.Width=frmWidth; this.Height=frmHeight; } void PictureBox1MouseMove(object sender, MouseEventArgs e) { if(e.Button==MouseButtons.Left) { int sizeageX=(MousePosition.X-this.Location.X); int sizeageY=(MousePosition.Y-this.Location.Y); if(sizeageX<120) sizeageX=120; if(sizeageY<81) sizeageY=81; frmWidth=sizeageX; frmHeight=sizeageY; if(frmLastWidth==0) frmLastWidth=frmWidth; if(frmLastHeight==0) frmLastHeight=frmHeight; if(frmIsResizing) { frmRectangle.Location=new System.Drawing.Point(this.Left,this.Top); frmRectangle.Size=new System.Drawing.Size(frmLastWidth,frmLastHeight); } frmIsResizing=true; ControlPaint.DrawReversibleFrame(frmRectangle,Color.Empty,System.Windows.Forms.FrameStyle.Thick); frmLastWidth=frmWidth; frmLastHeight=frmHeight; frmRectangle.Location=new System.Drawing.Point(this.Left,this.Top); frmRectangle.Size=new System.Drawing.Size(frmWidth,frmHeight); ControlPaint.DrawReversibleFrame(frmRectangle,Color.Empty,System.Windows.Forms.FrameStyle.Thick); } } } }
读取word表格数据
传三个参数 ,word文档的路径,行的索引,列的索引,索引都是从1开始的哦 引用Microsoft.Office.Interop.Word using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using Microsoft.Office.Interop.Word; using System.Data; public class WordOper { #region public string ReadWord(string fileName, int rowIndex, int colIndex) { ApplicationClass cls = null; Document doc = null; Microsoft.Office.Interop.Word.Table table = null; object missing = Missing.Value; object path = fileName; cls = new ApplicationClass(); try { doc = cls.Documents.Open (ref path, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing); table = doc.Tables[1]; string text = table.Cell(rowIndex, colIndex).Range.Text.ToString(); text = text.Substring(0, text.Length - 2); //去除尾部的mark return text; } catch (Exception ex) { return ex.Message; } finally { if (doc != null) doc.Close(ref missing, ref missing, ref missing); cls.Quit(ref missing, ref missing, ref missing); } } #endregion } 需要添加的引用参考(1) public class WordTableRead { #region private string fileName; private ApplicationClass cls = null; private Document doc = null; private Microsoft.Office.Interop.Word.Table table = null; private object missing = Missing.Value; //Word是否处于打开状态 private bool openState; /// <summary> /// 自定义构造方法 /// </summary> /// <param name="fileName">包含路径的文件名</param> public WordTableRead(string fileName) { this.fileName = fileName; } /// <summary> /// 打开Word文档 /// </summary> public void Open() { object path = fileName; cls = new ApplicationClass(); try { doc = cls.Documents.Open (ref path, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing); openState = true; } catch { openState = false; } } /// <summary> /// 返回指定单元格中的数据 /// </summary> /// <param name="tableIndex">表格号</param> /// <param name="rowIndex">行号</param> /// <param name="colIndex">列号</param> /// <returns>单元格中的数据</returns> public string ReadWord(int tableIndex, int rowIndex, int colIndex) { //Give the value to the tow Int32 params. try { if (openState == true) { table = doc.Tables[tableIndex]; string text = table.Cell(rowIndex, colIndex).Range.Text.ToString(); text = text.Substring(0, text.Length - 2); //去除尾部的mark return text; } else { return ""; } } catch (Exception ee) { return ee.ToString(); } } public DataTable WordTable(int tableIndex) { DataTable dt = new DataTable(); if (openState == true) { table = doc.Tables[tableIndex]; for (int ii = 0; ii < table.Columns.Count; ii++) { dt.Columns.Add("cl" + ii.ToString(), typeof(string)); } for (int ii = 0; ii < table.Rows.Count; ii++) { DataRow rw = dt.NewRow(); for (int jj = 0; jj < table.Columns.Count; jj++) { string text = table.Cell(ii + 1, jj + 1).Range.Text.ToString(); //string text = table.Rows[ii].Cells[jj].ToString(); text = text.Substring(0, text.Length - 2); rw["cl" + (jj).ToString()] = text; } dt.Rows.Add(rw); } } return dt; } /// <summary> /// 关闭Word文档 /// </summary> public void Close() { if (openState == true) { if (doc != null) doc.Close(ref missing, ref missing, ref missing); cls.Quit(ref missing, ref missing, ref missing); } } #endregion } 需要的参数实例化的时候传word文档的路径 用法 WordTableRead wtr = new WordTableRead(TextBoxPath.Text); wtr.Open(); wtr.ReadWord(tableIndex, int rowIndex, int colIndex) //表格,行,列的索引值,都是从1开始的哦 wtr.Close();
使用C#实现移动无边框窗体
转载于http://q.163.com/csharpok/blog/zhplive/268151862007493204439/all/#268151862007493204439 其实这是个让人说过无数次的内容,但是最近在写一个测试小程序的时候发现了一个问题,今天没什么事做,就做个小的总结。 通过拖动窗体的客户区来移动一个窗体并不是很新鲜的内容,很多的程序都用到了这一点,尤其是一些可以换肤的程序。 这篇文章并不打算详细论述如何在C#下实现这一功能,因为它的代码实在是简单得不能再简单。这里简单说一下实现的原理: 首先说一个概念——窗体的客户区,窗体的客户区指的是一个窗体除了标题栏和边框以外的部分。 当我们的鼠标在窗体中移动的时候,会触发WM_NCHITTEST系统消息,MSDN中对这个消息的说明为:The WM_NCHITTEST message is sent to a window when the cursor moves, or when a mouse button is pressed or released. If the mouse is not captured, the message is sent to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse. (当光标移动或一个鼠标键被按下或释放时,WM_NCHITTEST消息会被发送到一个窗口中,如果光标没有被捕获,这个消息被送到光标下的窗口。否则这个消息被送到捕获了光标的窗口。) 这个消息被默认的(请注意是“默认的”)窗口过程(窗口过程这个概念后面再说)处理后,会根据触发这个消息时鼠标的位置返回一个值,例如当鼠标在窗口的标题栏上时,返回HTCAPTION;当鼠标在一个窗口的客户区中时,返回HTCLIENT;如果鼠标指向某个窗口的字窗口的“关闭”按钮或系统菜单(就是点击窗口图标后出现的那个菜单),就返回HTSYSMENU。 所以我们要做的就是骗!我们要欺骗Windows,当我们的鼠标在窗体的客户区中移动时,默认的窗口过程处理后会返回HTCLIENT,Windows系统根据这个值进行相应的操作,把适当的消息插入到应用程序的消息队列(这个概念同样在后面讨论)中。 这时如果我们做一些改变,人为地修改窗口过程的返回值,把HTCLIENT修改为HTCAPTION并返回给系统,系统就会认为鼠标这时在窗体的标题栏中,而拖动标题栏可以移动一个窗体,所以当我们在一个被这样修改后的应用程序的客户区按下鼠标并拖动时,Windows会认我们在拖动一个窗体的标题栏,于是它把一个移动窗体的消息插入到程序的消息队列中,再经过窗口过程的处理,就实现了我们需要的功能——拖动窗体的客户区移动窗体。 于是就有了下面的代码: protected override WndProc(ref message m) { switch (m.Msg) { case WM_NCHITTEST: //如果鼠标移动或单击 base.WndProc(ref m);//调用基类的窗口过程——WndProc方法处理这个消息 if (m.Result == (IntPtr)HTCLIENT)//如果返回的是HTCLIENT { m.Result = (IntPtr)HTCAPTION;//把它改为HTCAPTION return;//直接返回退出方法 } break; } base.WndProc(ref m);//如果不是鼠标移动或单击消息就调用基类的窗口过程进行处理 } 这也是MSDN上的一个例子,重写窗体的WndProc方法,判断消息然后返回。 我本来也是想这样就完事了,可是后来测试的时候却发现有个大问题:双击窗体的时候,窗体会最大化。 那天脑子有点迷糊,也没多想就到网上问了一下,一个高手提醒我说可能是那个重写的窗口过程的问题,于是一下子明白了。我们向Windows传递了假信息,Windows我们在窗体的客户区双击鼠标在Windows看来是双击了窗体的标题栏,理所当然的Windows会告诉窗口过程窗体需要最大化,窗口过程又理所当然的照做了,于是就出现了这样的现象。 刚开始的时候还不是很确定这样想对不对,不过后来出现的另一个现象证实了这个推断是正确的: 因为窗体没有标题栏,每次退出程序都要按Alt+F4实在是比较不爽,我就给窗体添加了一个ContextMenuStrip,只有一个菜单项用来关闭窗体退出程序。我发现当我修改了窗体的默认窗口过程后,这个右键菜单就显示不出来了。出现这个现象的原因只能有一个——Windows真的把窗体的客户区当成标题栏处理了,而默认ContextMenuStrip只能用在窗体的客户区或控件上。 后来我又跟那位高手讨论了一下,他给我提供了另一种方法,这个方法需要两个API函数: LRESULT SendMessage( HWND hWnd,// handle of destination window UINT Msg,// message to send WPARAM wParam,// first message parameter LPARAM lParam // second message parameter ); BOOL ReleaseCapture(VOID) SendMessage函数想必不用多说了,无数个木马制作教学贴里都有详细的描述,这个函数用来向指定的窗体发送Windows消息,功能的确十分强大^_^ ReleaseCapture函数相对陌生一些,这个函数用来释放被当前线程中某个窗口捕获的光标。 他给出的代码是这样的: private void Form1_MouseDown(object sender, MouseEventArgs e) { ReleaseCapture(); SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0); } 也就是说,在窗体的MouseDown(鼠标按下)事件中,首先释放光标,然后向窗口过程发送WM_SYSCOMMAND消息。 说实话这个方式的SendMessage函数调用我也是第一次遇到,刚开始怎么也不明白为什么要把它们(SC_MOVE 和 HTCAPTION)用一个加号连接起来。 这个WM_SYSCOMMAND消息包含了一些信息表示用户要进行的操作,消息的wParam字段表示用户要最大化、最小化或移动窗体。 我去掉HTCAPTION试了一下,每当我在窗体上按下鼠标左键时,鼠标就会移动到窗体的最顶端——原来标题栏的位置,与我们在系统菜单中选择“移动”菜单项的效果一样。于是查阅MSDN,在WM_SYSCOMMAND的帮助中查到这样一句话:In WM_SYSCOMMAND messages, the four low-order bits of the uCmdType parameter are used internally by Windows. To obtain the correct result when testing the value of uCmdType, an application must combine the value 0xFFF0 with the uCmdType value by using the bitwise AND operator. (在WM_SYSCOMMAND消息中,uCmdType的低四位是Windows内部使用的。如果测试时要获得uCmdType的正确结果,应用程序必须把0xFFF0这个值与uCmdType的值通过位相加的方式合并在一起。)于是豁然开朗:这个所谓的“Windows内部使用的值”在移动这个窗体的时候其实就是表示“窗体的标题栏”,所以我们使用SC_MOVE + HTCAPTION表示窗体将被移动且目前鼠标正在窗体的标题栏中。 至于这里为什么要先释放光标再发送消息,根据前面的WM_NCHITTEST消息的说明,如果光标被当前窗口捕获,那么当鼠标移动时,就会发送WM_NCHITTEST到我们的窗体,而由于我们这时没有重写窗口过程,这个消息会被按照默认的方式处理,Windows会发现鼠标在窗体的客户区移动,SendMessage发过去的HTCAPTION被WM_NCHITTEST消息中的HTCLIENT覆盖,这样窗体就不会有任何动作。 还有两个名词解释: 窗口过程:窗口过程是一个应用程序定义的、用来处理Windows消息的回调(CallBack)函数,当有消息发生时,窗口过程负责处理消息。 消息队列:Windows会把有关一个应用程序的全部消息放到一块内存区域中,这个区域使用一种先进先出(FIFO)的方式工作,就是说最先进入这个区域的消息会第一个离开这个区域,故称消息队列。应用程序从消息队列中取出一条消息,进行相应的处理,返回一定的信息,然后再取出下一条处理。 PS:我手头只有一份Win32 Developer's References,是以前从一张Delphi的碟里扒下来的。里面的说明不是很详细,有份Platform SDK就好多了,55555~~~~具体代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } [DllImport("user32.dll", EntryPoint = "SendMessage")] public static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam); [DllImport("user32.dll", EntryPoint = "ReleaseCapture")] public static extern int ReleaseCapture(); public const int WM_SysCommand = 0x0112; public const int SC_MOVE = 0xF012; private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { ReleaseCapture(); SendMessage(this.Handle, WM_SysCommand, SC_MOVE,0 ); } } }
无边框窗体的移动
无边框窗体的移动(C#)(转载) 2009-12-08 20:37 来自 清茶一杯(北斗星) C#无标题窗体移动 注意窗体上的控件是否把窗体覆盖了。。。MouseDown、MouseMove、MouseUp事件应该是鼠标所处位置最顶层的控件的事件 在窗体的类中声明两个变量 private Point mouseOffset; //记录鼠标指针的坐标 private bool isMouseDown = false; //记录鼠标按键是否按下 创建该窗体 MouseDown、MouseMove、MouseUp事件的相应处理程序 private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { int xOffset; int yOffset; if (e.Button == MouseButtons.Left) { xOffset = -e.X ; yOffset = -e.Y ; mouseOffset = new Point(xOffset, yOffset); isMouseDown = true; } } private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) { if (isMouseDown) { Point mousePos = Control.MousePosition; mousePos.Offset(mouseOffset.X, mouseOffset.Y); Location = mousePos; } } private void Form1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { // 修改鼠标状态isMouseDown的值 // 确保只有鼠标左键按下并移动时,才移动窗体 if (e.Button == MouseButtons.Left) { isMouseDown = false; } }
下面是第二种方式。 代码:[csharp] view plaincopyprint? public void SetWindowRegion() { GraphicsPath FormPath; FormPath = new System.Drawing.Drawing2D.GraphicsPath(); Rectangle rect = new Rectangle(-1, -1, this.Width + 1, this.Height); FormPath = GetRoundedRectPath(rect, 24); 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, 185, 90); // 右上角arcRect.X = rect.Right - diameter; path.AddArc(arcRect, 275, 90); // 右下角arcRect.Y = rect.Bottom - diameter; path.AddArc(arcRect, 356, 90); // 左下角arcRect.X = rect.Left; arcRect.Width += 2; arcRect.Height += 2; path.AddArc(arcRect, 90, 90); path.CloseFigure(); return path;}重写的OnPaint方法里调用SetWindowRegion.
一个可以闪烁的背景
一个可以闪烁的背景 2008-06-15 19:12 47人阅读 评论(0) 收藏 举报 private Image im; private void Form1_Load(object sender, EventArgs e) { this.im = Image.FromFile(@ "C:/aaa.jpg "); Thread t = new Thread(new ThreadStart(this.showback)); t.IsBackground = !t.IsBackground; t.Start(); } private void showback() { while (true) { this.BackgroundImage = this.im; Thread.Sleep(1000); this.BackgroundImage = null; } }
用鼠标拖动改变无边框窗体的大小
无边框窗体是无法向其他普通窗体一样用鼠标拖动边框来改变其大小的,一方面因为窗体样式中没有了WS_ThickFrame,另一方面就是因为窗体没有边框来施行拖动操作。 通过 SPY++ 的监视,终于发现了解决途径,我们要解决2方面的问题: 1、模拟出窗体边框,让Windows知道我们的Form中哪部分是客户区,哪部分是边框(可以通过在客户区内计算来区分)。 2、在我们模拟的边框范围内,截取 WM_NCHITTEST 消息,将其返回值做修改,返回拖动类型(上、下、左、右、左上、右上、左下、右下) 代码示例: 1 protected override void WndProc(ref Message m) 2 { 3 const int WM_NCHITTEST = 0x0084; 4 5 6 int HTCLIENT = 1; 7 int HTLEFT = 10; 8 int HTRIGHT = 11; 9 int HTTOP = 12; 10 int HTTOPLEFT = 13; 11 int HTTOPRIGHT = 14; 12 int HTBOTTOM = 15; 13 int HTBOTTOMLEFT = 16; 14 int HTBOTTOMRIGHT = 17; 15 16 int offset = 3; 17 switch (m.Msg) 18 { 19 case WM_NCHITTEST: 20 int px = Form.MousePosition.X - this.Left ; 21 int py = Form.MousePosition.Y - this.Top; 22 23 int temp; 24 25 if (px >= this.Width - offset) 26 { 27 if (py <= offset) temp = HTTOPRIGHT; 28 else if (py >= this.Height - offset) temp = HTBOTTOMRIGHT; 29 else temp = HTRIGHT; 30 } 31 else if (px <= offset) 32 { 33 if (py <= offset) temp = HTTOPLEFT; 34 else if (py >= this.Height - offset) temp = HTBOTTOMLEFT; 35 else temp = HTLEFT; 36 } 37 else 38 { 39 if (py <= offset) temp = HTTOP; 40 else if (py >= this.Height - offset) temp = HTBOTTOM; 41 else temp = HTCLIENT; 42 } 43 44 m.Result = (IntPtr)temp; 45 break; 46 default: 47 base.WndProc(ref m); 48 break; 49 } 50 } ================================= 2006-7-5 -- 今天发现以上方法在窗体拥有 WS_SYSMENU 样式的时候不起作用了,于是试着给窗体加上 WS_ThickFrame,加上以后窗体可以拖动,但是在窗体周围却出现了难看的 windows 凹凸边框,本想把扩展样式 EX_WindowEDGE 去掉,却发现去不掉,郁闷。 最后只好用笨办法,在拖动的时候把 WS_SYSMENU 去掉,拖动完成后又把 WS_SYSMENU 加回来....