65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows 的一个简单的 WPF 文本时钟小部件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (19投票s)

2013 年 1 月 1 日

CPOL

2分钟阅读

viewsIcon

44916

downloadIcon

1953

Windows 的一个简单的 WPF 文本时钟小部件

引言

这是一个基于 Windows Presentation Foundation (WPF) 的简单文本时钟小工具,时间显示为静态字符网格上的一组突出显示的字符。

背景

你们中的许多人一定见过许多文本时钟的变体。所以我认为如果我能把它做成桌面小工具的形式会很棒。由于我只是 WPF(以及 C#)的初学者,欢迎任何形式的建议。

Using the Code

负责生成基于文本的当前时间的函数如下

string TextTime = String.Empty; // for holding the text-time
static Dictionary<int, string> Mapping; // maps numbers with the corresponding text;
// e.g. 9 -> "NINE"
private string GetTextTime()
{
    TextTime = "IT IS ";
    Now = DateTime.Now;
    int sec = Now.Second;
    int min = Now.Minute;
    int hour = Now.Hour;

    if (min < 5)
        TextTime += GetStringValue(hour) + " OCLOCK";
    else if (min < 10)
        TextTime += "FIVE MINUTES PAST " + GetStringValue(hour);
    else if (min < 15)
        TextTime += "TEN MINUTES PAST " + GetStringValue(hour);
    else if (min < 20)
        TextTime += "A QUARTER PAST " + GetStringValue(hour);
    else if (min < 25)
        TextTime += "TWENTY MINUTES PAST " + GetStringValue(hour);
    else if (min < 30)
        TextTime += "TWENTY FIVE MINUTES PAST " + GetStringValue(hour);
    else if (min < 35)
        TextTime += "A HALF PAST " + GetStringValue(hour);
    else if (min < 40)
        TextTime += "TWENTY FIVE MINUTES TO " + GetStringValue(hour + 1);
    else if (min < 45)
        TextTime += "TWENTY MINUTES TO " + GetStringValue(hour + 1);
    else if (min < 50)
        TextTime += "A QUARTER TO " + GetStringValue(hour + 1);
    else if (min < 55)
        TextTime += "TEN MINUTES TO " + GetStringValue(hour + 1);
    else
        TextTime += "FIVE MINUTES TO " + GetStringValue(hour + 1);

    return TextTime;
}

private static string GetStringValue(int n)
{
    n = n % 12;
    string value = (Mapping.Where(m => m.Key == n)).ToList()[0].Value;
    return value;
} 

然后,我有一个char序列,用于生成字符网格。

static string CHAR_SEQUENCE = 
  "ITRISRAOTENTWENTYPHALFQUARTERFIVEMINUTESXTOBPASTHONETWOTHREEELEVENFOURFIVESIXSEVENQEIGHTNINE
   JTWELVETENPCOCLOCK";

下面是我用来添加包含字符的TextBlock的网格的 XAML 标记。 我分别使用几个函数将 CHAR_SEQUENCE 字符串转换为字符的二维数组,并在 XAML 网格中添加 TextBlock,每个 TextBlock 包含一个字符作为其 Text 属性。

<Grid HorizontalAlignment="Left" Margin="0,0,0,0" 
          Name="grdChars" VerticalAlignment="Top">
    <Grid.BitmapEffect>
        <DropShadowBitmapEffect></DropShadowBitmapEffect>
    </Grid.BitmapEffect>
</Grid>
private static void FillCharGrid() // for converting CHAR_SEQUENCE into a 2D array
{
    var charArr = CHAR_SEQUENCE.ToCharArray();
    int j = 0;
    for (int i = 0; i < charArr.Length; i++, j++)
    {
        char c = charArr[i];
        CharGrid[i / 11, j % 11] = c;
    }
}

private void RenderCharGrid() // Render chars in 2D as separate TextBlocks
{
    FillCharGrid();
    int topMargin = 20;
    for (int i = 0; i < CharGrid.GetLength(0); i++)
    {
        int leftMargin = 0;
        for (int j = 0; j < CharGrid.GetLength(1); j++)
        {
            TextBlock txt = new TextBlock();
            txt.Name = "lbl" + i.ToString() + j.ToString();
            txt.Text = CharGrid[i, j].ToString();
            txt.FontFamily = new System.Windows.Media.FontFamily("Tahoma");
            txt.Height = 30;
            txt.HorizontalAlignment = HorizontalAlignment.Left;
            txt.TextAlignment = TextAlignment.Center;
            txt.Margin = new Thickness(leftMargin, topMargin, 0, 0);
            txt.VerticalAlignment = VerticalAlignment.Top;
            txt.Width = 35;
            txt.Foreground = new SolidColorBrush(Colors.DarkGray);
            txt.Opacity = 2;

            leftMargin += 20;
            grdChars.Children.Add(txt);
        }
        topMargin += 20;
    }
}

以下是我用于突出显示当前文本时间(由 GetTextTime() 方法生成)中的字符的方法。

private void HighlightTextTime(string time)
{
    UIElementCollection elements = grdChars.Children;
    var timeArr = time.Split(new char[] { ' ' });
    bool toBreak = false;

    bool isFlattenedWRTFive = IsFlattenedWRTFive(time);
    bool isFlattenedWRTTen = IsFlattenedWRTTen(time);
    int currentFive = 0; int currentTen = 0;

    foreach (var str in timeArr)
    {
        var arr = str.ToCharArray();
        List<textblock> labels = new List<textblock>();
        for (int i = 0; i < grdChars.Children.Count; i++)
        {
            if (toBreak)
            {
                toBreak = false;
                break;
            }
            TextBlock txt = elements[i] as TextBlock;
            if (txt.Opacity == 2)
                continue;
            bool flag = false;
            List<textblock> Reds = new List<textblock>();
            if (txt.Text.ToUpper().Equals(str[0].ToString().ToUpper()))
            {
                for (int j = 0; j < str.Length; j++)
                {
                    TextBlock txt_succ = elements[i + j] as TextBlock;
                    if (!txt_succ.Text.ToUpper().Equals(str[j].ToString().ToUpper()))
                    {
                        flag = false;
                        Reds.Clear();
                        break;
                    }
                    else
                    {
                        flag = true;
                        Reds.Add(txt_succ);
                    }
                }
                if (flag)
                {
                    if (str.ToUpper().Equals("FIVE") && !isFlattenedWRTFive && currentFive == 0)
                    {
                        currentFive = 1;
                        continue;
                    }
                    if (str.ToUpper().Equals("TEN") && !isFlattenedWRTTen && currentTen == 0)
                    {
                        currentTen = 1;
                        continue;
                    }
                    for (int p = 0; p < Reds.Count; p++)
                    {
                        Reds[p].Foreground = new SolidColorBrush(Colors.Red);
                        Reds[p].Opacity = 2;
                    }
                    toBreak = true;
                }
            }
        }
    }
}

我稍微遇到了一些类似 IT IS FIVE MINUTES TO FIVEIT IS TEN MINUTES TO TWELVE 这样的时间的问题,因为“FIVE”和“TEN”有两个字符集。 第一个用于分钟,第二个用于小时。 因此,我编写了一个简单的方法来确定当前文本时间是否相对于字符串 FIVETEN 进行了扁平化,因为它们可以表示分钟或小时,如果是小时,我只是跳过该字符串的第一个 char 集并使用后一个。 我知道这不是处理此问题的最佳方式,但它效果很好。 这是一个检查文本时间是否相对于字符串“TEN”进行扁平化的示例方法

private bool IsFlattenedWRTTen(string time)
{
    time = time.ToUpper();
    var tenCount = CountSubStrings(time, "TEN");
    if ((tenCount == 2 || tenCount == 0))
        return true;
    if (time.Contains("MINUTES"))
        if (time.IndexOf("TEN") < time.IndexOf("MINUTES"))
            return true;
    return false;
}

现在,正如您可能指出的那样,这需要相当大的处理能力,因为它需要在每秒执行一次。 所以,我使用了一个 string CURRENT_TEXT_TIME 来存储当前的文本时间。 每秒之后,当生成新的文本时间时,它首先与此 string 进行比较,如果它们不同,则刷新突出显示的字符并突出显示新的文本时间。

这是构造函数和 timer_Tick() 事件处理程序。

public MainWindow()
{
    InitializeComponent();
    InitializeComponent();
    RenderCharGrid();
    // return;
    Mapping = new Dictionary<int,>();
    FillMapping();
    timer = new DispatcherTimer();
    timer.Interval = TimeSpan.FromSeconds(1);
    timer.Tick += new EventHandler(timer_Tick);
    timer.Start();
}

private void timer_Tick(object sender, EventArgs e)
{
    string time = GetTextTime();

    if (CURRENT_TEXT_TIME.ToUpper().Equals(time.ToUpper()))
        return;
    CURRENT_TEXT_TIME = time;
    ResetCharGrid();
    HighlightTextTime(time);
}

最后但并非最不重要的一点是,由于我们要创建一个桌面小工具风格的应用程序,我们必须设置 XAML 窗口的一些属性,一个关闭小工具的按钮,最后是一个 Window_MouseLeftButtonDown() 处理程序来启用拖动小工具。 以下是窗口的 XAML 代码、Close 按钮 Click 事件处理程序和鼠标单击处理程序。

<Window x:Class="TextClock.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TextClock by 007" Height="248" Width="253" 
	AllowsTransparency="True" 
	WindowStartupLocation="CenterScreen"
	WindowStyle="None" 
	Opacity="0.8" 
	Background="Black"
    MouseLeftButtonDown="Window_MouseLeftButtonDown" 
	ShowInTaskbar="False">

......

</window>
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    this.DragMove();
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    this.Close();
}

享受吧...!!

© . All rights reserved.