2018/12/13

[C#] WPF Analog Clock

這篇用WPF 來寫一個可以顯示時鐘的APP。
如果只是要顯示數字形式的Digital Clock很簡單,但如果是想要做指針形式的Analog Clock 的話,就要加一些數學去算圖案的旋轉角度。
程式的架構概念,設定一個計時器,每秒會去抓系統目前的時間,在把抓到的值換算成旋轉的角度。
second、minute、hour 算出來的角度,分別對應到秒針、分針跟時針的圖案。

先準備好三張指針的圖片,分別是秒針、分針跟時針。
用DispatcherTimer 設定計時器的寫法之前有寫過(參考這篇)
在計時器中利用以下函式,分別去抓目前系統的時間(秒、分、時)
  1. sec = DateTime.Now.Second;
  2. min = DateTime.Now.Minute;
  3. hr = DateTime.Now.Hour;

注意,這邊因為圖案設計的關係,在一開始必須先把旋轉的中心點設定在圖片的中間底部,
用RenderTransformOrigin 來設定,這樣轉才會正確。
  1. secondPointer.RenderTransformOrigin = new Point(0.5, 1);
  2. minutePointer.RenderTransformOrigin = new Point(0.5, 1);
  3. hourPointer.RenderTransformOrigin = new Point(0.5, 1);

接著把得到的值,分別算成對應旋轉的角度,然後去旋轉對應的圖片物件
  1. secondPointer.RenderTransform = new RotateTransform((sec / 60) * 360);
  2. minutePointer.RenderTransform = new RotateTransform((min * 360 / 60) + ((sec / 60) * 6));
  3. hourPointer.RenderTransform = new RotateTransform((hr * 360 / 12) + (min / 2));

附上完整的程式碼參考
MainWindow.cs:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Data;
  8. using System.Windows.Documents;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using System.Windows.Navigation;
  13. using System.Windows.Shapes;
  14. using System.Windows.Threading;
  15.  
  16. namespace ClockApp
  17. {
  18. public partial class MainWindow : Window
  19. {
  20. double sec, min, hr;
  21. DispatcherTimer clock = new DispatcherTimer();
  22.  
  23. public MainWindow()
  24. {
  25. InitializeComponent();
  26.  
  27. // set RenderTransformOrigin
  28. secondPointer.RenderTransformOrigin = new Point(0.5, 1);
  29. minutePointer.RenderTransformOrigin = new Point(0.5, 1);
  30. hourPointer.RenderTransformOrigin = new Point(0.5, 1);
  31.  
  32. // set timer
  33. clock.Interval = TimeSpan.FromSeconds(1);
  34. clock.Tick += clock_Tick;
  35. clock.Start();
  36.  
  37. setCurrentTime();
  38. }
  39.  
  40. void clock_Tick(object sender, EventArgs e)
  41. {
  42. setCurrentTime();
  43. }
  44.  
  45. private void setCurrentTime()
  46. {
  47. // get current time
  48. sec = DateTime.Now.Second;
  49. min = DateTime.Now.Minute;
  50. hr = DateTime.Now.Hour;
  51.  
  52. // rotate pointer image
  53. secondPointer.RenderTransform = new RotateTransform((sec / 60) * 360);
  54. minutePointer.RenderTransform = new RotateTransform((min * 360 / 60) + ((sec / 60) * 6));
  55. hourPointer.RenderTransform = new RotateTransform((hr * 360 / 12) + (min / 2));
  56. }
  57. }
  58. }
  59.  

MainWindow.xaml:
  1. <Window x:Name="mMainWindow" x:Class="ClockApp.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:ClockApp"
  7. mc:Ignorable="d"
  8. Title="MainWindow" Height="768" Width="1024" Left="0" Top="0" WindowStyle="None" Topmost="True" AllowsTransparency="True">
  9. <Grid>
  10. <Image x:Name="clockface" Source="images/bg_1280x720-01.png" Height="768" Width="1024"/>
  11. <Image x:Name="hourPointer" Source="images/pointer_hr.png" Height="200" Width="41" Stretch="Fill" Margin="0,-200,0,0"/>
  12. <Image x:Name="minutePointer" Source="images/pointer_min.png" Height="200" Width="16" Stretch="Fill" Margin="0,-200,0,0"/>
  13. <Image x:Name="secondPointer" Source="images/pointer_sec.png" Height="200" Width="7" Stretch="Fill" Margin="0,-200,0,0"/>
  14. </Grid>
  15. </Window>
  16.  

END

沒有留言:

張貼留言