模拟时钟 要求如下: 1. 修改窗体形状为圆形 2. 提供时针、分针、秒针,并且每秒都要重新绘制它们以显示在合适的位置 3. 能用鼠标左键拖动窗体来移动模拟时钟的位置 目的: 1、熟悉Pen、Brush、Color、Font、Bitmap等对象的常用属性和方法 2、掌握Graphics对象的常用绘图方法 先上个效果图,再慢慢详解。首先制作圆形窗体,先用绘图工具绘出一张圆形的图,中间填充色,背景色为白色, 然后设置WinForm窗体选择窗体,找到BackgroundImage属性,点击打开新的窗口,选择下面的导入资源文件,选择你的不规则的BMP图片, 找到窗体的TansparencyKey,将它设置为你背景图片的背景色(白色色) 找到窗体的FormBorderStyle,将其设置为none,即不显示标题栏。 这个时候显示的是一个圆形的窗体,但是实际上不是圆形的,只是其他的边角被隐藏了,还需要通过 this .Region= new Region(GraphicPath gpath)裁剪一下,这样才是真正你要的形状,在下边的代码中会详细介绍。 这是开始涉及具体的编写: private Thread timeThread;声明一个线程,不断的对页面进行重绘 private Point mouseOffset;定义鼠标的位置 private float r;定义所绘表盘的半径 private PointF center;定义中心点 private bool isMouseDown = false ;标记鼠标是否按下 private Graphics g = null ; 实现窗体的拖拽、移动:主要涉及了Mouse_Move ,Mouse_Down ,Mouse_Up事件,一一介绍: /// <summary> /// 鼠标按下事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form2_MouseDown( object sender, MouseEventArgs e) { int x, y; if (e.Button == MouseButtons.Left) { x = -e.X - SystemInformation.FrameBorderSize.Width;<br> //ystemInformation.FrameBorderSize.Width获取正在拖动调整大小窗口周围绘制的大小调整边框的粗细水平分量 y = -e.Y - SystemInformation.FrameBorderSize.Height - SystemInformation.CaptionHeight;<br> //SystemInformation.CaptionHeight 获取窗口的标准标题栏区域的高度 mouseOffset = new Point(x, y); isMouseDown = true ; } } /// <summary> ///鼠标移动事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form2_MouseMove( object sender, MouseEventArgs e) { if (isMouseDown) { Point mPoint = Control.MousePosition; //获取鼠标光标的位置 mPoint.Offset(mouseOffset.X, mouseOffset.Y); //设定鼠标平移指定量 Location = mPoint; } } /// <summary> /// 鼠标抬起事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form2_MouseUp( object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { isMouseDown = false ; } } 至此就可以使用拖拉、移动。 结接下来就是主要实现表盘、指针的绘制和移动 //重写绘图事件 protected override void OnPaint(PaintEventArgs e) { g = e.Graphics; g.SmoothingMode = SmoothingMode.HighQuality; //高质呈现画面 //绘制出一个圆弧(这里是一个圆) g.DrawArc( new Pen(Color.Black, 0.5f), new RectangleF(center.X - r, center.Y - r, 2 * r - 3, 2 * r - 3), 0, 360); GraphicsPath round = new GraphicsPath(); //向当前图像追加一段圆弧 round.AddArc( new RectangleF(center.X - r, center.Y - r, 2 * r - 3, 2 * r - 3), 0, 360); Region = new Region(round); //用上边所画的图形创建一个区域(相当于将多余的区域裁剪) for ( int i = 0; i < 59; i++) { g.ResetTransform(); //重置为单位矩阵 g.TranslateTransform(center.X, center.Y); // 通过左乘指定的平移来更改系统的坐标原点 g.RotateTransform(i*6); //旋转 ,每一秒旋转6度 if ((i==0)||(i%5==4)) //绘制表盘的刻度 { g.DrawLine( new Pen(Color.Black,2.5f),r-12,0,r-5,0); //小时标准刻度 } else { g.DrawLine( new Pen (Color.Black,0.5f),r-6,0,r-5,0); //分钟标准刻度 } } float hour, minute, second; hour = DateTime.Now.Hour; minute = DateTime.Now.Minute; second = DateTime.Now.Second; hour = hour + minute / 60f + second / 3600f; minute = minute + second / 60f; g.ResetTransform(); g.TranslateTransform(center.X, center.Y); //画时针 g.RotateTransform(hour * 30 + 270 - 6); g.DrawLine( new Pen(Color.Black,2.5f),0,0,r*0.5f,0f); //绘出时针 g.ResetTransform(); //画分针 ,坐标系恢复到默认状态,Graphics对象回到默认坐标系中绘图。 g.TranslateTransform(center.X,center.Y); //通过左乘指定的平移来更改系统的坐标原点 g.RotateTransform(minute*6+270-6); g.DrawLine( new Pen(Color.Black,1.5f),0,0,r*0.6f,0f); g.ResetTransform(); //画秒针 g.TranslateTransform(center.X,center.Y); g.RotateTransform(second * 6 + 270 - 6); g.DrawLine( new Pen(Color.Black,0.5f),0,0,r*0.7f,0f); //绘出秒针 base .OnPaint(e); } 最后写下线程执行函数,实现页面的不断重绘: private void DrawTime() { while ( true ) { Invalidate(); //重绘整个画面 Thread.Sleep(950); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构