最近发现日常的工作中,经常因为敲代码而忘记了休息,晚上眼睛特别的累。
并且经常长时间看着显示器,对眼睛一定是不好的,所以今天开发了一个小程序,用于提醒休息。
下面先看看运行效果:
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的简洁了许多。
最后,把程序添加到系统的启动文件夹内,以后开机就能自动运行了。
当看到倒计时的时候,应该要停下工作,起来活动活动了。