四則運算結對項目之GUI

    本次結對編程讓我學到了許多許多知識,受益不淺!在此以前,我沒想過我能作出一個雙擊運行的小程序。html

    感謝個人隊友與我同心合力,感謝室友宇欣告訴我操做符爲「最多多少」而不是「多少」並教我使用效能分析工具,感謝陳杰任勞任怨幫我測試14寸顯示屏效果,感謝福孝大佬給我發的安裝包!感謝學姐對項目的建議!java

    代碼倉庫地址:https://git.coding.net/Siamese_miao/team.gitgit

    本人:莊莉,學號:2016012034算法

    隊友:王璐瑤,學號:2016012095編程


 

計劃PSP

PSP小程序

任務內容數組

計劃共完成須要的時間(h)多線程

Planningapp

計劃dom

0.5

Estimate

   估計這個任務須要多少時間,並規劃大體工做步驟

0.5

Development

開發

39.25

   Analysis

需求分析 (包括學習新技術)

0.5

Design Spec

  生成設計文檔

0.25

  Design Review

設計複審 (和同事審覈設計文檔)

0.25

Coding Standard

 代碼規範 (爲目前的開發制定合適的規範)

0.25

 Design

 具體設計

2

Coding

具體編碼

30

Code Review

 代碼複審

1

Test

測試(自我測試,修改代碼,提交修改)

5

Reporting

報告

4

Test Report

測試報告(包括博客)

3

 Size Measurement

計算工做量

0.5

Postmortem & Process Improvement Plan

過後總結, 並提出過程改進計劃

0.5

 


 

結對編程對接口的設計

信息隱藏(Information Hiding)

    Information hiding is part of the foundation of both structured design and object-oriented design. In structured design, the notion of 「black boxes」 comes from information hiding. In object-oriented design, it gives rise to the concepts of encapsulation and modularity, and it is associated with the concept of abstraction.

    在《代碼大全》中列出了兩類須要隱藏的內容:

    第一類信息是複雜化的信息。對於咱們的項目,咱們的main函數只有一個對gui的實例化,使用者並不知道內部的運行方式。內部的算法實現封裝起來,外部只有調用的接口,只能夠調用方法,不能夠改變內部變量,作到了信息隱藏。

    對於第二類,是指變更的信息。好比在用戶的輸入需求中出現了錯誤,提示並返回,這個錯誤在類中進行了適當的處理,錯誤沒有擴散,這樣能夠提升程序的容錯性。

接口設計(Interface Design)

    在本項目設計接口過程當中,按需求新建接口,使用明確的命名方式使接口的功能清晰化,加強了可讀性;接口與接口之間互相獨立,使用方便。

鬆耦合(Loose coupling)

    耦合的強度依賴於:(1)一個模塊對另外一個模塊的調用;(2)一個模塊向另外一個模塊傳遞的數據量;(3)一個模塊施加到另外一個模塊的控制的多少;(4)模塊之間接口的複雜程度。等等。

    模塊內子程序(下一個層次上)應共享數據(有必定的耦合度),而減小全局變量能下降子程序性間的耦合性。

  類與類之間一般經過接口的契約實現服務提供者/服務請求者模式,這就是典型的鬆耦合。

    耦合程度越高,模塊與模塊之間的聯繫性就更高,系統的靈活性就越低,報錯率就更高。在咱們的項目中,計算模塊的調用都比較單一,沒有雙向調用,使用之間互不干擾,增長了靈活性。

 


 

計算模塊接口的設計與實現過程

    通過商討,咱們決定基於個人我的項目修改。我先刪除了原來的分數運算,在將普通四則運算與括號四則運算拆分,變成簡單加減、四則運算、有括號加減與有括號四則運算。如圖我分爲5個類(test爲單元測試)。

  • Command類:命令行測試類,負責接收命令行的參數並啓動程序。
  • fileCreate類:建立文件類,負責產生result.text文件,將練習題寫入文件以及作題模式的生成記錄。
  • formula類:式子類,負責根據調用產生同種類型的式子,含有AddSubtract(加減運算)、arithmetic(簡單四則運算)、Bracket(帶括號的四則運算)、Bracket_AS (帶括號的加減運算)四種函數。
  • calculate類:計算類,負責各類計算,含有有條件產生後一位數、有條件操做符等7個方法。
  • stack類:棧,負責計算式子,並判斷式子合法性。

    其中,有條件生成操做符與後一位數我較爲滿意,它大大的下降了運行效率,部分代碼可看第5模塊的性能改進模塊。

 


 

計算模塊接口部分的性能改進

    基於原來的我的項目代碼,因爲出現了運算過程以及運算結果數值範圍的限制,本來的result(String temp)再也不使用,改用了棧運算。

 1 // 計算結果  2 public static Object result(String temp) {  3 ScriptEngineManager sem = new ScriptEngineManager();  4 ScriptEngine se = sem.getEngineByName("js");  5 Object last = 0;  6 try {  7 last = se.eval(temp);  8 } catch (ScriptException e) {  9  e.printStackTrace(); 10  } 11 return last; 12 }
result函數

    在棧的運算中加入判斷

1 if (Math.abs(sresulat) > upper || Math.abs(sresulat) < lower) 2 { 3 return 0; 4 }
判斷

    而對於簡單加減無括號全程不改變優先級的運算則不過棧,直接邊生成數字便運算,減小了運算時間。

    另外,本來的操做符是一開始隨機生成好的再判斷選擇後一個數,而後再判斷符號是否合法,再修改符號,若是仍是有小數或負數,則從新運行生成算式的函數,這樣使得代碼運行有些慢且屢次運行。再加上數值範圍的限定以及能夠存在負數,我改變了想法。

    由於負數的存在,使得加減號並無數字的限制,而乘法有上限限制,除法有下限限制。因此在只有加減的運算中,符號隨機生成,後一個數根據運算符以及數值範圍生成合法的數。

 1 // 相加不超過範圍  2 public static int decide0(int x, int min, int max)  3  {  4 int y;  5 int temp = 0;  6 if (x > 0)  7  {  8 temp = max - min - x + 1;// 加一個正整數範圍  9 } else 10  { 11 temp = max - (min - x) + 1;// 加至正整數的範圍 12  } 13 if (temp < 0) 14 {// 範圍小於0 15 if (x > 0) 16  { 17 temp = Math.abs(x) - min * 2 + 1;// 正整數過大,需加負數 18 y = 0 - (int) (Math.random() * temp) - min; 19 } else 20  { 21 temp = Math.abs(x) - 2 * min + 1;// 負數太小,越值,加小整數至負數範圍 22 y = (int) (Math.random() * temp) + min; 23  } 24 } else 25  { 26 y = (int) (Math.random() * temp + min); 27  } 28 return y; 29  } 30 31 // 相減不小於最小 32 public static int decide1(int x, int min, int max) 33  { 34 int temp = 0; 35 int y = 0; 36 if (x > 0) 37  { 38 temp = x - 2 * (min - 1) - 1; // 減一個正數範圍 39 } else 40  { 41 temp = max + x - min + 1;// 減一個正數範圍 42  } 43 if (temp > 0) 44  { 45 if (x < 0 && temp < min) 46  { 47 temp = Math.abs(x) - 2 * min + 1;// 負數太小,需減負數 48 y = 0 - (int) (Math.random() * temp) - min; 49 } else 50  { 51 y = (int) (Math.random() * temp + min); 52  } 53 } else 54  { 55 temp = max - x - min + 1;// 只有x>0的狀況會出現,正數太小,需減負數 56 y = 0 - (int) (Math.random() * temp) - min; 57  } 58 return y; 59 }
加減法的後一位數選定

    當有乘除時,則根據上一個數生成操做符,再根據操做符生成合法的後一位數。

 1 // 操做符的選定  2 public static int operator(int num, int middle2, int middle3)  3  {  4 if (Math.abs(num) <= middle2)  5 {// 除法下界  6 if (Math.abs(num) < middle3)  7  {  8 return 3;  9 } else 10  { 11 return 0; 12  } 13 } else if (Math.abs(num) >= middle3) 14 {// 乘法上界 15 return 2; 16 } else 17  { 18 return (int) (Math.random() * 4); 19  } 20  } 21 // 下一位數字的選定 22 public static int[] numberB(int key, int num, int lower, int upper) 23  { 24 int[] find = new int[] { 0, lower }; 25 if (key == 0) 26  { 27 find[1] = decide0(num, lower, upper); 28 return find; 29 } else if (key == 2) 30  { 31 int[] judge = new int[2]; 32 judge = decide2(num, lower);// 確保可以整除,並不低於下限 33 if (judge[0] == 0) 34  { 35 find[1] = judge[1]; 36 return find; 37 } else 38  { 39 find[0] = 1; 40  } 41 } else if (key == 3) 42  { 43 find[1] = decide3(num, lower, upper); 44 if (find[0] == 0) 45  { 46 return find; // 乘法不超過上限 47  } 48  } 49 find[1] = decide1(num, lower, upper); 50 return find; 51 }
操做符選定以及下一位數字的選定

    這樣大大減小了從新調用函數的問題,而且實現了運算過程與數值皆在範圍內的功能。

    在附加題記錄用戶模塊,一開始使用contains(name)函數判斷用戶,後來發現這樣會出現abc與abcabc被認爲同一我的而的狀況,通過思考,咱們使用字符串的斷開。

  1 String[] arrays = txt.split(" "); 

    再使用equals(String)函數判斷用戶,解決了這個問題。

    其中,生成有括號與乘除的式子生成的函數判斷耗時最多,由於它的判斷較多,限制較多,優先級易改變,容易生成最終不合法的式子而從新運行。

 1 // 帶括號的四則運算  2 public static String Bracket(int lower, int upper, int o) {  3 int middle2 = lower * lower;// 除法下界  4 int middle3 = upper / lower;// 乘法上界  5 int brack_left = 0; // 記錄未匹配的左括號個數  6 int brack = 0; // 括號個數  7 int j = 0;  8 char[] p = new char[] { '+', '-', '÷', '*' };  9 String temp1 = ""; 10 int[] num = new int[o + 1]; // 數字 11 int[] key = new int[o]; // 符號所在的下標 12 num[0] = (int) (Math.random() * (upper - lower + 1) + lower); 13 int result; 14 int[] find = new int[2]; 15 for (j = 0; j < (o - 1); j++) { 16 if (num[j] < 0) { 17 temp1 += "(" + String.valueOf(num[j]) + ")"; 18 } else { 19 temp1 += String.valueOf(num[j]); 20  } 21 int tmpcnt = brack_left; 22 for (int i = 0; i < tmpcnt; i++) { // 若當前有未匹配的左括號,則對每個未匹配的左括號,都有必定機率生成相應右括號。 23 if ((int) (Math.random() * 5) > 1) { // 生成右括號機率爲0.6 24 brack_left--; 25 temp1 += ")"; 26  } 27  } 28 key[j] = calculate.operator(num[j], middle2, middle3); 29 find = calculate.numberB(key[j], num[j], lower, upper); 30 if (find[0] == 1) { 31 key[j] = 1; 32  } 33 num[j + 1] = find[1]; 34 temp1 += String.valueOf(p[key[j]]); 35 if (((brack * 2) <= o) && (((int) (Math.random() * 2)) == 0)) { // 以必定機率生成左括號,機率爲1/2 36 temp1 += "("; 37 brack++; 38 brack_left++; 39 j++; 40 if (num[j] < 0) { 41 temp1 += "(" + String.valueOf(num[j]) + ")"; 42 } else { 43 temp1 += String.valueOf(num[j]); 44 } // 生成左括號後必須生成一個數字和運算符,否則可能出現(15)這樣的錯誤 45 key[j] = calculate.operator(num[j], middle2, middle3); 46 find = calculate.numberB(key[j], num[j], lower, upper); 47 if (find[0] == 1) { 48 key[j] = 1; 49  } 50 num[j + 1] = find[1]; 51 temp1 += p[key[j]]; 52  } 53  } 54 while (j != o) { // 判斷是否爲最後一個數 55 if (num[j] < 0) { 56 temp1 += "(" + String.valueOf(num[j]) + ")"; 57 } else { 58 temp1 += String.valueOf(num[j]); 59  } 60 key[j] = calculate.operator(num[j], middle2, middle3); 61 temp1 += p[key[j]]; 62 find = calculate.numberB(key[j], num[j], lower, upper); 63 if (find[0] == 1) { 64 key[j] = 1; 65  } 66 j++; 67 num[j] = find[1]; 68  } 69 if (num[o] < 0) { 70 temp1 += "(" + String.valueOf(num[o]) + ")"; 71 } else { 72 temp1 += String.valueOf(num[o]); 73  } 74 while ((brack_left) != 0) { // 補全右括號 75 temp1 += ")"; 76 brack_left--; 77  } 78 result = stack.work(temp1, lower, upper, 1); 79 if (result == 0) { 80 temp1 = Bracket(lower, upper, o); 81  } 82 return temp1; 83 84  } 85 86 }
有括號四則運算

    項目整體分析圖,從內存,多線程,CPU等方面分析了計算模塊的性能,截圖以下:

     性能分析過程截圖:

     按F4,出現如下截圖。資源所有被回收。證實沒有資源泄露。程序性能良好。

      使用單元測試的CPU分析以下圖:

    使用Command.java的CPU效能分析以下圖: 

 


 

單元測試

1  @Test 2     public void testWork() { 3         assertEquals(0, stack.work("7-5÷(1*37)÷(1*83)", 1, 900, 1)); 4         assertEquals(30, stack.work("55+(-25)÷5*(20-15)", 2, 300, 1)); 5         assertEquals(80, stack.work("((55+25)÷5)*(20-15)", 2, 300, 1)); 6         assertEquals(0, stack.work("60*(20-15)", 2, 200, 1)); 7     }
棧的測試

    第一個斷言測試的是沒法整除返回錯誤標誌0;

    第二個斷言測試的是負數運算;

    第三個斷言測試的是特殊括號位置的運算;

    第四個斷言測試的是超過數值返回錯誤標誌0。

 1 @Test  2 public void testAll() {  3 // 順序不一樣以及異常測試。生成的文件會被覆蓋。  4 String[] arg0 = new String[] { "-n", "100", "-m", "5", "100", "-o", "3", "-c", "-b" };  5 String[] arg1 = new String[] { "-m", "5", "50", "-o", "3", "-n", "100", "-c" };  6 String[] arg2 = new String[] { "-o", "3", "-m", "5", "50", "-n", "100", "-b" };  7 String[] arg3 = new String[] { "-n", "100", "-o", "3", "-m", "5", "50" };  8 Command.main(arg0);// 有括號四則運算測試  9 Command.main(arg1);// 四則運算測試 10 Command.main(arg2);// 有括號加減運算測試 11 Command.main(arg3);// 加減運算測試 12 }
命令行正確輸入測試

    該部分測試的命令行的更改輸入順序的四種出題選擇正常運行。輸入異常部分請看第七點。

    命令行單元測試覆蓋率截圖以下:

1 @Test 2 public void testDecide2() { 3 int[] find = new int[2]; 4 find = calculate.decide2(20, 2); 5 assertEquals(2, find[1]); 6 find = calculate.decide2(13, 2); 7 assertEquals(1, find[0]); 8 }
除法選擇除數測試

    decide2(int x, int min)爲除法選擇除數的函數,函數以下:

 1 // 被除數能被除數整除並不低於最小  2 public static int[] decide2(int x, int min)  3  {  4 int[] judge = new int[] { 1, 0 };  5 int temp = Math.abs(x) / min - min + 1;// 除數的範圍  6 for (int i = min; i < (temp + min); i++)  7  {  8 if (Math.abs(x) % i == 0)  9 {// 判斷是否整除 10 judge[0] = 0; 11 judge[1] = i; 12 return judge; 13  } 14  } 15 return judge; 16 }
decide2函數

    其中,judge[0]用於判斷該數可否有可整除的除數,1爲沒有,0爲有,judge[1]爲除數的值。該單元測試則測試了一次可產生除數與一次不能產生除數的狀況。

 


 

異常說明

 1 @Test  2 public void testAll() {  3 String[] arg4 = new String[] { "-o", "3", "-m", "5", "50", "-n" };  4 String[] arg4_1 = new String[] { "-o", "3", "-n", "-m", "5", "50" };  5 String[] arg4_2 = new String[] { "-n", "100000", "-m", "5", "50" };  6 String[] arg4_3 = new String[] { "-o", "3", "-m", "5", "50" };  7  8 String[] arg5 = new String[] { "-n", "50" };  9 String[] arg5_1 = new String[] { "-m", "5", "-n", "50", "-o", "3" }; 10 String[] arg5_2 = new String[] { "-n", "50", "-m", "3" }; 11 String[] arg5_3 = new String[] { "-n", "50", "-o", "3", "-m" }; 12 String[] arg5_4 = new String[] { "-m", "-n", "50" }; 13 14 String[] arg6 = new String[] { "-o", "11", "-m", "5", "50", "-n", "100" }; 15 String[] arg6_1 = new String[] { "-n", "100", "-o", "-m", "5", "50" }; 16 String[] arg6_2 = new String[] { "-n", "100", "-m", "5", "50", "-o" }; 17 18 String[] arg7 = new String[] { "-m", "5", "20", "-n", "100", "-c" }; 19 String[] arg7_1 = new String[] { "-m", "5", "50", "-n", "100", "-b" }; 20 21 String[] arg8 = new String[] { "-b", "1", "-o", "3", "-m", "5", "50", "-n", "100" }; 22 String[] arg8_1 = new String[] { "-c", "1", "-o", "3", "-m", "5", "50", "-n", "100" }; 23 String[] arg8_2 = new String[] { "-n", "100", "-m", "5", "50", "-d" }; 24 25 Command.main(arg4);// 缺乏題數值測試 26  Command.main(arg4_1); 27 Command.main(arg4_2);// 題數值過大測試 28 Command.main(arg4_3);// 缺乏題數測試 29 30 Command.main(arg5);// 缺乏數值範圍 31 Command.main(arg5_1);// 缺乏數值範圍上限測試 32  Command.main(arg5_2); 33 Command.main(arg5_3);// 缺乏數值範圍上下限測試 34  Command.main(arg5_4); 35 36 Command.main(arg6);// 操做符數值過大測試 37 Command.main(arg6_1);// 缺乏操做符數值測試 38  Command.main(arg6_2); 39 40 Command.main(arg7);// 乘除須要上界大於下界的平方 41 Command.main(arg7_1);// 括號須要操做符數大於1 42 43 Command.main(arg8);// 輸入非法測試之b後有數字 44 Command.main(arg8_1);// 輸入非法測試之c後有數字 45 Command.main(arg8_2);// 輸入非法測試之無辨識字符 46 }
命令行異常輸入測試

    對於命令行可能出現的異常大概有13個:

  • 缺乏題數值(-n後無帶數字,如arg4與arg4_1)時,提醒缺乏題數值,並告知-n的範圍;

  • 題數值過大(-n後數值超過10000,如arg4_2)時,提醒告知題數值範圍(太小同理);

  • 缺乏題數(命令中無-n,如arg4_3)時,提醒-n爲必須項,並告知-n範圍。

  • 缺乏數值範圍(命令中無-m,如arg5)時,提醒-m爲必須項,並告知-m上下限各自範圍;

  • 缺乏數值範圍上限(-m後只帶一個數字,如arg5_1和 arg5_2)時,提醒缺乏上限,並告知上限範圍;

  • 缺乏數值範圍上下限(-m後不帶數字,如arg5_3和 arg5_4)時,提醒缺乏上下限,並告知上下限各自範圍;

  • 數值範圍數值太小過大時,提醒告知操做符數值範圍。

  • 操做符數值過大(-o後數值超過10,如arg6)時,提醒告知操做符數值範圍(太小同理);

  • 缺乏操做符數值(輸入-o,後方沒有帶數值,如arg6_1與arg6_2)時,提醒缺乏操做符數值,並告知-o範圍。

  • 選擇乘除法可是上界小於下界的平方,沒法生成含有乘除的式子(如arg7)時,提醒上界需大於下界的平方;

  • 選擇括號可是操做符默認爲1或選擇爲1,不符合生成括號的條件(如arg7_1)時,提醒選擇括號須要操做符數大於1。

  • –b(或-c)後帶數字(如arg8與arg8_1),提醒-b(或-c)後不能帶數字;

  • 出現除m、n、o、b、c外的字符如d等(如arg8_2),提醒輸入值非法。

 

 


 

界面模塊的詳細設計過程

    設計圖以下:

    咱們先從選擇出題或作題開始。

    選擇出題則進入出題參數輸入界面。

    利用MouseListenermouseEntered(MouseEvent e)setTitle(String);使得鼠標移到參數上,標題會有提示功能。

    輸入完畢點擊確認後,由輸入的參數判斷是否有異常並提示直至無異常建立文件。

 1 public class submitListener implements ActionListener {  2 public void actionPerformed(ActionEvent e) {  3 String m = "題數與數值上下限爲必填項,請按標題提示輸入正整數!";  4 String m2 = "建立文件成功!";  5 int n0, lower0, upper0, o0, c0, b0;  6 o0 = 1;  7 c0 = 0;  8 b0 = 0;  9 String o1 = ""; 10 try { 11 n0 = Integer.parseInt(n.getText()); 12 lower0 = Integer.parseInt(lower.getText()); 13 upper0 = Integer.parseInt(upper.getText()); 14 if (n0 < 1 || n0 > 10000) { 15 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "題數範圍爲1-10000", "提示", 16  JOptionPane.INFORMATION_MESSAGE); 17 return; 18  } 19 if (lower0 < 1 || lower0 > 100) { 20 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "下界範圍爲1-100", "提示", 21  JOptionPane.INFORMATION_MESSAGE); 22 return; 23  } 24 if (upper0 < 50 || upper0 > 1000) { 25 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "上界範圍爲50-1000", "提示", 26  JOptionPane.INFORMATION_MESSAGE); 27 return; 28  } 29 if (upper0 < (2 * lower0)) { 30 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "上界必須大於兩倍下界", "提示", 31  JOptionPane.INFORMATION_MESSAGE); 32 return; 33  } 34 } catch (NumberFormatException e2) { 35 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), m, "提示", JOptionPane.INFORMATION_MESSAGE); 36 return; 37  } 38 try { 39 o1 = o.getText(); 40 o0 = Integer.parseInt(o1); 41 } catch (NumberFormatException e2) { 42 if (!o1.equals("")) { 43 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "請輸入1-10的正整數或不輸入保持默認,默認爲1", "提示", 44  JOptionPane.INFORMATION_MESSAGE); 45 return; 46  } 47  } 48 if (c.isSelected()) { 49 c0 = 1; 50  } 51 if (b.isSelected()) { 52 b0 = 1; 53  } 54 if (o0 == 1 && b0 == 1) { 55 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "括號須要操做符數量大於1", "提示", 56  JOptionPane.INFORMATION_MESSAGE); 57 return; 58  } 59 if (c0 == 1 && upper0 < (lower0 * lower0)) { 60 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "乘除法須要上界數值大於下界的平方", "提示", 61  JOptionPane.INFORMATION_MESSAGE); 62 return; 63  } 64  createFile.fileCreate(n0, lower0, upper0, o0, c0, b0); 65 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), m2, "提示", JOptionPane.INFORMATION_MESSAGE); 66 System.exit(0); 67  } 68 }
參數確認

    選擇作題則先輸入作題人名字(在這裏建議使用英文,中文名字沒法很好的記錄)。

    接着上傳文件,在這裏使用了txt文件過濾器,使之僅可上傳txt文件。

1 FileFilter filter = new FileNameExtensionFilter("Text file", "txt"); 2 JFileChooser fileChooser = new JFileChooser(); 3 fileChooser.setAcceptAllFileFilterUsed(false); 4 fileChooser.addChoosableFileFilter(filter); 5 FileSystemView fsv = FileSystemView.getFileSystemView();
過濾器

    另外,出題與作題都統一爲utf-8編碼,免去執行文件編碼錯誤。

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true), "UTF-8"));
InputStreamReader read = new InputStreamReader(new FileInputStream(file), "utf-8");

    上傳成功後開始計時作題,並於最後結果中顯示用時。

    通過後面JTextPane控件的啓發,我考慮到出題時題目長度有長短,爲了更加美觀顯示,應該須要自動換行,我一樣採用了HTML編輯文本的想法,作出改進。

 1 public static void JlabelSetText(JLabel jLabel, String longString) throws InterruptedException {  2 StringBuilder builder = new StringBuilder("<html>");  3 char[] chars = longString.toCharArray();  4 FontMetrics fontMetrics = jLabel.getFontMetrics(jLabel.getFont());  5 int start = 0;  6 int len = 0;  7 while (start + len < longString.length()) {  8 while (true) {  9 len++; 10 if (start + len > longString.length()) 11 break; 12 if (fontMetrics.charsWidth(chars, start, len) > jLabel.getWidth()) { 13 break; 14  } 15  } 16 builder.append(chars, start, len - 1).append("<br/>"); 17 start = start + len - 1; 18 len = 0; 19  } 20 builder.append(chars, start, longString.length() - start); 21 builder.append("</html>"); 22  jLabel.setText(builder.toString()); 23 }
換行

    計時方面我本來採用秒數計時,後來考慮到當作題時間較長時,秒數很難清晰明確的表達,因此改用了 hh:mm:ss 法顯示。

 1 public static String getTimeStrBySecond(long second) {  2 if (second <= 0) {  3 return "00:00:00";  4  }  5 int hours = (int) second / HOUR_SECOND;  6 if (hours > 0) {  7  8 second -= hours * HOUR_SECOND;  9  } 10 int minutes = (int) second / MINUTE_SECOND; 11 if (minutes > 0) { 12 second -= minutes * MINUTE_SECOND; 13  } 14 return (hours > 10 ? (hours + "") 15 : ("0" + hours) + ":" + (minutes > 10 ? (minutes + "") : ("0" + minutes)) + ":" 16 + (second > 10 ? (second + "") : ("0" + second))); 17 }
秒數轉換

    自動換行處理與秒數轉換被我寫入新類——dataDeal類中。

    最終作完題目後除了顯示用時,還顯示題數、分數、錯題以及該題正確答案,非首次用戶會顯示歷史分數以及最高分數。

    本來該部分使用了JTextArea控件,但學姐建議正確答案部分對齊顯示會更加美觀,並提出了C#中的ListView控件,但很遺憾,Java中彷佛並無。JTextArea控件是純文本顯示,很難作到不一樣的對齊方式,因此我刪除了該類。通過多方學習比較,我最終選擇了JTextPane控件,該控件簡單易用,可將文本顯示爲HTML文本,大大提升了編輯的樣式性。我最終採起了表格法對齊,另外對重點突出的地方加粗變紅顯示,達到強調與必定視覺衝擊效果,可從後文看到對比圖。

 1 String text = "<p style='font-family:楷體; font-size:19'>" + name + " 本次用時<span style='color:red'><strong> "  2 + dataDeal.getTimeStrBySecond(spentTime) + " </strong></span>,得分<span style='color:red'><strong> "  3 + goal + " </strong></span>分。<br>";  4 if (size0 == 0) {  5 text += "你總共答了<span style='color:red'><strong> " + size  6 + " </strong></span>道題,並所有答對!<span style='color:red'><strong>恭喜!</strong></span></p>";  7 } else {  8 text += "你總共答了<span style='color:red'><strong> " + size  9 + " </strong></span>道題,答對<span style='color:red'><strong> " + size1 10 + " </strong></span>道,答錯<span style='color:red'><strong> " + size0 11 + " </strong></span>道,分別爲:</p><p><table border=0>"; 12 for (int i = 0; i < (size0 * 2); i++) { 13 text += "<tr><td style='font-family:楷體; font-size:19'><strong>" + wrong.get(i++) 14 + " </strong></td><td width='180' style='font-family:楷體; font-size:19;color:red'><strong> " 15 + wrong.get(i) + "</strong></td></tr>"; 16  } 17  } 18 text += "</table></p>"; 19 text += "<p style='font-family:楷體; font-size:19'>" + createFile.record(name, goal) + "</p>"; 20 21 JTextPane textarea = new JTextPane(); 22 textarea.setContentType("text/html"); 23  textarea.setText(text); 24 textarea.setEditable(false); 25 JScrollPane textAreascrollPane = new JScrollPane(textarea); 26 add(textAreascrollPane, BorderLayout.CENTER);
JTextPane

 


 

界面模塊與計算模塊的對接

    如圖所示

    在界面模塊選擇出題輸入參數以後調用fileCreate類,再由fileCreate類調用計算模塊,建立result.txt

    在界面模塊選擇作題輸入名字、上傳文件、作題。作題時調用計算模塊的stack類計算判斷正確性,記錄錯題。最終結果由計算模塊中的fileCreate類的record(String name, int goal)記錄,由界面模塊顯示。

    實現的功能大體有12個,而且爲了提升用戶體驗,修改了圖標並增長了背景,將操做符數修改成下拉框選擇,默認選擇爲1,避免輸入非數字錯誤:

模式選擇

出題參數輸入(先後對比圖)

出題參數要求提醒

輸入參數有誤提醒(見第七點異常)

生成文件

記錄用戶

上傳文件(只容許txt文件)

判斷文件是否爲空或非練習題

計時

一道一道作題而且題目過長時自動換行

評分

    根據學姐給的建議作出了修改,如下爲先後對比圖,正確答案對齊,使之更加美觀。另外我修改了作題時間的顯示形式,這樣當作題時間較長時能夠更加清晰的看出時間狀況。而作題時間、得分狀況、錯題與正確答案皆加粗甚至標紅,使之更加顯眼,提升用戶體驗。

記錄歷史分數與最高分數

 


 

結對編程

    咱們先一塊兒分析了需求與功能的實現,並提出了一些有實質性的方法,並確認數據的傳遞方式。再分析各自的我的項目代碼,指出了雙方優劣性,在綜合考慮選擇基礎代碼加以改進。

    咱們根據本身較爲擅長的方面分工,如相對之下,我對gui較爲熟悉,而她對字符串處理較爲熟悉,則我負責界面展現而她負責命令行的分析。各自寫完以後咱們再複審雙方代碼,對代碼不理解之處詢問並補充註釋,以及對雙方異常狀況補充。最後在一塊兒整合雙方代碼,使之成爲完整項目。

 


 

結對編程的優缺點

    在此過程當中咱們互相幫助、互相學習、能力上獲得互補,而代碼和產品質量提升,有效地減小bug而且考慮到更多方面的狀況。有兩臺電腦能夠測試程序效果,如她的電腦比我小,個人gui顯示不一樣,她的部分算式被遮擋,最終我選擇了將按鈕部分的面板設爲透明,解決了這個問題。

    不足之處在於隊友之間的進度相互影響,不一樣的代碼風格之間的磨合也花費了必定時間。

    雙方優缺點:

  莊莉 王璐瑤
優勢

認真細心,有責任心

不辭辛苦

代碼能力高

對字符串以及字符串數組的處理十分熟練

動手能力強

頗有想法,有好點子

缺點

有時候對於小問題過於鑽牛角尖

因生病而不在狀態,沒注意到比較細的地方,時間較少

 


 

實際PSP

PSP

任務內容

實際完成須要的時間(min)

Planning

計劃

0.5

Estimate

   估計這個任務須要多少時間,並規劃大體工做步驟

0.5

Development

開發

53.25

   Analysis

需求分析 (包括學習新技術)

0.5

Design Spec

  生成設計文檔

0.25

  Design Review

設計複審 (和同事審覈設計文檔)

0.25

Coding Standard

 代碼規範 (爲目前的開發制定合適的規範)

0.25

 Design

 具體設計

1

Coding

具體編碼

40

Code Review

 代碼複審

1

Test

測試(自我測試,修改代碼,提交修改)

10

Reporting

報告

9

Test Report

測試報告

8

 Size Measurement

計算工做量

0.5

Postmortem & Process Improvement Plan

過後總結, 並提出過程改進計劃

0.5

 


 

    本次結對編程真的讓我學到不少知識,尤爲是各類操做,就像上一篇博客的連接同樣,我查了許許多多這樣的連接,學習了一種有一種的方法,與隊友配合,完成了此次項目。而每次寫博客,都能從新總結個人思路,受益良多。

    雖然真的很辛苦,但能作出來也就夠了。

 


 

    如下部分因爲時間與精力關係,咱們小組並無完成,僅提供思路參考,有想法的同窗可加以嘗試。

    附加題多語言思路參考:程序國際化

 

https://blog.csdn.net/zhuxinquan61/article/details/51540806

 

http://www.javashuo.com/article/p-gdfjqelb-me.html

 

    思路注意點參考:

  • 文字描述使用短語、名詞與阿拉伯數字,便於翻譯。 標準語言建議英語,中文字符難以使用字符串判斷內容。
  • 語言選擇可爲下拉框列表旁邊帶一不可編輯的文本框。因爲能夠自添加,因此能夠創建一個文件(如txt),文件中加入選項,執行代碼時讀出文件,for循環將每一項添加進下拉框列表中。有一項設置爲其餘或自定義,選擇它時,旁邊的文本框變爲可編輯,用於添加語言(也可以讓下拉框爲可編輯,當輸入的語言下拉選項中沒有時認爲添加新語言)。
  • 添加語言則需配置文件(參考網址),將全部須要翻譯的文字讓用戶對應翻譯。生成新的配置文件,並命名爲該語言(使用英文命名),將該語言添加到保存下拉框選項的文件中。
  • 當用戶選擇一種語言時,經過其相同的命名,便可調用該語言的配置文件進行翻譯,達到多語言轉化功能。
相關文章
相關標籤/搜索