Follow me on GitHub Follow me on Twitter

WPF 制作简单的个人时间记录工具

软件需求:  
  为什么要做这么个工具呢?在博主的《工作学习周总结#2》中有说到。
  市面上有很多个人效率工具,但是都不适合博主目前的需要,博主现在需要的是可以1.快速记录每小时做了什么,2.生成EXCEL表用于分析。的软件,其它什么界面是否美观,功能是否像瑞士军刀一样,统统无所谓。所以打断了WPF的学习链,基于昨天《WPF HELLO WROLD》的基础,制作这么个工具。
  将分为四个部分,1.界面设计 2.逻辑,功能实现 3.功能演示 4.思考如何进一步提升

  在开始之前,因为这个工具希望可以伴随着WPF的学习一直改进,下去,所以需要加入代码管理,在本地创建了GIT,关联好后可以看到所有文件图标都多了一把蓝色的锁,代表成功关联。

  


  

界面设计:
  第一步,搭出界面结构:
  这个工具初步设计为有24个输入框(一小时一个),1个标题栏,一个导出EXCEL的按钮。确定这种方案是可行的之后开始搭结构。
        <TextBlock></TextBlock>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <TextBox></TextBox>
        <Button></Button>
界面结构
  结构搭好之后开始设计样式。
<Window x:Class="TimeNoter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TimeNote" Height="450" Width="500">
    <Grid Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Background="White" FontSize="30"  
                   TextAlignment="Center" FontFamily="Comic Sans MS" 
                   Foreground="#FF1565B6" Name="Title">HELLO GWX</TextBlock>
        <TextBox Grid.Row="1" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="1" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="2" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="2" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="3" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="3" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="4" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="4" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="5" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="5" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="6" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="6" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="7" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="7" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="8" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="8" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="9" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="9" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="10" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="10" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="11" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="11" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="12" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Grid.Row="12" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <Button Grid.Row="13" Margin="0 30 0 0" Width="70" Height="30" Background="#1570a6"
                Foreground="White" FontSize="16">Confirm</Button>
    </Grid>
</Window>
XAML
  效果图:

  现在要做的就是给所有的会在程序中用到的元素加上Name
<Window x:Class="TimeNoter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TimeNote" Height="450" Width="500">
    <Grid Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Background="White" FontSize="30"  
                   TextAlignment="Center" FontFamily="Comic Sans MS" 
                   Foreground="#FF1565B6" Name="Title">HELLO GWX</TextBlock>
        <TextBox Name="InputBoxAM1" Grid.Row="1" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM2" Grid.Row="1" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM3" Grid.Row="2" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM4" Grid.Row="2" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM5" Grid.Row="3" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM6" Grid.Row="3" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM7" Grid.Row="4" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM8" Grid.Row="4" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM9" Grid.Row="5" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM10" Grid.Row="5" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM11" Grid.Row="6" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxAM12" Grid.Row="6" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM1" Grid.Row="7" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM2" Grid.Row="7" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM3" Grid.Row="8" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM4" Grid.Row="8" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM5" Grid.Row="9" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM6" Grid.Row="9" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM7" Grid.Row="10" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM8" Grid.Row="10" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM9" Grid.Row="11" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM10" Grid.Row="11" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM11" Grid.Row="12" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Left" BorderBrush="#7DCFF3"></TextBox>
        <TextBox Name="InputBoxPM12" Grid.Row="12" Background="White" Margin="10 5 10 0" Foreground="#FF817B7B"  Width="230" HorizontalAlignment="Right" BorderBrush="#7DCFF3"></TextBox>
        <Button Name="ConfirmButton" Grid.Row="13" Margin="0 30 0 0" Width="70" Height="30" Background="#1570a6"
                Foreground="White" FontSize="16">Confirm</Button>
    </Grid>
</Window>
加完Name后的XAML
  

  

逻辑部分:
逻辑部分,以下是代码,实现的功能:1.所有的输入框,都会有提示文字,该提示文字在用户点击输入框时消失,如果用户什么都没输入,焦点消失后继续存在。2.标题可以随机切换文字。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TimeNoter
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        TextBox[] businessInputBoxs;
        private readonly string Promptwords = "What I did at ";
        private readonly string[] words = {"Try your best!"};


        /// <summary>
        /// 初始化标题,输入框逻辑与按键逻辑
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
            initializeTitle();
            initializeBoxArray();
            initializeButton();
        }

        private void initializeButton()
        {
            ConfirmButton.Click += ConfirmButton_Click;
        }

        void ConfirmButton_Click(object sender, RoutedEventArgs e)
        {
            //TODO
        }

        private void initializeTitle()
        {
            var randomNumber = new Random();
            Title.Text = words[randomNumber.Next(words.Length)];
        }

        
        void InputBox_GotFocus(object sender, RoutedEventArgs e)
        {
            var index = (sender as TextBox).Name.IndexOf('x');
            var boxMarker = (sender as TextBox).Name.Substring(index + 1);
            if ((sender as TextBox).Text == (Promptwords + boxMarker))
            {
                (sender as TextBox).Text = "";
            }
        }

        void InputBox_LostFocus(object sender, RoutedEventArgs e)
        {
            var index = (sender as TextBox).Name.IndexOf('x');
            var boxMarker = (sender as TextBox).Name.Substring(index + 1);
            if ((sender as TextBox).Text == "")
            {
                (sender as TextBox).Text = Promptwords + boxMarker;
            }
        }

        private void initializeBoxArray()
        {
            businessInputBoxs = new TextBox[24];
            businessInputBoxs[0] = InputBoxAM1;
            businessInputBoxs[1] = InputBoxAM2;
            businessInputBoxs[2] = InputBoxAM3;
            businessInputBoxs[3] = InputBoxAM4;
            businessInputBoxs[4] = InputBoxAM5;
            businessInputBoxs[5] = InputBoxAM6;
            businessInputBoxs[6] = InputBoxAM7;
            businessInputBoxs[7] = InputBoxAM8;
            businessInputBoxs[8] = InputBoxAM9;
            businessInputBoxs[9] = InputBoxAM10;
            businessInputBoxs[10] = InputBoxAM11;
            businessInputBoxs[11] = InputBoxAM12;
            businessInputBoxs[12] = InputBoxPM1;
            businessInputBoxs[13] = InputBoxPM2;
            businessInputBoxs[14] = InputBoxPM3;
            businessInputBoxs[15] = InputBoxPM4;
            businessInputBoxs[16] = InputBoxPM5;
            businessInputBoxs[17] = InputBoxPM6;
            businessInputBoxs[18] = InputBoxPM7;
            businessInputBoxs[19] = InputBoxPM8;
            businessInputBoxs[20] = InputBoxPM9;
            businessInputBoxs[21] = InputBoxPM10;
            businessInputBoxs[22] = InputBoxPM11;
            businessInputBoxs[23] = InputBoxPM12;
            for (int i = 0; i < 24; i++)
            {
                businessInputBoxs[i].Text = Promptwords + businessInputBoxs[i].Name.Substring(businessInputBoxs[i].Name.IndexOf('x') + 1);
                businessInputBoxs[i].GotFocus += InputBox_GotFocus;
                businessInputBoxs[i].LostFocus += InputBox_LostFocus;
            }
        }
    }
}
逻辑部分

 

 


  

功能部分:
EXCEL使用的是NPOI库,优点是即使设备没有安装EXCEL,本工具仍然能使用。
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace TimeNoter
{
    public class ExcelUtility :IExcel
    {
        public void StoreWorkInfo(string[] workInfoArr)
        {
            var nowDate = DateTime.Now;
            IWorkbook workBook;
            FileStream fileStreamFromTemplate;
            ISheet sheet;
            var targetPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, nowDate.Year.ToString() + '-' + nowDate.Month.ToString() + ".xls");
            if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, nowDate.Year.ToString() + '-' + nowDate.Month.ToString() + ".xls")))
            {
                fileStreamFromTemplate = new FileStream(targetPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                workBook = new NPOI.HSSF.UserModel.HSSFWorkbook(fileStreamFromTemplate);
                sheet = workBook.GetSheet("TimeTable");
            }
            else
            {
                fileStreamFromTemplate = new FileStream(targetPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                workBook = new NPOI.HSSF.UserModel.HSSFWorkbook();
                sheet = workBook.CreateSheet("TimeTable");
                sheet.CreateRow(0);
                for (int i = 0; i < 12; i++)
                {
                    sheet.GetRow(0).CreateCell(i).SetCellValue("AM " + i.ToString() + '-' + (i + 1).ToString());
                    sheet.GetRow(0).CreateCell(12 + i).SetCellValue("PM " + i.ToString() + '-' + (i + 1).ToString());
                }
            }

            var day = nowDate.Day;
            sheet.CreateRow(day);
            for (int i = 0; i < 12; i++)
            {
                sheet.GetRow(day).CreateCell(i).SetCellValue(workInfoArr[i]);
                sheet.GetRow(day).CreateCell(12 + i).SetCellValue(workInfoArr[i]);
            }

            workBook.Write(fileStreamFromTemplate);
            fileStreamFromTemplate.Close();
        }
    }
}
EXCEL部分实现 
void ConfirmButton_Click(object sender, RoutedEventArgs e)
{
    var outputInfoArray = new string[24];
    if(InputBoxAM1.Text.Trim() == "" || InputBoxAM1.Text == "What I did at AM1" )
    {
        MessageBox.Show("What happend at AM1?");
        return;
    }
    for (int i = 0; i < 24; i++)
    {
        bool invalidInputFlag;
        invalidInputFlag = (businessInputBoxs[i].Text.Trim() == "" || businessInputBoxs[i].Text ==
            ("What I did at " + businessInputBoxs[i].Name.Substring(businessInputBoxs[i].Name.IndexOf('x') + 1))) 
            ? true: false;
        if (invalidInputFlag)
        {
            businessInputBoxs[i].Text = businessInputBoxs[i - 1].Text;
        }
        outputInfoArray[i] = businessInputBoxs[i].Text;
    }
    utility.StoreWorkInfo(outputInfoArray);
}
按键处理部分
初始界面:

 

为了便于我的使用,我在程序里默认这样设置:比如说AM2没有输入,那么就代表它和AM1做的是同样的事:
现在就记录下我今天都做了什么吧!每天12点提交一次就可以了,会在程序的根目录生成EXCEL,(今天周末睡的久了点)

   

以下是生成的EXCEL,由于今天是16号,所以在17行,如果每天都Confirm,这张表就会被填满,每个月会自动产生张新表。

   


可在博主的平板上运行:

   





  

如何改进:
下次关于这个工具的博客发表时,博主会:
1.进行代码重构,消除散发臭味的代码。
2.增加导出图标的功能,可以直接导入EXCEL,生成”时间分析图“
3.改善界面.
4.用户可以设置,再次打开时是初始化界面,还是上次关闭工具时保留的界面。
posted @ 2014-11-16 21:04  官文祥  阅读(532)  评论(1编辑  收藏  举报