GDI+模拟电子时钟全解析

模拟时钟

要求如下:
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;
//ystemInformation.FrameBorderSize.Width获取正在拖动调整大小窗口周围绘制的大小调整边框的粗细水平分量 y = -e.Y - SystemInformation.FrameBorderSize.Height - SystemInformation.CaptionHeight;
//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); } }

  

原文地址:https://www.cnblogs.com/Olive116/p/2695626.html