WPF程序员自定义控库系列(三)——冷却按钮

最近新做了一个倒计时按钮,感觉跟游戏里的技能冷却图标挺像的。

整理了一下,先上demo。

下载地址

 

主要用了控件的裁剪功能。

 

控件的XAML

其中,文本控件是用来显示倒计时用的。冷却按钮里面没有,所以隐藏掉了。

 1 <UserControl x:Class="NingTao.coolDownButton"
 2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 4   <Grid>
 5 
 6     <Image Margin="0" Name="imageBtnBack" MouseUp="imageBtnBack_MouseUp"></Image>
 7     <Image Margin="0" Name="imageBtnFront" IsHitTestVisible="False"></Image>
 8     <Label Margin="0,0,0,0" Name="labelCounter" IsHitTestVisible="False" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Foreground="Red" FontSize="26" Visibility="Hidden">0</Label>
 9 
10   </Grid>
11 </UserControl>

控件的CS文件

其中,把以前的检测无动作功能去掉,以前是有动作就从新计时。

注释掉的部分是反方向旋转的,因为跟常见的冷却方向不一致,所以更改方向。

虽然代码不是很多,可是考虑cos和sin的时候也挺费工夫的。

弧线的起点和终点不一样,弧线的圆心在哪一侧也是不一样的。

  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.Runtime.InteropServices;
 15 
 16 namespace NingTao
 17 {
 18   /// <summary>
 19   /// UserControl1.xaml 的交互逻辑
 20   /// </summary>
 21   public partial class coolDownButton : UserControl
 22   {
 23     // 按钮的背景前景图片
 24     private ImageSource imageBack = null;
 25     private ImageSource imageFront = null;
 26     // 文本属性
 27     private FontFamily textFamily;
 28     private double textSize;
 29     private Brush textColor;
 30     // 显示倒计时的计时器
 31     private System.Timers.Timer msgTimer = new System.Timers.Timer();
 32     // 计时器到期委托调用
 33     private delegate void invokeTimerTrick();
 34     // 倒计时最大值
 35     private double maxCounter = 0;
 36     // 无动作时间
 37     private double nowCounter = 0;
 38     // 点击事件 或者倒计时结束触发
 39     public event EventHandler Click = null;
 40     // 是否由点击触发(可能为页面后退事件)
 41     public bool isClickEvent = false;
 42 
 43     // 按钮背景图片
 44     public ImageSource ImageBack
 45     {
 46       get { return imageBack; }
 47       set
 48       {
 49         imageBack = value;
 50         imageBtnBack.Source = imageBack;
 51       }
 52     }
 53     // 按钮前景图片
 54     public ImageSource ImageFront
 55     {
 56       get { return imageFront; }
 57       set
 58       {
 59         imageFront = value;
 60         imageBtnFront.Source = imageFront;
 61       }
 62     }
 63     // 文本字体
 64     public FontFamily TextFamily
 65     {
 66       get { return textFamily; }
 67       set
 68       {
 69         textFamily = value;
 70         labelCounter.FontFamily = textFamily;
 71       }
 72     }
 73     // 文本字号
 74     public double TextSize
 75     {
 76       get { return textSize; }
 77       set
 78       {
 79         textSize = value;
 80         labelCounter.FontSize = textSize;
 81       }
 82     }
 83     // 文本颜色
 84     public Brush TextColor
 85     {
 86       get { return textColor; }
 87       set
 88       {
 89         textColor = value;
 90         labelCounter.Foreground = textColor;
 91       }
 92     }
 93     // 倒计时最大值
 94     public double MaxCounter
 95     {
 96       get { return maxCounter; }
 97       set
 98       {
 99         nowCounter = 0;
100         maxCounter = value;
101         // 启动计时器
102         msgTimer.Start();
103       }
104     }
105 
106     public coolDownButton()
107     {
108       InitializeComponent();
109 
110       // 初始化海报倒计时计数器
111       msgTimer.Elapsed += new System.Timers.ElapsedEventHandler(msgTimer_Elapsed);
112       msgTimer.Interval = 200;
113     }
114 
115     // 计数器到期
116     private void msgTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
117     {
118       //nowCounter = GetIdleTick() / 1000;
119       nowCounter += 0.2;
120       if (nowCounter < maxCounter + 0.2)
121       {
122         Dispatcher.Invoke(new invokeTimerTrick(reDraw));
123       }
124       else
125       {
126         isClickEvent = false;
127         Dispatcher.Invoke(new invokeTimerTrick(buttonClick));
128       }
129     }
130 
131     private void reDraw()
132     {
133       // 显示剩余时间
134       int timeLeft = Convert.ToInt32(maxCounter - nowCounter);
135       int intMinute = timeLeft / 60;
136       int intSecond = timeLeft % 60;
137       labelCounter.Content = string.Format("{0:D2}:{1:D2}",intMinute, intSecond);
138       // 裁剪剩余时间扇形区域
139       double angle = 360 - 360 * nowCounter / maxCounter;
140       if (360 == angle)
141       {
142         imageBtnFront.Clip = new EllipseGeometry(new Rect(0, 0, imageBtnFront.ActualWidth, imageBtnFront.ActualHeight));
143       }
144       else
145       {
146         //PathGeometry PathGeometry1 = new PathGeometry();
147         //PathFigure PathFigure1 = new PathFigure();
148         //PathFigure1.StartPoint = new Point(imageBtnFront.ActualWidth / 2, imageBtnFront.ActualHeight / 2);
149         //LineSegment LineSegment1 = new LineSegment();
150         //LineSegment1.Point = new Point(imageBtnFront.ActualWidth / 2, 0);
151         //PathFigure1.Segments.Add(LineSegment1);
152         //double offsetX = Math.Sin(angle * Math.PI / 180);
153         //double offsetY = Math.Cos(angle * Math.PI / 180);
154         //Point endPoint = new Point(imageBtnFront.ActualWidth * (1 + offsetX) / 2, imageBtnFront.ActualHeight * (1 - offsetY) / 2);
155         //ArcSegment ArcSegment1 = new ArcSegment(
156         //  endPoint,
157         //  new Size(imageBtnFront.ActualWidth / 2, imageBtnFront.ActualHeight / 2),
158         //  angle,
159         //  (angle > 180),
160         //  SweepDirection.Clockwise,
161         //  true);
162         //PathFigure1.Segments.Add(ArcSegment1);
163         //PathGeometry1.Figures.Add(PathFigure1);
164         //imageBtnFront.Clip = PathGeometry1;
165         // 顺时针
166         PathGeometry PathGeometry1 = new PathGeometry();
167         PathFigure PathFigure1 = new PathFigure();
168         // 起点为中心点
169         PathFigure1.StartPoint = new Point(imageBtnFront.ActualWidth / 2, imageBtnFront.ActualHeight / 2);
170         // 连接到扇形的圆弧起点
171         LineSegment LineSegment1 = new LineSegment();
172         double offsetX = Math.Sin(angle * Math.PI / 180);
173         double offsetY = Math.Cos(angle * Math.PI / 180);
174         LineSegment1.Point = new Point(imageBtnFront.ActualWidth * (1 - offsetX) / 2, imageBtnFront.ActualHeight * (1 - offsetY) / 2);
175         PathFigure1.Segments.Add(LineSegment1);
176         // 圆弧 终点在正上方
177         ArcSegment ArcSegment1 = new ArcSegment(
178           new Point(imageBtnFront.ActualWidth / 2, 0),
179           new Size(imageBtnFront.ActualWidth / 2, imageBtnFront.ActualHeight / 2),
180           angle,
181           (angle > 180),
182           SweepDirection.Clockwise,
183           true);
184         PathFigure1.Segments.Add(ArcSegment1);
185         // 对图像控件进行裁剪
186         PathGeometry1.Figures.Add(PathFigure1);
187         imageBtnFront.Clip = PathGeometry1;
188       }
189     }
190 
191     // 点击事件
192     private void imageBtnBack_MouseUp(object sender, MouseButtonEventArgs e)
193     {
194       isClickEvent = true;
195       buttonClick();
196     }
197 
198     private void buttonClick()
199     {
200       // 停止计时器
201       msgTimer.Stop();
202       // 触发点击事件
203       if (null != Click) Click(null, null);
204     }
205 
206     public void stopCount()
207     {
208       // 停止计时器
209       msgTimer.Stop();
210     }
211 
212     [DllImport("user32.dll")]
213     static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
214 
215     /// <summary>
216     /// 获取最后一次输入经过的时间
217     /// </summary>
218     /// <returns></returns>
219     private int GetIdleTick()
220     {
221       LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
222       lastInputInfo.cbSize = Marshal.SizeOf(lastInputInfo);
223       if (!GetLastInputInfo(ref lastInputInfo)) return 0;
224       return Environment.TickCount - (int)lastInputInfo.dwTime;
225     }
226 
227     [StructLayout(LayoutKind.Sequential)]
228     private struct LASTINPUTINFO
229     {
230       [MarshalAs(UnmanagedType.U4)]
231       public int cbSize;
232       [MarshalAs(UnmanagedType.U4)]
233       public uint dwTime;
234     }
235   }
236 }

 

调用:

先添加引用coolDownButton.dll。

前边是xaml里的调用部分,后边是动态加载图片和设置点击事件。

 1 // xaml
 2 // xmlns:coolDownButton="clr-namespace:NingTao;assembly=coolDownButton"
 3 //<coolDownButton:coolDownButton x:Name="cdButton" HorizontalAlignment="Right" Width="200" Margin="0,12,12,50"></coolDownButton:coolDownButton>
 4 
 5       // ================ 冷却按钮 ================
 6       cdButton.ImageBack = new BitmapImage(new Uri(System.Environment.CurrentDirectory + "\\skins\\a1.png"));
 7       cdButton.ImageFront = new BitmapImage(new Uri(System.Environment.CurrentDirectory + "\\skins\\a2.png"));
 8       cdButton.Click += new EventHandler(cdButton_Click);
 9 
10     void cdButton_Click(object sender, EventArgs e)
11     {
12       // 按钮被点击
13       if (cdButton.isClickEvent)
14       {
15         cdButton.MaxCounter = Convert.ToDouble(textBox1.Text);
16       }
17       else
18       {
19         MessageBox.Show("冷却完成");
20       }
21     }

 

 

转载于:https://www.cnblogs.com/slowhand/archive/2013/05/23/3095297.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值