用C#编写一个自用单词测试程序

一、需求分析

1、写需求文档

对于我们想要的结果,应该包括

        a)复习,测试等不同训练模式

        b)可以切换中英文进行训练扩展等

        c)可以判断结果,同时展示出并写入文本文件

        d)可以增加新单词,扩充词汇本单词量

        e)确定文本单词数据格式,方便读写

2、确定数据格式

首先我们得包含单词序号,中英文以及音标,考虑到中文词性的多样性,暂且定为3个中文,同时包含错误次数,方便日后分析单词薄弱环节,所以组合为 “单词序号,英文,音标,中文1,中文2,中文3,错误次数” 7项,表述十分抽象,接下来放一张图方便理解。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxODkxODQz,size_16,color_FFFFFF,t_70

3、考虑单词存放格式

题主刚开始考虑使用结构体进行存储,但发现十分复杂,索性考虑使用类以及泛型列表存储,列表内存储的是类,简单来说就是列表内的每一项都是一个类的实例。

4、大致画出主程序界面

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxODkxODQz,size_16,color_FFFFFF,t_70

二、建立项目

1、新建项目

打开visual studio,点击创建新项目(没有的读者可以去微软官网下载,选择2019社区版即可)

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxODkxODQz,size_16,color_FFFFFF,t_70

选择C#Windows窗体应用

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxODkxODQz,size_16,color_FFFFFF,t_70

自由创建名字和路径

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxODkxODQz,size_16,color_FFFFFF,t_70

2、进入界面后,根据界面分析,画出程序主体内容 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxODkxODQz,size_16,color_FFFFFF,t_70

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxODkxODQz,size_16,color_FFFFFF,t_70

序号为此单词在文本中的次序,错误次数为历史以来错误填写次数,0/0为当前单词序号/总单词数。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxODkxODQz,size_16,color_FFFFFF,t_70

3、引入读写数据库

using System.IO; //读取写入文件

四、创建一系列自定义函数

 1、初始化一系列变量

        t1为计数单词数据中的第一个的单词序号

        t2为写新单词的计数,方便直接写出新单词的序号

        t3为所有单词的总个数

        t4为左上方0/0的单词计数

        model为复习模式,测试模式等的标记

        test_model为中英文切换标记

        同时还定义了一系列y,yy,yyy为昨天,前天,大前天的路径,方便日后扩展功能

        int t1 = 0;     // 单词序号计数器
        int t2 = 1;     // 写新计数器
        int t3 = 1;     // Allwords计数器
        int t4 = 2;     // 单词计数器
        int model = 0;  // 学习模式
        int test_model = 0; // 中->英 or 英->中
        string base_path = "../../../../../";
        string nowaday_path, yesterday_path, yyesterday_path, yyyesterday_path, Allwords_path;

2、创建类以及生成泛型空列表

        public class word
        {
            public int number;
            public string English;
            public string SoundMark;
            public int numoferror;
            public string Chinese1;
            public string Chinese2;
            public string Chinese3;
        }
        List<word> words = new List<word>(); //创建了一个泛型空列表   

3、遍历函数

创建此函数的作用是方便调用,以及可以直接读取文本内的内容并添加至words列表中,由于我们的数据是用逗号分隔,则直接使用split函数可以读取各分量数据,方便添加至words列表中。形参为需要读取的文件路径。

        public void Traverse(string Path)
        {
            // 读取path文本数据保存在alllines数组里
            string[] alllines = File.ReadAllLines(Path, Encoding.Default);
            // 遍历文本
            for (int i = 0; i < alllines.Length; i++)
            {
                List<string> list = new List<string>(alllines[i].Split(','));
                word word = new word();
                word.number = i + 1;
                word.English = list[1];
                word.SoundMark = list[2];
                word.Chinese1 = list[3];
                word.Chinese2 = list[4];
                word.Chinese3 = list[5];
                word.numoferror = Convert.ToInt32(list[6]);
                words.Add(word);
            }
        }

4、只展示中英文函数

形参为传入的单词

        public void ShowChinese(word temp)
        {
            label5.Text = "<-" + Convert.ToString(temp.number) + "->";
            label10.Text = "null";
            label11.Text = "null";
            label12.Text = temp.Chinese1;
            label15.Text = temp.Chinese2;
            label16.Text = temp.Chinese3;
            label13.Text = Convert.ToString(temp.numoferror);
            label17.Text = Convert.ToString(t4) + "/" + words.Count;
        }
        public void ShowEnglish(word temp)
        {
            label5.Text = "<-" + Convert.ToString(temp.number) + "->";
            label10.Text = temp.English;
            label11.Text = temp.SoundMark;
            label12.Text = "null";
            label15.Text = "null";
            label16.Text = "null";
            label13.Text = Convert.ToString(temp.numoferror);
            label17.Text = Convert.ToString(t4) + "/" + words.Count;
        }

此函数中的labelX中的X为创建的显示区块对应label序号,例如ShowChinese中显示中文1,对应为主界面的Label12watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxODkxODQz,size_16,color_FFFFFF,t_70

5、ShowAll函数

只展示了中英文也不够啊,当你选择了答案之后肯定得呈现出答案才行,方便记忆不是吗,所以创建ShowAll,当调用此函数时,展现中英文音标等所有信息。形参为传入的单词。

        // 显示所有信息函数
        public void ShowAll(word temp)
        {
            label10.Text = temp.English;
            label11.Text = temp.SoundMark;
            label12.Text = temp.Chinese1;
            label15.Text = temp.Chinese2;
            label16.Text = temp.Chinese3;
            label13.Text = Convert.ToString(temp.numoferror);
        }

6、写文件 

形参为写入文件的路径,以及需要写入的各内容分量。

        // 写文件函数
        public void Write(string Path,int Number, string English, string SoundMark,string Chinese1,string Chinese2, string Chinese3, int numoferror)
        {
            StreamWriter sw = new StreamWriter(Path, true, Encoding.Default);//实例化StreamWriter
            sw.WriteLine(Convert.ToString(Number) + "," + English + ",/" + SoundMark + "/," + Chinese1 + "," + Chinese2 + "," + Chinese3 + "," + Convert.ToString(numoferror));
            sw.Flush();
            sw.Close();
            label14.Text = "写入成功!";
        }

7、清除函数

清除函数清除了泛型列表words中的内容以及清除ListBox中的内容

        // 清除words和list函数
        public void Clear()
        {
            words.Clear();
            listBox1.Items.Clear();
        }

8、Check函数

在写入文件时,得检查此单词是否已存在,不存在才需写入,已存在则放弃写入,形参为需检查的单词

        // 检查是否有重复单词
          public void Check_Write(string word)
        {
            foreach (word temp in words)
            {
                if (temp.English == word)
                    return;
            }
            Write(Allwords_path, ++t3, textBox2.Text, textBox4.Text, textBox3.Text, textBox5.Text, textBox6.Text, 0);
        }

9、随机数生成

形参为单词列表的总个数,中->英模式还是英->中模式,以及生成随机数个数(默认为30)

        // 生成n个不重复的随机数
        public void RandGetwords(int maxNum, int test_model, int n = 30)
        {
            int[] index = new int[maxNum];
            for (int i = 0; i < maxNum; i++)
                index[i] = i + 1;
            Random r = new Random();
            //用来保存随机生成的不重复的n个数 
            int[] result = new int[n];
            for (int j = 0; j < n; j++)
            {
                //在随机位置取出一个数,保存到结果数组
                int num = r.Next(0, maxNum);
                result[j] = index[num];
                //最后一个数复制到当前位置
                index[num] = index[maxNum - 1];
                //位置的上限减少一 
                maxNum--;  
            }
            // 读取path文本数据保存在alllines数组里
            string[] alllines = File.ReadAllLines(Allwords_path, Encoding.Default);
            // 遍历文本
            for (int i = 0; i < alllines.Length; i++)
            {
                List<string> list = new List<string>(alllines[i].Split(','));
                word word = new word();
                word.number = i + 1;
                word.English = list[1];
                word.SoundMark = list[2];
                word.Chinese1 = list[3];
                word.Chinese2 = list[4];
                word.Chinese3 = list[5];
                word.numoferror = Convert.ToInt32(list[6]);
                for (int j = 0; j < n; j++)
                    if (word.number == result[j])
                        words.Add(word);                      
            }
        }

10、裁决边界函数

对于按下一个按钮,得判断列表words中是有数还是没数,从而弹出不同的选框

        // 判断下标过小还是过大
        public void JudgeofBounds()
        {
            if (words.Count == 0)
                MessageBox.Show("请先选择模式!", "Warn");
            else
                MessageBox.Show("恭喜你,完成了本次训练!", "Complete");
        }

11、写一号单词函数

传入test_model为中英文标记,根据标记呈现第一位单词

        public void FirstWord(int test_model)
        {
            switch (test_model)
            {
                // 英->中
                case 0:
                    ShowEnglish(words[0]);
                    label17.Text = 1 + "/" + words.Count;
                    break;
                // 中->英
                case 1:
                    ShowChinese(words[0]);
                    label17.Text = 1 + "/" + words.Count;
                    break;
            }
        }

四、编辑具体按钮内容

1、窗体加载

窗体加载的任务是

        a)首先组合各路径

        b)提取出单词本中的单词个数至t3,方便之后追加新单词

        c)清空单词列表words

具体代码如下

        private void Form1_Load(object sender, EventArgs e)
        {
            // 加载各路径
            nowaday_path = base_path + "Day_List/" + DateTime.Now.ToShortDateString() + ".txt";
            yesterday_path = base_path + "Day_List/" + DateTime.Now.AddDays(-1).ToShortDateString() + ".txt";
            yyesterday_path = base_path + "Day_List/" + DateTime.Now.AddDays(-2).ToShortDateString() + ".txt";
            yyyesterday_path = base_path + "Day_List/" + DateTime.Now.AddDays(-2).ToShortDateString() + ".txt";
            Allwords_path = base_path + "Sum_List/Allwords.txt";
            // 遍历Allwords取出count
            Traverse(Allwords_path);
            t3 = words.Count;
            Clear();
        }

2、复习模式

复习模式的任务是

        a)标记model,计数清零,清除文本框以及单词列表

        b)读入昨天写入的新单词

        c)并写入第一个单词至上方Label框内

具体代码如下

        private void button7_Click(object sender, EventArgs e)
        {
            t1 = 0;
            model = 0;
            Clear();
            Traverse(yesterday_path);
            FirstWord(test_model);
        }

3、测试模式

复习模式的任务是

        a)标记model,计数清零,清除文本框以及单词列表

        b)读入单词本内的所有单词,并随机取出n个单词进行测试

        c)并写入第一个单词至上方Label框内

具体代码如下

        private void button8_Click(object sender, EventArgs e)
        {
            t1 = 0;
            model = 1;
            Clear();
            RandGetwords(t3,test_model);
            FirstWord(test_model);
        }

[注]由于在自定函数中我们已经初始过n=30,所以这里不传入n也能运行 

4、英->中

英->中模式的任务是

        a)标记test_model

        b)写出此单词的英文

        c)裁决边界

具体代码如下

        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                test_model = 0;
                ShowEnglish(words[t1]);
            }
            catch
            {
                JudgeofBounds();
            }
        }

5、英->中:×

英->中:×的任务是

        a)判断目前是否是英->中模式,若不是则弹出窗口提示

        b)展现此单词所有信息,并在ListBox中添加错词

        c)裁决边界

具体代码如下

        private void button4_Click(object sender, EventArgs e)
        {
            try
            {
                if (test_model == 1)
                    MessageBox.Show("当前是  “中->英”  模式,请先切换模式!", "Warn");
                else
                {
                    ShowAll(words[t1]);
                    this.listBox1.Items.Add(words[t1].number + ":" + words[t1].English + "," + Convert.ToString(words[t1].numoferror));
                }
            }
            catch(System.ArgumentOutOfRangeException)
            {
                JudgeofBounds();
            }
        }

6、英->中:√

英->中:√的任务是

        a)判断目前是否是英->中模式,若不是则弹出窗口提示

        b)展现此单词所有信息

        c)裁决边界

具体代码如下

        private void button5_Click_1(object sender, EventArgs e)
        {
            try
            {
                if (test_model == 1)
                    MessageBox.Show("当前是  “中->英”  模式,请先切换模式!", "Warn");
                else
                    ShowAll(words[t1]);
            }
            catch
            {
                JudgeofBounds();
            }
        }

7、中->英

中->英模式的任务是

        a)标记test_model

        b)写出此单词的中文

        c)裁决边界

具体代码如下

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                test_model = 1;
                ShowChinese(words[t1]);
            }
            catch
            {
                JudgeofBounds();
            }
        }

8、中->英:判断

中->英:判断的任务是

        a)判断目前是否是中->英模式,若不是则弹出窗口提示

        b)判断单词是否拼写正确,若不正确则在ListBox中添加错词

        c)展现所有单词信息,清空拼写单词文本框

        d)裁决边界

具体代码如下

        private void button3_Click(object sender, EventArgs e)
        {
            try
            {
                if(test_model == 0)
                    MessageBox.Show("当前是  ”英->中“  模式,请先切换模式!", "Warn");
                else
                {
                    ShowAll(words[t1]);
                    textBox1.Text = null;
                    if (textBox1.Text != words[t1].English)
                        this.listBox1.Items.Add(words[t1].number + ":" + words[t1].English + ":" + Convert.ToString(words[t1].numoferror));
                }
            }
            catch
            {
                JudgeofBounds();
            }
        }

9、Next

Next的任务是

        a)判断是否填写答案,若无则弹窗提示

        b)根据test_model中英文标记显示下一位单词的具体信息

        c)裁决边界

具体代码如下

        private void button9_Click(object sender, EventArgs e)
        {
            try
            {
                if (test_model == 0 && label12.Text != "null")
                {
                    word temp = words[++t1];
                    ShowEnglish(temp);
                    t4++;
                }
                else if (test_model == 1 && label10.Text != "null")
                {
                    word temp = words[++t1];
                    ShowChinese(temp);
                    t4++;
                }
                else
                    MessageBox.Show("请先选择你的答案!", "Warn");
            }
            catch
            {
                JudgeofBounds();
            }
        }

10、写入单词

写入单词的任务是

        a)判断是否有错词,若无则无需写入,弹窗提示

        b)根据具体模式选择相应的路径

        c)清空原先的文档,并依照错词的序号,把相应单词的错误次数自加1,重新写入文档

具体代码如下

        private void button10_Click(object sender, EventArgs e)
        {
            if (listBox1.Items.Count == 0)
                MessageBox.Show("无错词,无需更改文档!", "Warn");
            string path = null;
            label14.ForeColor = Color.Green;
            // 根据模式选择路径
            switch (model) 
            {
                case 0:
                    path = yesterday_path;
                    break;
                case 1:
                    path = Allwords_path;
                    break;
            }
            // 清空文本文档
            words.Clear();
            Traverse(path);
            FileStream fs = new FileStream(path, FileMode.Truncate, FileAccess.ReadWrite);
            fs.Close();
            // new 一个长度为 listBox1.Items.Count的数组
            int[] a = new int[listBox1.Items.Count];
            // 循环便利listBox1中的每一项,且把序号存储在数组a中
            for (int i = 0; i < listBox1.Items.Count; i++)
            {
                List<string> list1 = new List<string>(Convert.ToString(listBox1.Items[i]).Split(':'));
                a[i] = Convert.ToInt32(list1[0])-1;
                words[a[i]].numoferror++;
            }
            // 在清空的文档中追加写入文件
            for(int i = 0; i < words.Count; i++)
            {
                word temp = words[i];
                Write(path, i+1, temp.English, temp.SoundMark.Replace("/",""), temp.Chinese1, temp.Chinese2, temp.Chinese3, temp.numoferror);
            }
        }

11、写新

写新的任务是

        a)判断中英文文本框中是否有内容,若无则弹窗提示

        b)根据今天的日期创建新文档并写入单词,同时在单词本中新追加单词

        c)清空写新单词中的文本框

具体代码如下

        private void button6_Click(object sender, EventArgs e)
        {
            // 判断英文和中文框内是否有内容
            if ( textBox2.Text == "" && textBox3.Text == "")
                MessageBox.Show("请输入中文&英文!", "Warn");
            else
            {
                // 写入Day_List,nowaday
                Write(nowaday_path, t2++, textBox2.Text, textBox4.Text, textBox3.Text, textBox5.Text, textBox6.Text, 0);
                // 写入Allwords
                Check_Write(textBox2.Text);
                // 更换label4文本框颜色
                if (t2 % 2 == 0)
                    label14.ForeColor = Color.Red;
                else
                    label14.ForeColor = Color.Black;
                // 清空文本框
                textBox2.Text = null;
                textBox3.Text = null;
                textBox4.Text = null;
                textBox5.Text = null;
                textBox6.Text = null;
            }
        }

五、测试程序

至此程序大体框架搭建完成,接下来进行测试

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxODkxODQz,size_16,color_FFFFFF,t_70

测试没有问题,可以正常使用

六、附录

鉴于本人能力所限,文中难免存有疏漏之处,恳请读者谅解并指正。

接下来放出程序源码,方便看到最后的读者学习交流,同时题主给出yyesterday,yyyesterday的变量的定义,以及新建Wrong_List的文件夹,感兴趣的读者可以自由修改添加新内容,根据复习模式选择复习昨天的单词还是前天大前天的单词,或者整理错词,提取错误次数大于n的单词写入至Wrong_List文件夹等。

百度网盘,提取码:hlf9

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sumzeek丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值