最近发现日常的工作中,经常因为敲代码而忘记了休息,晚上眼睛特别的累。
并且经常长时间看着显示器,对眼睛一定是不好的,所以今天开发了一个小程序,用于提醒休息。
下面先看看运行效果:
1、程序启动后,后台运行,不显示界面,也没有制作显示托盘图标
2、当时间到达后,屏幕居中显示以下界面,并且开始倒计时
3、倒计时为0时,屏幕熄灭,但其实随便碰一下鼠标或键盘就会点亮显示器了。
4、人手点亮显示器后,显示以下界面,也可以不亮屏的状态下直接输入密码。
5、输入密码并且正确,界面隐藏至后台,并且重新计时。
上代码:
首先,要有一个控制显示器的帮助类,MonitorHelper
1 using System; 2 using System.Runtime.InteropServices; 3
4 namespace MonitorTool 5 { 6 /// <summary>
7 /// 显示器开关控制 8 /// </summary>
9 public class MonitorHelper 10 { 11 [DllImport("user32.dll")] 12 public static extern IntPtr SendMessage( 13 IntPtr hWnd, 14 uint msg, 15 uint wParam, 16 int lParam); 17
18 //系统消息
19 private const uint WM_SYSCOMMAND = 0x112; 20
21 //关闭显示器的系统命令
22 private const int SC_MONITORPOWER = 0xF170; 23
24 //2为PowerOff, 1为省电状态,-1为开机
25 private const int MonitorPowerOff = 2; 26
27 /// <summary>
28 /// 关闭显示器 29 /// </summary>
30 public static void PowerOff(IntPtr hWnd) 31 { 32 SendMessage( 33 hWnd, 34 WM_SYSCOMMAND, 35 SC_MONITORPOWER, 36 2
37 ); 38 } 39
40 /// <summary>
41 /// 打开显示器 42 /// </summary>
43 public static void PowerOn(IntPtr hWnd) 44 { 45 SendMessage( 46 hWnd, 47 WM_SYSCOMMAND, 48 SC_MONITORPOWER, 49 -1
50 ); 51 } 52 } 53 }
程序界面:
只有2个控件,分别是Label控件,ID是"lblTips",TextBox控件,ID是"txtPwd"
窗体的TopMost设置为True,StartPosition设置为CenterScreen
窗体的后台代码:
1 using System; 2 using System.Threading; 3 using System.Windows.Forms; 4
5 namespace MonitorTool 6 { 7 public partial class FrmMain : Form 8 { 9 //工作总时间
10 public int WorkTime { get; set; } 11 //显示器关闭前的倒计时时间
12 public int TipsTime { get; set; } 13
14 public string Password { get; set; } 15 //线程变量
16 public Thread tTotal { get; set; } 17
18 public FrmMain() 19 { 20 InitializeComponent(); 21 //初始化变量值,也是方便以后修改
22 this.WorkTime = 50 * 60 * 1000; //ms(分钟*60秒*1000毫秒)
23 this.TipsTime = 5; //s(倒计时的总秒数)
24 this.Password = "cong"; //重新计时的密码
25 } 26
27 private void FrmMain_Load(object sender, EventArgs e) 28 { 29 TimerTotal(); 30
31 //隐藏窗口
32 this.ShowInTaskbar = false; 33 this.Hide(); 34 } 35
36 //开始计时,至屏幕熄灭的方法
37 public void TimerTotal() 38 { 39 //打开新的线程
40 tTotal = new Thread(() =>
41 { 42 //挂起线程,直到到达工作总时间
43 Thread.Sleep(this.WorkTime); 44
45 //声明系统的委托
46 Action<string> actionDelegate = null; 47
48 //第一次使用委托,显示窗口
49 actionDelegate = (x) =>
50 { 51 lblTips.Text = ""; 52 this.Show(); 53 }; 54 this.Invoke(actionDelegate, "show"); 55
56 //第二次使用委托,for循环,显示倒计时提示信息,每个循环挂起线程1秒
57 for (int i = this.TipsTime; i >= 0; i--) 58 { 59 actionDelegate = (x) =>
60 { 61 lblTips.Text = string.Format("Monitor will turn off after {0} secords ...", x); 62 }; 63 this.lblTips.Invoke(actionDelegate, i.ToString()); 64 Thread.Sleep(1000); 65 } 66
67 //第三次使用委托,显示器熄灭,挂起线程3秒,用于缓冲,并且使密码框获得焦点,以便快速输入密码
68 actionDelegate = (x) =>
69 { 70 MonitorHelper.PowerOff(this.Handle); 71 Thread.Sleep(3000); 72 lblTips.Text = "please type your password."; 73 txtPwd.Focus(); 74 }; 75 this.Invoke(actionDelegate, "hide"); 76 }); 77
78 //运行线程前,必须定义为后台运行,并开启线程
79 tTotal.IsBackground = true; 80 tTotal.Start(); 81 } 82
83 //密码框,如果密码正确,则再次开启线程,重新计时
84 private void txtPwd_TextChanged(object sender, EventArgs e) 85 { 86 if (txtPwd.Text.Trim().Equals(this.Password)) 87 { 88 txtPwd.Text = ""; 89
90 TimerTotal(); 91 this.Hide(); 92 } 93 } 94 } 95 }
这样就可以完成了。
其实也可以使用Timer控件来制作,但是因为不大熟练线程的使用,所以特意使用线程。
当然,这只用到了线程中很少一部分的知识,代码比使用Timer的简洁了许多。
最后,把程序添加到系统的启动文件夹内,以后开机就能自动运行了。
当看到倒计时的时候,应该要停下工作,起来活动活动了。