C#绘制时钟的方法

本文实例为大家分享了使用C#写一个时钟,供大家参考,具体内容如下

时钟是这样的

一共使用四个控件即可:

WinFrom窗体应用程序代码:

using SpeechLib;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MyClockTest
{
    public partial class Form1 : Form
    {
        //创建对象myclock
        MyClock myclock = new MyClock();

        //定义date1,共电子表使用 -- 获取到当下时间点
        DateTime date1 = DateTime.Now; //Now 为静态只读属性(属性可计算)

        //定义中心点center和半径radius -- 时钟的圆心和半径大小
        Point center = new Point(160, 200); // 圆心点的坐标
        int radius = 150; // 半径 150
        //定义判定是否击中表盘的bool变量 -- 鼠标点击拖拽功能
        bool down = false;
        //记录鼠标点击的点
        Point pre;

        //程序入口
        public Form1()
        {
            InitializeComponent();
        }

        //开始画时钟
        private void OnPaint(object sender, PaintEventArgs e)
        {
            //这里不使用Graphics,而选择使用BufferedGraphics:
            //Graphics和BufferedGraphics对比:
            //5000次下时Graphics效率高一些;5000次以后BufferedGraphics效率高一些
            //Bitmap bmp = new Bitmap(width ,height );
            //Graphics g2 = Graphics.FromImage(bmp );
            //myclock.Draw(g2);
            //g2.CreateGraphics();
            //g2.DrawImage(bmp,0,0);
            //bmt.dispose();

            //Image iamge = new Bitmap(this.Width ,this .Height );
            //Graphics g1 = Graphics.FromImage(iamge);
            //g1.Clear(Form .DefaultBackColor );

            //C#双缓冲解释:
            //简单说就是当我们在进行画图操作时,系统并不是直接把内容呈现到屏幕上,而是先在内存中保存,然后一次性把结果输出来。
            //如果没用双缓冲的话,你会发现在画图过程中屏幕会闪的很厉害,因为后台一直在刷新,
            //而如果等用户画完之后再输出就不会出现这种情况,具体的做法,其实也就是先创建一个位图对象,然后把内容保存在里面,最后把图呈现出来。

            //解决空间重绘时闪烁的问题,并在改变大小时重绘图形
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);
            //矩形绘图区域
            Rectangle rect = e.ClipRectangle;

            //关于BufferedGraphicsContext类:
            //    手工设置双缓冲.netframework提供了一个类BufferedGraphicsContext负责单独分配和管理图形缓冲区。
            //    每个应用程序域都有自己的默认 BufferedGraphicsContext 实例来管理此应用程序的所有默认双缓冲。
            //    大多数情况下,每个应用程序只有一个应用程序域,所以每个应用程序通常只有一个默认 BufferedGraphicsContext。

            //关于此处的绘图:
            //通过管理BufferedGraphicsContext实现双缓冲的步骤如下:

            //(1)获得对 BufferedGraphicsContext 类的实例的引用。

            //(2)通过调用 BufferedGraphicsContext.Allocate 方法创建 BufferedGraphics 类的实例。

            //(3)通过设置 BufferedGraphics.Graphics 属性将图形绘制到图形缓冲区。

            //(4)当完成所有图形缓冲区中的绘制操作时,可调用 BufferedGraphics.Render 方法将缓冲区的内容呈现到与该缓冲区关联的绘图图面或者指定的绘图图面。

            //(5)完成呈现图形之后,对 BufferedGraphics 实例调用释放系统资源的 Dispose 方法。

            BufferedGraphicsContext current = BufferedGraphicsManager.Current; //(1)
            BufferedGraphics bg;
            bg = current.Allocate(e.Graphics, e.ClipRectangle); //(2)
            Graphics g = bg.Graphics; //(3)
            //定义画布 
            //Graphics g = CreateGraphics();
            //消除锯齿
            //g.SmoothingMode = SmoothingMode.AntiAlias;
            g.SmoothingMode = SmoothingMode.HighQuality; //高质量
            g.PixelOffsetMode = PixelOffsetMode.HighQuality; //高像素偏移质量
            //每次绘画后的背景色填充 && 定义画电子钟的字体
            g.Clear(this.BackColor);
            Font font = new Font("Times New Roman", 20);
            //在每次绘画时,更新时间,半径及中心点
            myclock.Date = DateTime.Now;
            myclock.Week = DateTime.Now;
            myclock.P = center;
            myclock.R = radius;

            //调用myclock中的Draw函数画出钟
            myclock.Draw(g);
            //直接调用DrawString函数,显示电子表,并且设置显示格式
            g.DrawString(date1.ToString(), font, Brushes.Black, 10, 10);//10,10表示字的左上角在哪
            bg.Render(e.Graphics); //(4)---> 开启绘制
            bg.Dispose(); //(5)---> 绘制完成,释放资源

            //如果为整点,则报时
            if (Convert.ToString(DateTime.Now.Minute) == "0" && Convert.ToString(DateTime.Now.Second ) == "0")
            {
                SpVoice voice = new SpVoice();
                voice.Speak("现在时间为" + Convert.ToString(DateTime.Now.Month) + "月" + Convert.ToString(DateTime.Now.Day) + "日" + Convert.ToString(DateTime.Now.Hour) + "点" + Convert.ToString(DateTime.Now.Minute) + "分", SpeechVoiceSpeakFlags.SVSFDefault);
            }
        }

        //更新时钟的时间
        private void OnTime(object sender, EventArgs e)
        {
            //使用timer控件来更新时间 ---> 1s/次

            //更新钟的时间
            myclock.Date = DateTime.Now;
            myclock.Week = DateTime.Now;
            //更新电子表的时间
            date1 = DateTime.Now;
            //刷新 --- 每走动一秒都更新画布(重绘)
            Invalidate();
            //Refresh();
        }

        //鼠标单击到时钟上的坐标
        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            //记录点击的点,并且计算是否击中时钟 -- 记录点击时的坐标
            pre = new Point(e.X, e.Y);
            down = myclock.HitTest(pre, center, radius);
        }

        //在点击后,鼠标拖动时
        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            //使用if来判断是否击中,若击中,更新中心点
            Point p = new Point(e.X, e.Y);
            //如果点击持续
            if (down)
            {
                //更新圆心坐标点
                center = new Point(center.X + p.X - pre.X, center.Y + p.Y - pre.Y);
                //pre = 当前移动的点的坐标
                pre = p;
                //重绘
                Invalidate();
                //Refresh();
            }
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            //取消击中 -- 拖拽结束
            down = false;
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            //使用 trackBar1来控制半径大小,并且更新 ---> trackBar控件改变时钟的大小
            radius = trackBar1.Value;
            Invalidate();
            //refresh
        }

        //单击:报时功能
        private void button1_Click(object sender, EventArgs e)
        {
            DateTime da = new DateTime();
            da = DateTime.Now;
            //SpVoice报时
            SpVoice voice = new SpVoice();
            voice.Speak("现在时间为" + Convert.ToString(da.Month) + "月" + Convert.ToString(da.Day) + "日" + Convert.ToString(da.Hour) + "点" + Convert.ToString(da.Minute) + "分", SpeechVoiceSpeakFlags.SVSFDefault);
        }
    }

    //初始化时钟:类应该写在外面(此处不规范)
    public class MyClock
    {
        enum time { XII, III, VI, IX } //定义结构体 -- 时钟的4顶点
        public DateTime date; //Now 为静态只读{get}属性(属性可计算),智能作为右值 -- 电子表时间
        public DateTime week; // 周
        public Point p; // 圆心点的坐标
        public int r; // 半径

        public MyClock()
        {
            //定义一个构造函数,赋予date当前时间
            date = DateTime.Now;
            week = DateTime.Now;
            p = new Point(160, 200); // 圆心点的坐标
            r = 150; // 半径
        }

        //画表盘
        public void DrawDial(Graphics g)
        {
            //定义两个pen,p1用来画小刻度及表盘,p2用来画大刻度
            Pen p1 = new Pen(Color.Black, 2);
            Pen p2 = new Pen(Color.Green, 2);
            //时钟顶点时间的字体大小
            float f = r / 10;
            //字体样式 && 字体大小
            Font font = new Font("Times New Roman", f);

            //定义两个点数组来存储刻度线的两点 --- [60] 数组中共存放了60个点的坐标
            PointF[] pointf1 = new PointF[60];
            PointF[] pointf2 = new PointF[60];
            // 
            for(int i = 0; i < 59; i++)
            {
                //通过for循环来给pointf1赋值 ---> f1点就在圆形的边上,r
                float x1 = (float)(p.X + r * Math.Sin((i + 1) * Math.PI * 2 / 60));
                float y1 = (float)(p.Y + r * Math.Cos((i + 1) * Math.PI * 2 / 60));
                pointf1[i] = new PointF(x1, y1);

                //使用if来判断,能整除5就画大刻度,不能就画小刻度
                if ((i + 1) % 5 == 0)
                {
                    float x2 = (float)(p.X + (r - r / 20) * Math.Sin((i + 1) * 2 * Math.PI / 60));
                    float y2 = (float)(p.Y + (r - r / 20) * Math.Cos((i + 1) * 2 * Math.PI / 60));
                    pointf2[i] = new PointF(x2, y2);
                    //画大刻度
                    g.DrawLine(p2, pointf1[i], pointf2[i]);
                }
                else
                {
                    float x2 = (float)(p.X + (r - r / 40) * Math.Sin((i + 1) * 2 * Math.PI / 60));
                    float y2 = (float)(p.Y + (r - r / 40) * Math.Cos((i + 1) * 2 * Math.PI / 60));
                    pointf2[i] = new PointF(x2, y2);
                    //画小刻度
                    g.DrawLine(p2, pointf1[i], pointf2[i]);
                }
            }
            //用pointf3来储存四个点的位置 表盘的4个顶点位置 ---> 横坐标 && 纵坐标调整距离到合适的位置上
            PointF[] pointf3 =
            {
            new PointF (pointf1 [30].X-f/4,pointf1 [30].Y +r/20),
            new PointF (pointf1 [15].X-r/20-2*f ,pointf1 [15].Y+f/3 ),
            new PointF (pointf1 [0].X-2*f ,pointf1 [0].Y -r/20-4*f/3),
            new PointF (pointf1 [45].X+r/20 ,pointf1 [45].Y -r/20-4*f/3),
            };

            //画出四个点相应的时间值
            for (int m = 0; m < 4; m++)
            {
                g.DrawString(((time)m).ToString(), font, Brushes.Black, pointf3[m]);
            }

            //代码重复 ---> 代码保持高内聚低耦合 ---> (time)将阿拉伯数字改成时间类型
            //g.DrawString(((time)0).ToString(), font, Brushes.Black, pointf3[0]);
            //g.DrawString(time.III.ToString(), font, Brushes.Black, pointf3[1]);
            //g.DrawString(time.VI.ToString(), font, Brushes.Black, pointf3[2]);
            //g.DrawString(time.IX.ToString(), font, Brushes.Black, pointf3[3]);

            //使用DrawEllipse画表盘 --- pen 左上角的x坐标 左上角的y坐标 宽度 高度 ---> 画圆
            g.DrawEllipse(p1, p.X - r, p.Y - r, 2 * r, 2 * r);
        }

        //画时针
        public void DrawHourPointer(Graphics g)
        {
            //定义画笔p1,设置其属性,使其带有箭头,圆点尾部
            Pen p1 = new Pen(Color.Green, 4);
            p1.EndCap = LineCap.ArrowAnchor; // 箭头
            p1.StartCap = LineCap.Round; // 尾部

            //获取分钟,转化为int型
            int i = Convert.ToInt32(date.Minute);
            //获取小时,并转换为int型,同时对12取余,获得十二小时制的小时数
            int j = (Convert.ToInt32(date.Hour)) % 12;

            //计算点值 --- (2 * Math.PI) * j / 720) 根据分钟表示时针的位置 ---> 1分钟再小时里占比1/720 ---> 60分钟*12个小时数 = 720
            //点1的坐标
            float x1 = (float)(p.X + (r - r / 3) * Math.Sin((j * 2 * Math.PI / 12) + (2 * Math.PI) * i / 720));
            float y1 = (float)(p.Y - (r - r / 3) * Math.Cos((j * 2 * Math.PI / 12) + (2 * Math.PI) * i / 720));
            //点2的坐标
            float x2 = (float)(p.X - r / 30 * Math.Sin((j * 2 * Math.PI / 12) + (2 * Math.PI) * i / 720));
            float y2 = (float)(p.Y + r / 30 * Math.Cos((j * 2 * Math.PI / 12) + (2 * Math.PI) * i / 720));
            PointF pointf1 = new PointF(x1, y1);
            PointF pointf2 = new PointF(x2, y2);

            //用DrawLine画时针
            g.DrawLine(p1, pointf2, pointf1);
        }

        //画分针
        public void DrawMinutePointer(Graphics g)
        {
            //定义画笔p1,设置其属性,使其带有箭头,圆点尾部
            //画笔宽度为3 ---> 分针比时针细一点
            Pen p1 = new Pen(Color.Blue, 3);
            p1.EndCap = LineCap.ArrowAnchor;
            p1.StartCap = LineCap.Round;

            //获取当前分钟,并转换为int型
            int i = Convert.ToInt32(date.Minute);

            //计算点值
            //点1
            float x1 = (float)(p.X + (r - r / 5) * Math.Sin(i * 2 * Math.PI / 60));
            float y1 = (float)(p.Y - (r - r / 5) * Math.Cos(i * 2 * Math.PI / 60));
            //点2
            float x2 = (float)(p.X - r / 20 * Math.Sin(i * 2 * Math.PI / 60));
            float y2 = (float)(p.Y + r / 20 * Math.Cos(i * 2 * Math.PI / 60));
            PointF pointf1 = new PointF(x1, y1);
            PointF pointf2 = new PointF(x2, y2);

            //用DrawLine画分针
            g.DrawLine(p1, pointf2, pointf1);
        }

        //画秒针
        public void DrawSecondPointer(Graphics g)
        {
            Pen p1 = new Pen(Color.Red, 2);
            p1.EndCap = LineCap.ArrowAnchor;
            p1.StartCap = LineCap.Round;

            //获取当前秒,并转换为int型
            int i = Convert.ToInt32(date.Second);

            //计算点值
            float x1 = (float)(p.X + (r - r / 20) * Math.Sin(i * 2 * Math.PI / 60));
            float y1 = (float)(p.Y - (r - r / 20) * Math.Cos(i * 2 * Math.PI / 60));
            float x2 = (float)(p.X - r / 15 * Math.Sin(i * 2 * Math.PI / 60));
            float y2 = (float)(p.Y + r / 15 * Math.Cos(i * 2 * Math.PI / 60));
            PointF pointf1 = new PointF(x1, y1);
            PointF pointf2 = new PointF(x2, y2);
            //用DrawLine画秒针 ---> 根据两点之间画线
            g.DrawLine(p1, pointf2, pointf1);
        }

        //周和日期显示 --->  表盘上
        public void DrawWeeks(Graphics g)
        {
            //字体大小
            float f = r / 15;
            Font font = new Font("Times New Roman", f);
            //放置位置
            float f1 = (float)(p.X + r * Math.Sin(Math.PI) / 2);
            float f2 = (float)(p.Y - r * Math.Cos(Math.PI) / 2);
            //DrawString ---> 画字符串
            g.DrawString(week.DayOfWeek.ToString(), font, Brushes.Black, f1, f2);
            g.DrawString(week.Day.ToString(), font, Brushes.Black, f1 + 80, f2);
        }

        public void Draw(Graphics g)
        {
            //定义函数Draw,画出时钟

            //画表盘
            DrawDial(g);
            //画时针
            DrawHourPointer(g);
            //画分针
            DrawMinutePointer(g);
            //画秒针
            DrawSecondPointer(g);
            //画周和日期
            DrawWeeks(g);
        }

        public bool HitTest(Point p, Point center, int r)
        {
            //HitTest函数表示鼠标是否点在时钟里面

            //通过计算鼠标点击的点到中心点的距离和半径的比较来判定是否击中时钟
            //圆心到半径的距离画圆,便是圆的全部面积
            double f1 = (double)(p.X - center.X);
            double f2 = (double)(p.Y - center.Y);

            //test即为鼠标点击的点到中心点的距离
            //根据勾股定理,求距离,直角三角形 a² + b² = c²
            double test = Math.Sqrt(f1 * f1 + f2 * f2);

            //斜边长于圆的半径,则在圆的范围之外;斜边小于圆的半径,则在圆的范围之内
            if (test <= r)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        #region 属性
        //此处设置成了只读 ---> 不可写 ---> 导致时钟的DateTime时间无法写入进来
        //public DateTime Date { get; internal set; }
        //public DateTime Week { get; internal set; }
        //public Point P { get; internal set; }
        //public int R { get; internal set; }

        public DateTime Date
        {
            set { date = value; }
        }
        public Point P
        {
            set { p = value; }
        }
        public int R
        {
            set { r = value; }
        }
        public DateTime Week
        {
            set { week = value; }
        }
        #endregion
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • c# winform时钟的实现代码

    代码如下: 复制代码 代码如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace Simpclock {     public partial class Form1 : Form     {   

  • C#实现动态数字时钟和日历

    本文实例为大家分享了C#实现动态数字时钟和日历的具体代码,供大家参考,具体内容如下 实现如下图所示的简易时钟和日历,要求显示公历日期.时间.星期.农历日期. 首先新建一个ChineseCanlendar类用于实现和农历相关的操作: [ChineseCanlendar.cs] /*  * 作者:JeronZhou  * 时间:2021-11-01  * 功能:动态数字时钟和日历  */ using System; using System.Linq; using System.Globalizat

  • C#实现漂亮的数字时钟效果

    本文实例讲述了用C#做了一个漂亮的数字时钟.分享给大家供大家参考. 程序运行后界面如下: 实现技术:主要是通过Graphics类的DrawImage方法来绘制数字时钟中所有的数字,这些数字是从网上找的一些图片文件.时钟使用DateTime中Now属性来获得不同的,时,分,秒,最后通过定时器来实现时钟的运行状态. 主要代码如下: 复制代码 代码如下: //将0~9数字图片保存在Image数组中  private Image[] image = new Bitmap[10];  public For

  • C#绘制时钟的方法

    本文实例为大家分享了使用C#写一个时钟,供大家参考,具体内容如下 时钟是这样的 一共使用四个控件即可: WinFrom窗体应用程序代码: using SpeechLib; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.L

  • js+html5实现canvas绘制网页时钟的方法

    本文实例讲述了js+html5实现canvas绘制网页时钟的方法,画的是一个可用于网页的.带摆的钟表,可以通过按钮调整其大小和位置,具体实现内容如下 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Clock</title> <script type="tex

  • JavaScript html5 canvas绘制时钟效果

    本文实例讲述了JavaScript+html5 canvas绘制时钟效果.分享给大家供大家参考,具体如下: HTML部分: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0

  • JavaScript html5 canvas绘制时钟效果(二)

    对于H5来说,canvas可以说是它最有特色的一个地方了,有了它之后我们可以随意的在网页上画各种各样的图形,做一些小游戏啊什么的.canvas这个标签的用法,在网上也有特别多的教程了,这里就不作介绍了.今天我们就用canvas来做一个小小的时钟.完整的代码在这里https://github.com/wwervin72/HTML5-Clock. 那么首先在这个页面里面我使用了两个canvas,一个用来绘制静态的时钟表盘和刻度,另一个用来绘制时钟的三个指针,然后用定位让他们重合到一起.然后这里没什么

  • python利用matplotlib库绘制饼图的方法示例

    介绍 matplotlib 是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图.而且也可以方便地将它作为绘图控件,嵌入GUI应用程序中. 它的文档相当完备,并且 Gallery页面 中有上百幅缩略图,打开之后都有源程序.因此如果你需要绘制某种类型的图,只需要在这个页面中浏览/复制/粘贴一下,基本上都能搞定. matplotlib的安装方法可以点击这里 这篇文章给大家主要介绍了python用matplotlib绘制饼图的方法,话不多说,下面来看代码

  • asp.net实现C#绘制太极图的方法

    本文实例讲述了asp.net实现C#绘制太极图的方法.分享给大家供大家参考.具体如下: 成品图如下所示: html页面: 注意设置: 复制代码 代码如下: ContentType="Image/Jpeg" 复制代码 代码如下: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="TaiJiTu.aspx.cs" Inherits="TaiJiTu&qu

  • javascript+html5实现绘制圆环的方法

    本文实例讲述了javascript+html5实现绘制圆环的方法.分享给大家供大家参考.具体如下: <!DOCTYPE html> <html> <head> <title> </title> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> </head> <body> <fiel

  • js+html5通过canvas指定开始和结束点绘制线条的方法

    本文实例讲述了js+html5通过canvas指定开始和结束点绘制线条的方法.分享给大家供大家参考.具体实现方法如下: <!DOCTYPE html> <html> <body> <canvas id="myCanvas" width="200" height="100" style="border:1px solid #c3c3c3;"> Your browser does n

  • php绘制圆形的方法

    本文实例讲述了php绘制圆形的方法.分享给大家供大家参考.具体实现方法如下: php绘图的基本步骤,有四步(php.ini里的 extension = php_gb2.dll 组件首先需要启用) 1.创建画布: 2.画出所需要的图像(圆.直线.矩形.扇形.弧线.......): 3.输出到网页,或者另存: 4.销毁图片(目的是释放图像所占用的内存). 网站开发最常用的三种图像格式:gif.jpg/jpeg.png (1)gif格式:压缩率最高,但只能显示256色,可能造成色彩的丢失.优势:可能显

  • php使用Jpgraph绘制柱形图的方法

    本文实例讲述了php使用Jpgraph绘制柱形图的方法.分享给大家供大家参考.具体实现方法如下: <?php include ("src/jpgraph.php"); include ("src/jpgraph_bar.php"); $data = array(19,23,34,38,45,67,71,78,85,87,90,96); //定义数组 $graph = new Graph(400,300); //创建新的Graph对象 $graph->Se

随机推荐