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 }