说明:模拟带表盘的时钟
1 using System; 2 using System.Windows.Forms; 3 using System.Drawing; 4 using System.Drawing.Drawing2D; 5 using System.Globalization; 6 7 8 namespace BugQiang.Clocks { 9 public class Clock : UserControl { 10 11 Timer _timer; 12 13 Graphics _grahpics; 14 15 /// <summary> 16 /// 坐标原点X 17 /// </summary> 18 float _centerX; 19 20 /// <summary> 21 /// 坐标原点Y 22 /// </summary> 23 float _centerY; 24 25 /// <summary> 26 /// 外圆的外接矩阵 27 /// </summary> 28 Rectangle _outerEllipse; 29 30 /// <summary> 31 /// 内圆的外接矩阵 32 /// </summary> 33 Rectangle _innerEllipse; 34 35 /// <summary> 36 /// 内圆半径 37 /// </summary> 38 float _innerEllipseRadius; 39 40 //时分秒针的长度 41 float _hourLength; 42 float _minuteLength; 43 float _secondLength; 44 45 //外圆以及内圆与控件边界的距离 46 int _outerSpan = 2; 47 int _innerSpan = 5; 48 49 /// <summary> 50 /// 刻度长度 51 /// </summary> 52 float _scaleLength; 53 54 Pen _outerEllipsePen; 55 SolidBrush _innerEllipseBrush; 56 57 Pen _bigScalePen; 58 Pen _littleScalePen; 59 60 SolidBrush _scaleValueBrush; 61 62 Pen _hourPen; 63 Pen _minutePen; 64 Pen _secondPen; 65 66 /// <summary> 67 /// Hour的角度 68 /// </summary> 69 /// <remarks>平面直角坐标系正Y轴方向为参考</remarks> 70 public float HourAngle { 71 get { 72 return (DateTime.Now.Hour 73 + DateTime.Now.Minute / 60.0F 74 + DateTime.Now.Second / 3600.0F 75 + DateTime.Now.Millisecond / 3600000.0F) * 30F; 76 } 77 } 78 79 /// <summary> 80 /// Minute的角度 81 /// </summary> 82 /// <remarks>平面直角坐标系正Y轴方向为参考</remarks> 83 public float MinuteAngle { 84 get { 85 return (DateTime.Now.Minute 86 + DateTime.Now.Second / 60.0F 87 + DateTime.Now.Millisecond / 60000.0F) * 6F; 88 } 89 } 90 91 /// <summary> 92 /// Second的角度 93 /// </summary> 94 /// <remarks>平面直角坐标系正Y轴方向为参考</remarks> 95 public float SecondAngle { 96 get { return (DateTime.Now.Second + DateTime.Now.Millisecond / 1000.0F) * 6F; } 97 } 98 99 public Clock() { 100 InitializeComponent(); 101 Initialize(); 102 Initialize2(); 103 } 104 105 protected virtual void Initialize() { 106 this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); 107 this.SetStyle(ControlStyles.DoubleBuffer, true); 108 this.SetStyle(ControlStyles.ResizeRedraw, true); 109 this.SetStyle(ControlStyles.Selectable, true); 110 this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); 111 this.SetStyle(ControlStyles.UserPaint, true); 112 _timer = new Timer(); 113 _timer.Enabled = true; //激活计时器 114 _timer.Interval = 50; //秒针每0.05秒刷新一次 115 _timer.Tick += delegate { this.Invalidate(); }; 116 this.Resize += delegate { 117 Width = Height; 118 Initialize2(); 119 }; 120 121 _outerEllipsePen = new Pen(Color.Black, 3); 122 _innerEllipseBrush = new SolidBrush(Color.Gray); 123 124 _bigScalePen = new Pen(Color.Black, 4); 125 _littleScalePen = new Pen(Color.Black, 1); 126 127 _scaleValueBrush = new SolidBrush(Color.White); 128 129 _hourPen = new Pen(Color.White, 2.5F); 130 131 _minutePen = new Pen(Color.Wheat, 1.75F); 132 133 _secondPen = new Pen(Color.WhiteSmoke, 0.75F); 134 } 135 136 private void Initialize2() { 137 _centerX = Width / 2; 138 _centerY = Height / 2; 139 140 _outerEllipse = new Rectangle(_outerSpan, _outerSpan, Width - _outerSpan * 2, Height - _outerSpan * 2); 141 _innerEllipse = new Rectangle(_innerSpan, _innerSpan, Width - _innerSpan * 2, Height - _innerSpan * 2); 142 143 _innerEllipseRadius = Width / 2 - _innerSpan; 144 145 _hourLength = _innerEllipseRadius * 0.50F; 146 _minuteLength = _innerEllipseRadius * 0.75F; 147 _secondLength = _innerEllipseRadius * 0.90F; 148 149 _scaleLength = 10; 150 151 } 152 153 protected override void OnPaint(PaintEventArgs e) { 154 base.OnPaint(e); 155 _grahpics = e.Graphics; 156 _grahpics.SmoothingMode = SmoothingMode.HighQuality; 157 158 ////绘外圆以及内圆 159 _grahpics.DrawEllipse(_outerEllipsePen, _outerEllipse); 160 _grahpics.FillEllipse(_innerEllipseBrush, _innerEllipse); 161 162 ////绘小刻度 163 ResetTransformCenter();165 _grahpics.FillEllipse(new SolidBrush(Color.White), -5, -5, 10, 10); //绘中心圆点164
for (int i = 0; i < 60; i++) { 166 _grahpics.DrawLine(_littleScalePen, _innerEllipseRadius - _scaleLength, 0, _innerEllipseRadius, 0); 167 _grahpics.RotateTransform(6); 168 } 169 170 ////绘大刻度 171 ResetTransformCenter(); 172 for (int i = 0; i < 12; i++) { 173 _grahpics.DrawLine(_bigScalePen, _innerEllipseRadius - _scaleLength, 0, _innerEllipseRadius, 0); 174 _grahpics.RotateTransform(30); 175 } 176 177 ////绘刻度值 178 float x = 0F; 179 float y = 0F; 180 ResetTransformCenter(_centerX - 10, y + _innerEllipseRadius / 5F); 181 _grahpics.DrawString("12", 182 new Font("Times New Roman", 14, GraphicsUnit.Pixel), 183 _scaleValueBrush, 184 new PointF(x, 0)); 185 for (int i = 1; i < 6; i++) { 186 x = (float)(_innerEllipseRadius * Math.Sin(Math.PI * i / 6)); 187 y = (float)(_innerEllipseRadius * (1 - Math.Cos(Math.PI * i / 6))); 188 ResetTransformCenter(_centerX, y); 189 if (i == 3) { 190 _grahpics.DrawString(i.ToString(CultureInfo.InvariantCulture), 191 new Font("Times New Roman", 14, GraphicsUnit.Pixel), 192 _scaleValueBrush, 193 new PointF(x - 25, 0)); 194 _grahpics.DrawString((12 - i).ToString(CultureInfo.InvariantCulture), 195 new Font("Times New Roman", 14, GraphicsUnit.Pixel), 196 _scaleValueBrush, 197 new PointF(-x + 15, 0)); 198 } else if (i < 3) { 199 _grahpics.DrawString(i.ToString(CultureInfo.InvariantCulture), 200 new Font("Times New Roman", 14, GraphicsUnit.Pixel), 201 _scaleValueBrush, 202 new PointF(x - 25, _innerEllipseRadius / 6F)); 203 _grahpics.DrawString((12 - i).ToString(CultureInfo.InvariantCulture), 204 new Font("Times New Roman", 14, GraphicsUnit.Pixel), 205 _scaleValueBrush, 206 new PointF(-x + _innerEllipseRadius / 8F, _innerEllipseRadius / 6F)); 207 } else if (i > 3) { 208 _grahpics.DrawString(i.ToString(CultureInfo.InvariantCulture), 209 new Font("Times New Roman", 14, GraphicsUnit.Pixel), 210 _scaleValueBrush, 211 new PointF(x - 25, -_innerEllipseRadius / 6F)); 212 _grahpics.DrawString((12 - i).ToString(CultureInfo.InvariantCulture), 213 new Font("Times New Roman", 14, GraphicsUnit.Pixel), 214 _scaleValueBrush, 215 new PointF(-x + _innerEllipseRadius / 8F, -_innerEllipseRadius / 6F)); 216 } 217 } 218 x = 0F; 219 y = _innerEllipseRadius * 2; 220 ResetTransformCenter(_centerX - 5, y - _innerEllipseRadius / 5F); 221 _grahpics.DrawString("6", 222 new Font("Times New Roman", 14, GraphicsUnit.Pixel), 223 _scaleValueBrush, 224 new PointF(x, 0)); 225 226 ////绘秒针 227 ResetTransformCenter(); 228 _grahpics.RotateTransform(-90); 229 _grahpics.RotateTransform(SecondAngle); 230 _grahpics.DrawLine(_secondPen, -20, 0, _secondLength, 0); 231 232 ////绘分针 233 ResetTransformCenter(); 234 _grahpics.RotateTransform(-90); 235 _grahpics.RotateTransform(MinuteAngle); 236 _grahpics.DrawLine(_minutePen, 0, 0, _minuteLength, 0); 237 238 ////绘时针 239 ResetTransformCenter(); 240 _grahpics.RotateTransform(-90); 241 _grahpics.RotateTransform(HourAngle); 242 _grahpics.DrawLine(_hourPen, 0, 0, _hourLength, 0); 243 } 244 245 /// <summary> 246 /// 重置坐标原点(_centerX,_centerY) 247 /// </summary> 248 private void ResetTransformCenter() { 249 ResetTransformCenter(_centerX, _centerY); 250 } 251 252 /// <summary> 253 /// 重置坐标原点(centerX,centerY) 254 /// </summary> 255 /// <param name="centerX">坐标原点X</param> 256 /// <param name="centerY">坐标原点Y</param> 257 /// <remarks>坐标(centerX,centerY)以控件的右上角为参考点</remarks> 258 private void ResetTransformCenter(float centerX, float centerY) { 259 _grahpics.ResetTransform(); 260 _grahpics.TranslateTransform(centerX, centerY); 261 } 262 263 264 /// <summary> 265 /// 必需的设计器变量。 266 /// </summary> 267 private System.ComponentModel.IContainer components = null; 268 269 /// <summary> 270 /// 清理所有正在使用的资源。 271 /// </summary> 272 /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param> 273 protected override void Dispose(bool disposing) { 274 if (disposing && (components != null)) { 275 components.Dispose(); 276 } 277 278 if (disposing && _outerEllipsePen != null) 279 _outerEllipsePen.Dispose(); 280 if (disposing && _innerEllipseBrush != null) 281 _innerEllipseBrush.Dispose(); 282 283 if (disposing && _bigScalePen != null) 284 _bigScalePen.Dispose(); 285 if (disposing && _littleScalePen != null) 286 _littleScalePen.Dispose(); 287 288 if (disposing && _scaleValueBrush != null) 289 _scaleValueBrush.Dispose(); 290 291 if (disposing && _hourPen != null) 292 _hourPen.Dispose(); 293 if (disposing && _minutePen != null) 294 _minutePen.Dispose(); 295 if (disposing && _secondPen != null) 296 _secondPen.Dispose(); 297 298 base.Dispose(disposing); 299 } 300 301 #region 组件设计器生成的代码 302 303 /// <summary> 304 /// 设计器支持所需的方法 - 不要 305 /// 使用代码编辑器修改此方法的内容。 306 /// </summary> 307 private void InitializeComponent() { 308 this.SuspendLayout(); 309 // 310 // Clock 311 // 312 this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 313 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 314 this.Name = "Clock"; 315 this.Size = new System.Drawing.Size(227, 223); 316 this.ResumeLayout(false); 317 } 318 319 #endregion 320 } 321 }
PS:.NET坐标系,以画布的左上角为原点,分别取平面直角坐标系的正X以及负Y(.NET作为正Y).