![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }