1 package org.xn.chapter11.practice; 2 /** 3 * 课后习题1:做一个计算器,这里我们以windows-XP中的calc计算器的标准型为目标来做 4 * 程序分解: 5 * 1、GUI界面: 6 * 菜单栏:编辑(复制,粘贴)、查看、帮助 7 * 单行文本框: 8 * 回退键:Backspace、CE、C 9 * 数字键:1-9 、“0”、“.” 、“+/-” 10 * 计算键:+ 、- 、* 、/ ;sqrt 、% 、1/x 、 = 11 * 12 * 2、计算核心: 13 * 数字button监听类 14 * 计算方法button监听类 15 * 回退button监听类 16 * 17 * 总结: 18 * 计算器的大部分功能都得到了实现,比如:最基本的四则运算、3个特殊运算、3个不同的回退方法、 19 * 文本框只允许出现数字和运算符、运算时不能以运算符开头、一次运算自能输入一个运算符、特殊运算符只有一个数字、 20 * 菜单栏中只实现了编辑菜单中的复制、粘贴两个功能、 21 * 22 * 已知bug: 23 * 1、在键盘输入的时候,不能保证输入的运算符总是在末尾 24 * 2、 25 * 26 * 27 * */ 28 29 import java.awt.BorderLayout; 30 import java.awt.Button; 31 import java.awt.Color; 32 import java.awt.Frame; 33 import java.awt.GridLayout; 34 import java.awt.Menu; 35 import java.awt.MenuBar; 36 import java.awt.MenuItem; 37 import java.awt.MenuShortcut; 38 import java.awt.Panel; 39 import java.awt.TextField; 40 import java.awt.Toolkit; 41 import java.awt.datatransfer.Clipboard; 42 import java.awt.datatransfer.DataFlavor; 43 import java.awt.datatransfer.StringSelection; 44 import java.awt.datatransfer.UnsupportedFlavorException; 45 import java.awt.event.ActionEvent; 46 import java.awt.event.ActionListener; 47 import java.awt.event.KeyAdapter; 48 import java.awt.event.KeyEvent; 49 import java.awt.event.WindowAdapter; 50 import java.awt.event.WindowEvent; 51 import java.io.IOException; 52 53 import javax.swing.Box; 54 55 public class Calculator{ 56 Frame f = new Frame("计算器");//窗体 57 MenuBar mb = new MenuBar();//菜单 58 Box bMod = Box.createHorizontalBox();//水平盒子,用来盛放三个修改按钮 59 Box bTop = Box.createVerticalBox();//垂直盒子,用来盛放文本行+水平盒子 60 //利用Toolkit工具包类取得系统工具包,在系统工具包中取得系统剪贴板 61 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); 62 63 TextField tf = new TextField(20);//文本行 64 Panel p = new Panel();//用来盛放数字键+运算符 65 66 Panel numPan = new Panel();//定义数字键盘 67 Panel mathPan1 = new Panel();//定义加减乘除 68 Panel mathPan2 = new Panel();//定义开方、求模、求倒数、等于 69 70 Menu edit = new Menu("编辑"); 71 Menu select = new Menu("查看"); 72 Menu help = new Menu("帮助"); 73 74 MenuItem copyItem = new MenuItem("复制",new MenuShortcut(KeyEvent.VK_C)); 75 MenuItem patseItem = new MenuItem("粘贴",new MenuShortcut(KeyEvent.VK_P)); 76 77 MenuItem standard = new MenuItem("标准型"); 78 MenuItem science = new MenuItem("科学型"); 79 MenuItem group = new MenuItem("数字分组"); 80 81 MenuItem item = new MenuItem("帮助主题"); 82 MenuItem about = new MenuItem("关于计算器"); 83 Button but1 = new Button("1"); 84 Button but2 = new Button("2"); 85 Button but3 = new Button("3"); 86 Button but4 = new Button("4"); 87 Button but5 = new Button("5"); 88 Button but6 = new Button("6"); 89 Button but7 = new Button("7"); 90 Button but8 = new Button("8"); 91 Button but9 = new Button("9"); 92 Button but0 = new Button("0"); 93 Button butFuhao = new Button("+/-"); 94 Button butDian = new Button("."); 95 96 Button butAdd = new Button("+"); 97 Button butSub = new Button("-"); 98 Button butMul = new Button("*"); 99 Button butDiv = new Button("/");100 101 Button butSqr = new Button("sqr");102 Button butDao = new Button("1/x");103 Button butMo = new Button("%");104 Button butEqu = new Button("=");105 106 Button butBackspace = new Button("Backspace");107 Button butCE = new Button("CE");108 Button butC = new Button("C");109 110 public void init(){111 //为运输符号按钮设置颜色112 butAdd.setForeground(Color.RED);113 butSub.setForeground(Color.RED); 114 butMul.setForeground(Color.RED); 115 butDiv.setForeground(Color.RED); 116 butSqr.setForeground(Color.RED); 117 butMo.setForeground(Color.RED); 118 butDao.setForeground(Color.RED); 119 butEqu.setForeground(Color.RED); 120 butBackspace.setForeground(Color.RED); 121 butCE.setForeground(Color.RED); 122 butC.setForeground(Color.RED); 123 //添加按钮124 edit.add(copyItem);125 edit.add(patseItem);126 select.add(standard);127 select.add(science);128 select.add(group);129 help.add(item);130 help.add(about);131 mb.add(edit);132 mb.add(select);133 mb.add(help);134 bMod.add(butBackspace);135 bMod.add(butCE);136 bMod.add(butC);137 bTop.add(tf,BorderLayout.NORTH);138 bTop.add(bMod);139 // 设置Panel使用GridLayout布局管理器140 numPan.setLayout(new GridLayout(4, 4 , 4, 4));141 mathPan1.setLayout(new GridLayout(4, 2 , 4, 4));142 mathPan2.setLayout(new GridLayout(4, 2 , 4, 4));143 //将生成的按钮添加到组件上144 numPan.add(but1);145 numPan.add(but2);146 numPan.add(but3);147 numPan.add(but4);148 numPan.add(but5);149 numPan.add(but6);150 numPan.add(but7);151 numPan.add(but8);152 numPan.add(but9);153 numPan.add(but0);154 numPan.add(butFuhao);155 numPan.add(butDian);156 mathPan1.add(butAdd);157 mathPan1.add(butSub);158 mathPan1.add(butMul);159 mathPan1.add(butDiv);160 mathPan2.add(butSqr);161 mathPan2.add(butDao);162 mathPan2.add(butMo);163 mathPan2.add(butEqu);164 //为关闭窗体添加监听事件165 f.addWindowListener(new WindowAdapter(){166 public void windowClosing(WindowEvent e){167 System.exit(1);168 }169 });170 171 //为单行文本框添加键盘监听,只允许输入数字和运算符号,其他的输入一律无效172 tf.addKeyListener(new KeyAdapter(){173 public void keyReleased(KeyEvent e){174 char c = e.getKeyChar();175 byte b = (byte)c;176 if(b==10){177 String temp = tf.getText();178 if(temp.matches("\\S+\\+\\S+")){179 String num[] = temp.split("\\+");180 double result = Double.parseDouble(num[0])+Double.parseDouble(num[1]);181 tf.setText(result+"");182 return;183 }184 //求两个数的差值185 if(temp.matches("\\S+\\-\\S+")){186 String num[] = temp.split("\\-");187 double result = 0.0;188 if(num.length==2){189 result = Double.parseDouble(num[0])-Double.parseDouble(num[1]);190 }191 if(num.length==3){192 result = -Double.parseDouble(num[1])-Double.parseDouble(num[2]);193 }194 tf.setText(result+"");195 return;196 }197 //求两个数的积198 if(temp.matches("\\S+\\*\\S+")){199 String num[] = temp.split("\\*");200 double result = Double.parseDouble(num[0])*Double.parseDouble(num[1]);201 tf.setText(result+"");202 return;203 }204 //求一个数的倒数,求倒数应该在求商的前面,避免发生混淆205 if(temp.matches("\\S+[1/x]\\S+")){206 String num[] = temp.split("1/x");207 double result = 1/Double.parseDouble(num[0]);208 tf.setText(result+"");209 return;210 }211 //求两个数的商,这里的求商要和求倒数区分开来212 if(temp.matches("\\d+\\/\\d+")){213 String num[] = temp.split("\\/");214 double result = Double.parseDouble(num[0])/Double.parseDouble(num[1]);215 tf.setText(result+"");216 return;217 }218 //求一个数的平方根219 if(temp.matches("\\S+sqr")){220 String num[] = temp.split("sqr");221 double result = Math.sqrt(Double.parseDouble(num[0]));222 tf.setText(result+"");223 return;224 }225 //求两个数相除的模(即余数)226 if(temp.matches("\\S+\\%\\S+")){227 String num[] = temp.split("\\%");228 double result = Double.parseDouble(num[0])%Double.parseDouble(num[1]);229 tf.setText(result+"");230 return;231 }232 }233 if(!(b>=42&&b<=57)){234 tf.setText("");235 }236 }237 });238 239 //将组件添加到窗体中240 p.add(numPan);241 p.add(mathPan1);242 p.add(mathPan2);243 f.setMenuBar(mb);244 f.add(bTop,BorderLayout.NORTH);245 f.add(p);246 //设置用户不能调整窗体大小247 f.setResizable(false); 248 //设置窗口为最佳大小249 f.pack();250 //将窗口显示出来(Frame对象默认处于隐藏状态)251 f.setVisible(true);252 //添加数字按钮和运算按钮的监听事件253 Operate();254 //添加复制、粘贴的监听方法255 editMethod();256 }257 258 //定义操作方法,包括了数字和计算方法的监听259 public void Operate(){260 //定义数字按钮的监听事件261 ActionListener numListener = new ActionListener(){262 public void actionPerformed(ActionEvent e){263 if(e.getActionCommand().equals("1")){264 if(isOver(tf.getText())){265 return;266 }267 tf.setText(tf.getText()+"1");268 }269 if(e.getActionCommand().equals("2")){270 if(isOver(tf.getText())){271 return;272 }273 tf.setText(tf.getText()+"2");274 }275 if(e.getActionCommand().equals("3")){276 if(isOver(tf.getText())){277 return;278 }279 tf.setText(tf.getText()+"3");280 }281 if(e.getActionCommand().equals("4")){282 if(isOver(tf.getText())){283 return;284 }285 tf.setText(tf.getText()+"4");286 }287 if(e.getActionCommand().equals("5")){288 if(isOver(tf.getText())){289 return;290 }291 tf.setText(tf.getText()+"5");292 }293 if(e.getActionCommand().equals("6")){294 if(isOver(tf.getText())){295 return;296 }297 tf.setText(tf.getText()+"6");298 }299 if(e.getActionCommand().equals("7")){300 if(isOver(tf.getText())){301 return;302 }303 tf.setText(tf.getText()+"7");304 }305 if(e.getActionCommand().equals("8")){306 if(isOver(tf.getText())){307 return;308 }309 tf.setText(tf.getText()+"8");310 }311 if(e.getActionCommand().equals("9")){312 if(isOver(tf.getText())){313 return;314 }315 tf.setText(tf.getText()+"9");316 }317 if(e.getActionCommand().equals("0")){318 if(isOver(tf.getText())){319 return;320 }321 tf.setText(tf.getText()+"0");322 }323 if(e.getActionCommand().equals(".")){324 String str = tf.getText();325 if(isEnd(str)){ //如果程序以运输符号结尾则无法再输入任何运输符326 return;327 }328 if(str.matches("\\d+\\.\\d+")){329 return;330 }331 tf.setText(tf.getText()+".");332 }333 if(e.getActionCommand().equals("+/-")){334 String str = tf.getText();335 if(isEnd(str)){ //如果程序以运输符号结尾则无法再输入任何运输符336 return;337 }338 if(str.matches("-\\d+")){339 char[] c = str.toCharArray();340 tf.setText(new String(c,1,c.length-1));341 }else{342 tf.setText("-"+str);343 }344 }345 }346 };347 //定义计算按钮的监听事件348 ActionListener mathListener = new ActionListener(){349 public void actionPerformed(ActionEvent e){350 if(e.getActionCommand().equals("+")){351 if(isEnd(tf.getText())){ //如果程序以运输符号结尾则无法再输入任何运输符352 return;353 }354 tf.setText(tf.getText()+"+");355 }356 if(e.getActionCommand().equals("-")){357 if(isEnd(tf.getText())){358 return;359 }360 tf.setText(tf.getText()+"-");361 }362 if(e.getActionCommand().equals("*")){363 if(isEnd(tf.getText())){364 return;365 }366 tf.setText(tf.getText()+"*");367 }368 if(e.getActionCommand().equals("/")){369 if(isEnd(tf.getText())){370 return;371 }372 tf.setText(tf.getText()+"/");373 }374 if(e.getActionCommand().equals("sqr")){375 if(isEnd(tf.getText())){376 return;377 }378 tf.setText(tf.getText()+"sqr");379 }380 if(e.getActionCommand().equals("1/x")){381 if(isEnd(tf.getText())){382 return;383 }384 tf.setText(tf.getText()+"1/x");385 }386 if(e.getActionCommand().equals("%")){387 if(isEnd(tf.getText())){388 return;389 }390 tf.setText(tf.getText()+"%");391 }392 if(e.getActionCommand().equals("Backspace")){393 String temp = tf.getText();394 if(temp.length()==0){395 return;396 }397 char[] c = temp.toCharArray();398 tf.setText(new String(c,0,c.length-1));399 }400 if(e.getActionCommand().equals("CE")){401 String temp = tf.getText();402 String[] num = temp.split("\\D");403 if(num.length==1){404 tf.setText("");405 }406 if(num.length==2){407 tf.setText(num[0]);408 }409 }410 if(e.getActionCommand().equals("C")){411 tf.setText("");412 }413 //输入等号的时候,对TextField中输入的文字进行运算414 if(e.getActionCommand().equals("=")){415 String temp = tf.getText();416 if(temp.matches("\\S+\\+\\S+")){417 String num[] = temp.split("\\+");418 double result = Double.parseDouble(num[0])+Double.parseDouble(num[1]);419 tf.setText(result+"");420 return;421 }422 //求两个数的差值423 if(temp.matches("\\S+\\-\\S+")){424 String num[] = temp.split("\\-");425 double result = 0.0;426 if(num.length==2){427 result = Double.parseDouble(num[0])-Double.parseDouble(num[1]);428 }429 if(num.length==3){430 result = -Double.parseDouble(num[1])-Double.parseDouble(num[2]);431 }432 tf.setText(result+"");433 return;434 }435 //求两个数的积436 if(temp.matches("\\S+\\*\\S+")){437 String num[] = temp.split("\\*");438 double result = Double.parseDouble(num[0])*Double.parseDouble(num[1]);439 tf.setText(result+"");440 return;441 }442 //求一个数的倒数,求倒数应该在求商的前面,避免发生混淆443 if(temp.matches("\\S+[1/x]\\S+")){444 String num[] = temp.split("1/x");445 double result = 1/Double.parseDouble(num[0]);446 tf.setText(result+"");447 return;448 }449 //求两个数的商,这里的求商要和求倒数区分开来450 if(temp.matches("\\d+\\/\\d+")){451 String num[] = temp.split("\\/");452 double result = Double.parseDouble(num[0])/Double.parseDouble(num[1]);453 tf.setText(result+"");454 return;455 }456 //求一个数的平方根457 if(temp.matches("\\S+sqr")){458 String num[] = temp.split("sqr");459 double result = Math.sqrt(Double.parseDouble(num[0]));460 tf.setText(result+"");461 return;462 }463 //求两个数相除的模(即余数)464 if(temp.matches("\\S+\\%\\S+")){465 String num[] = temp.split("\\%");466 double result = Double.parseDouble(num[0])%Double.parseDouble(num[1]);467 tf.setText(result+"");468 return;469 }470 }471 }472 };473 //为所有的按钮添加监听事件474 but1.addActionListener(numListener);475 but2.addActionListener(numListener);476 but3.addActionListener(numListener);477 but4.addActionListener(numListener);478 but5.addActionListener(numListener);479 but6.addActionListener(numListener);480 but7.addActionListener(numListener);481 but8.addActionListener(numListener);482 but9.addActionListener(numListener);483 but0.addActionListener(numListener);484 butDian.addActionListener(numListener);485 butFuhao.addActionListener(numListener);486 butAdd.addActionListener(mathListener);487 butSub.addActionListener(mathListener);488 butMul.addActionListener(mathListener);489 butDiv.addActionListener(mathListener);490 butSqr.addActionListener(mathListener);491 butMo.addActionListener(mathListener);492 butDao.addActionListener(mathListener);493 butEqu.addActionListener(mathListener);494 butBackspace.addActionListener(mathListener);495 butCE.addActionListener(mathListener);496 butC.addActionListener(mathListener);497 }498 499 //以下的几种情况如果成立,则返回true,否则返回false。500 public boolean isEnd(String str){501 boolean temp = false;502 //不允许以运算符开头503 if(str.matches("")){504 temp = true;505 }506 //如果一个数字以运算结尾,后面不得再次输入运算符507 if(str.endsWith("+")||str.endsWith("-")||str.endsWith("*")||508 str.endsWith("/")||str.endsWith("sqr")||str.endsWith("1/x")||509 str.endsWith("%")||str.endsWith(".")){510 temp = true;511 }512 //如果两个数字中间出现过运算符,后面不得再次输入运算符513 if(str.matches("\\d+\\+\\d+")||str.matches("\\d+\\-\\d+")514 ||str.matches("\\d+\\*\\d+")||str.matches("\\d+\\/\\d+")){515 temp = true;516 }517 return temp;518 }519 520 //如果运算符是求平方根、求倒数这两种情况,则不允许后面出现数字521 public boolean isOver(String str){522 boolean temp = false;523 if(str.endsWith("sqr")){524 temp = true;525 }526 if(str.endsWith("1/x")){527 temp = true;528 }529 return temp;530 }531 532 //添加菜单中的复制,粘贴功能533 public void editMethod(){534 copyItem.addActionListener(new ActionListener(){535 public void actionPerformed(ActionEvent e) {536 StringSelection contents = new StringSelection(tf.getText());537 clipboard.setContents(contents,null);538 }539 });540 patseItem.addActionListener(new ActionListener(){541 public void actionPerformed(ActionEvent e) {542 //首选要判断剪贴板中是否包含可以剪贴的内容543 if(clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)){544 String str = null;545 try {546 str = (String)clipboard.getData(DataFlavor.stringFlavor);547 tf.setText(str);548 } catch (UnsupportedFlavorException e1) {549 e1.printStackTrace();550 } catch (IOException e1) {551 e1.printStackTrace();552 }553 }554 }555 });556 }557 558 //构造方法559 public Calculator(){}560 561 public static void main(String[] args) {562 new Calculator().init();563 }564 }