模拟数字时钟屏幕保护程序和应用程序





4.00/5 (1投票)
组合式模拟数字时钟屏保和应用,设置包括颜色和更新间隔。
引言
将您的电脑用作组合式模拟数字时钟。
有些人会一直开着电脑。有些人认为这可以延长电脑的功能寿命。如果您是这些人,不妨试试这款软件。
背景
本文介绍的是一款 C# 编写的模拟数字时钟屏保。它也非常轻量级,压缩后的 exe 文件为 11kb,压缩后的源代码为 33kb。这个 Windows 模拟时钟应用支持命令行参数,这是屏保程序所必需的。
所需的单独参数是 /s、 /c 和 /p,分别用于显示、配置和预览。
/s (显示) 参数会显示如上图所示的屏保。在此模式下,应用程序将在按键事件或鼠标移动时退出。还有一个非标准行为,在不移动鼠标的情况下双击,会显示配置窗体。请参见下文。
/c (配置) 参数会显示如上图所示的屏保设置。在 TextBox 点击事件中,会显示 ColorDialog 窗体。这允许用户选择他们喜欢的配色方案。还可以调整更新间隔。可用的间隔是 100、200、250、350、500、1000、5000 和 10000 毫秒。100 毫秒可以实现类似劳力士的秒针移动效果。选择较大的间隔可以减少 CPU 使用。将秒针的颜色设置为与表盘颜色相同,您几乎注意不到秒针的存在。
/p (预览) 参数会显示一个小的屏保版本,该版本在控制面板中显示(未显示)。
此应用程序还支持 /a (应用) 命令行参数,以正常的应用程序模式显示时钟,该模式可调整大小,并带有右上角的标准控制按钮(如上图所示)。还会显示本地时区信息。
通过在快捷方式中嵌入命令行参数,该应用程序可以以屏保模式或应用程序模式运行。
屏保使用方法
要用作屏保,请将 AnaClock.exe 的后缀从 .exe 改为 .scr,然后将其放入
\WINDOWS\system32 目录
或
\WINDOWS\sysWOW64 目录(适用于 Windows 7 64 位操作系统)
您可能需要以管理员身份运行才能执行此操作。
之后,AnaClock 屏保将出现在控制面板的屏保列表中。
选择后,应出现小预览,并且“设置”和“全屏预览”按钮将启用。
解决方案
Visual Studio 2008 项目包含两个窗体 *FormMain.cs* 和 *FormScreenSaverSettings.cs*,其他类有 `ColorUtils`、`RegistryWrapper` 和 `TextBoxColorSaver`。大部分核心功能都 resides 在窗体本身。`TextBoxColorSaver` 继承自 `RegistryWrapper`,并被两个窗体使用。`TextBoxColorSaver` 包含 `ColorUtils` 的实例。
根据命令行参数,Program.cs 将创建 `FormMain` 或 `FormScreenSaverSettings` 的实例。FormMain 的行为由使用的构造函数决定,对应于命令行参数 /s、/p 或 /a。
屏保模式与应用程序模式的核心区别
以下是 Visual Studio 生成的 `InitializeComponent()` 的代码片段,该代码在所有 `FormMain` 构造函数中使用。由于这是一个屏保,我们不希望有边框,不出现在任务栏,并且需要保持在最顶层。
private void InitializeComponent()
{
.
.
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.ShowInTaskbar = false;
this.TopMost = true;
.
.
}
以下是屏保的完整构造函数。我们希望设置基于屏幕尺寸的边界并隐藏光标。
public FormMain(Rectangle Bounds)
{
InitializeComponent();
this.Bounds = Bounds;
//hide the cursor
Cursor.Hide();
}
以下是应用程序模式的完整构造函数。我们设置了一些标志,以便程序不会因鼠标移动或按键而退出。最重要的是,我们将 `FormBorderStyle` 设置为 `Sizable`(可调整大小)。
/// default constructor used in application mode (/a)
public FormMain()
{
bRunAsApp = true;
IsPreviewMode = bRunAsApp;
InitializeComponent();
this.ShowInTaskbar = true;
this.Text = "MainForm as Application";
this.TopMost = false;
this.FormBorderStyle = FormBorderStyle.Sizable;
}
FormScreenSaverSettings
在 `FormScreenSaverSettings` 中的六个颜色相关的文本框都高效地使用了相同的 `OnColorTextBoxClick` 方法。在此事件处理程序中,我们将参数 sender(类型为 object)强制转换为子类 TextBox。对于这个窗体,我们知道每个 TextBox 都有一个唯一的名称。我们可以利用这一点来实现代码重用。
private void OnColorTextBoxClick(object sender, EventArgs e)
{
TextBox tb = sender as TextBox;
mTextBoxColorSaver.ChooseColor(ref tb, ref colorDialog);
}
注意,语法
TextBox tb = (TextBox)sender;
也会奏效。
类 `TextBoxColorSaver` 具有 `ChooseColor` 方法,该方法使用 Windows `ColorDialog` 允许用户选择颜色。确认后,将颜色的名称保存在注册表中,并设置文本框的 `BackColor`。此外,文本框的前景文字颜色设置为黑色或白色,以与 `BackColor` 形成对比。
/// pop up color picker and store results in Registry
/// and load into text box.
public void ChooseColor(ref TextBox tb, ref ColorDialog colorDialog)
{
DialogResult dr = colorDialog.ShowDialog();
if (dr == DialogResult.OK)
{
Color aColor = colorDialog.Color;
tb.Text = cu.GetColorName(aColor);
PutString(tb.Name, tb.Text);
tb.BackColor = aColor;
tb.ForeColor = cu.GetContrastTextColor(aColor);
}
else
{ // On Cancel Load default
tb.Text = cu.GetColorName(tb.BackColor);
PutString(tb.Name, tb.Text);
}
}
上述方法使用 `ColorUtils` 类的实例 `cu` 来调用 `GetColorName` 和 `GetContrastTextColor` 方法。该类完整展示如下。
using System;
using System.Drawing;
namespace Hugetiger
{
/// Color utilities
public class ColorUtils
{
/// Convert a String ColorName to an actual Color.
/// Prefer known colors, use DefaultColor if needed.
public Color StringToColor(String psColorName, Color DefaultColor)
{
Color rv = DefaultColor;
if (psColorName != "null" && psColorName != String.Empty)
{
rv = Color.FromName(psColorName);
KnownColor kn = rv.ToKnownColor();
if (kn.ToString() == "0")
{ // in Hex
rv = Color.FromArgb(HexToInt(psColorName.Substring(0, 2)),
HexToInt(psColorName.Substring(2, 2)), HexToInt(psColorName.Substring(4, 2)));
}
}
return rv;
}
/// Convert a String ColorName to an actual Color, use default Color White
public Color StringToColor(String psCN)
{
return StringToColor(psCN, Color.White);
}
/// Use White text for dark backgrounds
/// and visa versa
public Color GetContrastTextColor(Color aColor)
{
Color rv = Color.Gray;
float brightness = aColor.GetBrightness();
if (brightness < 0.50)
{
rv = Color.White;
}
else
{
rv = Color.Black;
}
return rv;
}
/// Returns either named color or web type 6 hex numbers
/// Black 000000 White FFFFFF Red FF0000 Blue 0000FF
public String GetColorName(Color p)
{
String rv = String.Empty;
if (p.IsNamedColor)
{
rv = p.Name;
}
else
{
rv = IntToHex(p.R) + IntToHex(p.G) + IntToHex(p.B);
}
return rv;
}
/// Convert an int to a hex string
/// tested for range int 0 to 255
public String IntToHex(int p)
{
String rv = p.ToString("X");
if (rv == "0")
{
rv = "00";
}
return rv;
}
/// Convert hex string to an int
/// tested for range hex 00 to FF
public int HexToInt(String p)
{
int rv = int.Parse(p, System.Globalization.NumberStyles.HexNumber);
return rv;
}
}
}
提供灵感和部分源代码的文章
- 使用 GDI+ 和 Windows Forms 的 C# 可调整大小的模拟时钟
- 制作 C# 屏保
关注点
Analog Digital Clock 屏保和应用以我喜欢且适合单个程序员小型项目的风格编写。其他组织风格可能更适合团队编程工作或大型项目。我用来实现应用程序之间持久化(Persistence)的技术很有趣。
编写这款软件、记录它以及撰写这篇文章都很有趣。已在 Windows 7、Vista、MS Server 2003 和 XP 上进行测试。
历史
首个版本:2012 年 5 月 7 日