一、Visual Studio创建一个WPF项目。

简单调整一下MainWindow.xaml文件。主要使用了两个Canvas控件,分别用于显示模拟和数字时钟,命名为AnalogCanvas、digitCanvas。代码如下:

<Window x:Class="MoonClock.MainWindow"
...
Title="Moon Clock" Height="600" Width="1280" WindowStartupLocation="CenterScreen">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Canvas Grid.Column="0" Name="AnalogCanvs" Width="500" Height="500" />
<Canvas Grid.Column="1" Name="digitCanvas" Width="600" Height="300" />
</Grid>
</Window>

二、模拟时钟先来。

(1)在MainWindow.xaml.cs先定义几个字段变量

// 共用字段
DispatcherTimer timer = new DispatcherTimer(); // 计时器
DateTime CurrTime = DateTime.Now; // 当前时间 // 模拟时钟字段定义
double radius = ; // 圆半径
double angle = ; // 角度
Point Opos = new Point(); // 原点位置
Line HourLine, MinuLine, SecdLine; // 时针、分针、秒针

这几个变量足够了。

(2)在构造函数初始化变量

public MainWindow()
{
InitializeComponent(); // 原点位置
Opos = new Point(, ); // 初始化计时器
timer.Interval = TimeSpan.FromMilliseconds();
timer.Tick += Timer_Tick; // 初始化时钟针
HourLine = new Line();
MinuLine = new Line();
SecdLine = new Line();
}

(3)定义几个画表盘的方法

都是先定义图形,然后添加到AngleCanvas中显示出来

/// <summary>
/// 画表盘外圆
/// </summary>
private void DrawCircle()
{
Ellipse ellipse = new Ellipse();
ellipse.Stroke = Brushes.DarkGray;
ellipse.StrokeThickness = ;
ellipse.Width = ;
ellipse.Height = ;
ellipse.Fill = Brushes.Gray; Canvas.SetLeft(ellipse, );
Canvas.SetTop(ellipse, ); AnalogCanvs.Children.Add(ellipse); Ellipse ellipse1 = new Ellipse();
ellipse1.Stroke = Brushes.Gray;
ellipse1.StrokeThickness = ;
ellipse1.Width = ;
ellipse1.Height = ; Canvas.SetLeft(ellipse1, -);
Canvas.SetTop(ellipse1, -);
AnalogCanvs.Children.Add(ellipse1);
}
/// <summary>
/// 圆形表心圆
/// </summary>
private void DrawOCircle()
{
Ellipse ellipseO = new Ellipse();
ellipseO.Width = ;
ellipseO.Height = ;
ellipseO.Fill = Brushes.DarkGray; Canvas.SetLeft(ellipseO, Opos.X - );
Canvas.SetTop(ellipseO, Opos.Y - ); if (AnalogCanvs.Children.Contains(ellipseO))
AnalogCanvs.Children.Remove(ellipseO);
AnalogCanvs.Children.Add(ellipseO);
}
/// <summary>
/// 画圆表盘数字
/// </summary>
private void DrawDigit()
{
double x, y;
for (int i=; i<; i++)
{
angle = WrapAngle(i * 360.0 / 12.0) - 90.0;
angle = ConvertDegreesToRadians(angle); x = Opos.X + Math.Cos(angle) * (radius - ) - ;
y = Opos.Y + Math.Sin(angle) * (radius - ) - ; TextBlock digit = new TextBlock();
digit.FontSize = ;
digit.Text = i.ToString(); // 数字12位置校正
if (i == )
{
Canvas.SetLeft(digit, x - );
}
else
{
Canvas.SetLeft(digit, x);
}
Canvas.SetTop(digit, y);
AnalogCanvs.Children.Add(digit);
}
}

这里ConvertDegreesToRadians方法后面再定义,用于将角度值转换为弧度。

继续画:

/// <summary>
/// 画圆表刻度
/// </summary>
private void DrawGridLine()
{
double x1 = , y1 = ;
double x2 = , y2 = ; for (int i = ; i < ; i++)
{
double angle1 = WrapAngle(i * 360.0 / 60.0) - ;
angle1 = ConvertDegreesToRadians(angle1); if (i % == )
{
x1 = Math.Cos(angle1) * (radius - );
y1 = Math.Sin(angle1) * (radius - );
}
else
{
x1 = Math.Cos(angle1) * (radius - );
y1 = Math.Sin(angle1) * (radius - );
} x2 = Math.Cos(angle1) * (radius - );
y2 = Math.Sin(angle1) * (radius - ); Line line = new Line();
line.X1 = x1;
line.Y1 = y1;
line.X2 = x2;
line.Y2 = y2;
line.Stroke = Brushes.Black;
line.StrokeThickness = ; Canvas.SetLeft(line, Opos.X);
Canvas.SetTop(line, Opos.Y);
AnalogCanvs.Children.Add(line); }
}

以上两个画刻度和画表盘数字方法原理是一样的,就是先计算角度,再与半径计算为位置,之后将刻度或数字图形画到AngleCanvas中。

(4)是时候画时针了。

先来短黑粗的小时针

/// <summary>
/// 画时针
/// </summary>
private void DrawHourLine()
{
int hour = CurrTime.Hour;
int minu = CurrTime.Minute;
double dminu = minu / 60.0; // 根据分钟数增加时针偏移
double dhour = hour + dminu; double hour_angle = WrapAngle(dhour * (360.0 / 12.0) - 90.0);
hour_angle = ConvertDegreesToRadians(hour_angle); double x = Math.Cos(hour_angle) * (radius - );
double y = Math.Sin(hour_angle) * (radius - ); HourLine.X1 = ;
HourLine.Y1 = ;
HourLine.X2 = x;
HourLine.Y2 = y;
HourLine.Stroke = Brushes.Black;
HourLine.StrokeThickness = ; Canvas.SetLeft(HourLine, Opos.X);
Canvas.SetTop(HourLine, Opos.Y);
if(AnalogCanvs.Children.Contains(HourLine))
{
AnalogCanvs.Children.Remove(HourLine);
}
AnalogCanvs.Children.Add(HourLine);
}

其中注释句用于根据分钟数增加小时指针的偏移。如果没有增加这一偏移,会是每小时跳一次小时指针,现实中的模拟时钟是不存在这种情况的。

再来秒钟指针:

/// <summary>
/// 画秒针
/// </summary>
private void DrawSecondLine()
{
int second = CurrTime.Second; // 秒针正方向点
double se_angle = WrapAngle(second * (360.0 / 60.0) - );
se_angle = ConvertDegreesToRadians(se_angle);
double sec_x = Math.Cos(se_angle) * (radius - );
double sec_y = Math.Sin(se_angle) * (radius - ); // 秒针反方向点
se_angle = WrapAngle(second * (360.0 / 60.0) + );
se_angle = ConvertDegreesToRadians(se_angle);
double sec_x_ = Math.Cos(se_angle) * (radius - );
double sec_y_ = Math.Sin(se_angle) * (radius - ); SecdLine.X1 = sec_x_;
SecdLine.Y1 = sec_y_;
SecdLine.X2 = sec_x;
SecdLine.Y2 = sec_y;
SecdLine.Stroke = Brushes.Red;
SecdLine.StrokeThickness = ; Canvas.SetLeft(SecdLine, Opos.X);
Canvas.SetTop(SecdLine, Opos.Y);
if (AnalogCanvs.Children.Contains(SecdLine))
{
AnalogCanvs.Children.Remove(SecdLine);
}
AnalogCanvs.Children.Add(SecdLine);
}

反方向点用于确定秒钟指针经过原点另一端的位置。一般秒钟在圆点两端都会伸出,只是两端长短不同而已。

分钟就留给有心人练手吧,这里就不贴了。

(5)接近最后——两个辅助方法

/// <summary>
/// 角度360度进制
/// </summary>
/// <param name="angle"></param>
/// <returns></returns>
private double WrapAngle(double angle)
{
return angle % ;
} /// <summary>
/// 将角度转为弧度
/// </summary>
/// <param name="degrees"></param>
/// <returns></returns>
private double ConvertDegreesToRadians(double degrees)
{
double radians = (Math.PI / ) * degrees; return radians;
}

(6)更新方法:方法中的几项内容是需要根据时间更新的。

/// <summary>
/// 更新小时针、分针、秒针
/// </summary>
private void Update()
{
DrawHourLine();
DrawMinuteLine();
DrawSecondLine();
DrawOCircle();
}

(7)定义计时器事件

/// <summary>
/// 计时器事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Timer_Tick(object sender, EventArgs e)
{
// 更新当前时间
CurrTime = DateTime.Now;
// 更新圆盘时针
Update();
}

看最后效果

练手WPF(一)——模拟时钟与数字时钟的制作(上)的更多相关文章

  1. 练手WPF(一)——模拟时钟与数字时钟的制作(中)

    今天接着制作数字时钟 数字时钟主要用到Path控件,主要用于定义数字笔划的形状. (1)添加一个DigitLine类 数字时钟的数字8由7笔组成,看如下定义的字段字符串数组PathDatas,每个st ...

  2. 练手WPF(一)——模拟时钟与数字时钟的制作(下)

    继续数字时钟.上一篇写好了数字笔划专用的DigitLine类.现在是时候使用它了.下面对一些主要代码进行说明. 打开MainWindow.xaml.cs文件: (1)添加字段变量 // 数字时钟字段定 ...

  3. 练手WPF(三)——扫雷小游戏的简易实现(上)

    一.创建项目1.创建WPF项目,设置初始化窗口大小(初级难度):高x宽为430x350.2.添加文件夹Images,并添加相关图片. 3.xaml中引入图片资源. <Window.Resourc ...

  4. 练手WPF(二)——2048游戏的简易实现(上)

    1.创建游戏界面编辑MainWindow.xaml,修改代码如下: <Window.Resources> <Style TargetType="Label"> ...

  5. python3 练手实例5 做一个简单电子时钟

    import time,sys,os while(1): t = time.strftime('%Y-%m-%d\n%H:%M:%S',time.localtime(time.time())) pri ...

  6. 练手WPF(三)——扫雷小游戏的简易实现(下)

    十四.响应鼠标点击事件    (1)设置对应坐标位置为相应的前景状态 /// <summary> /// 设置单元格图样 /// </summary> /// <para ...

  7. 练手WPF(四)——贪吃蛇小游戏的简易实现(下)

    八.生成新的单节蛇身我们这里先说说游戏小原理好了,游戏运行后,通过计时器事件不断生成新的单节蛇身类SnakeNode,添加到List中的0位置,原来的蛇头变成了第二节.该节新蛇头的坐标通过蛇头前进方向 ...

  8. 练手WPF(四)——贪吃蛇小游戏的简易实现(上)

    一. 游戏界面首先,按照惯例,编辑MainWindow.xaml,先将游戏界面制作好.非常简单:(1)主游戏区依然使用我们熟悉的Canvas控件,大小为640X480像素,设定每小格子为20px,所以 ...

  9. 练手WPF(三)——扫雷小游戏的简易实现(中)

    八.随机布雷 /// <summary> /// 随机布地雷 /// </summary> /// <param name="mineNum"> ...

随机推荐

  1. xcode6新建工程

    xcode6中新建空工程 (2014-10-29 13:14:44) 转载▼ 标签: it ios 分类: iOS 升级xcode6之后,直接建立Empty工程后发现,这是太坑,真的是什么都没有啊.只 ...

  2. 对cell每一行做标记

    通过数组进行标记 初始化列表的时候给一个值如 for (int i = 0; i < [self.tableData count]; i++)    {        [_allOrderBoo ...

  3. SpringData系列四 @Query注解及@Modifying注解@Query注解及@Modifying注解

    @Query注解查询适用于所查询的数据无法通过关键字查询得到结果的查询.这种查询可以摆脱像关键字查询那样的约束,将查询直接在相应的接口方法中声明,结构更为清晰,这是Spring Data的特有实现. ...

  4. F5部署SSL证书

    查找中间证书 为了保证可以兼容所有浏览器,我们必须在服务器上安装中间证书,请到 中间证书下载工具,输入您的Server.cer,然后下载中间证书,请将中间证书保存为Chain.cer. 证书文件的上传 ...

  5. shell 多行重定向方法(多重嵌套)

    这里讲的是多重嵌套.没用过 EOF的朋友请参考其他基础贴 在自动化运维中,常常需要shell脚本.在自动化创建脚本时,会遇到脚本内容里有用EOF重定向到配置文件的代码. 这样就不能用EOF来创建脚本了 ...

  6. [Python]使用生成器来简化代码

    原本只是大概知道生成器是什么,但一直不知道怎么用,或是什么情景下用,后来才发现: 在需要一边读数据一边处理任务时,如果直接为每个任务都写一个函数,那么读数据的部分就要在每个函数都重复一遍 直接将所有任 ...

  7. 201871010126 王亚涛 《面向对象程序设计(java)》 第6-7周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  8. 201871010110-李华《面向对象程序设计(java)》第十三周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  9. 01-numpy-笔记-empty

    import numpy as np >>> a = np.empty([2,3]) >>> a array([[0.00000000e+000, 4.935933 ...

  10. Linux下Maven安装(十二)

    一.前提条件 下载并安装好JDK .在终端输入命令“java -version”,如果出现类似如下信息说明JDK安装成功. 二.开始配置Maven 1. 下载maven:http://mirror.b ...