暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java面向对象程序设计|文本框式计算器1.0

335

当用户与GUI交互时,如移动鼠标、按下键盘/鼠标各按键、单击按钮、在文本框输入文本、从下拉框中选择一项等,GUI会产生不同类型的事件。事件的产生地被称作事件源,如鼠标单击按钮,按钮就是事件源。每一种事件都有对应的监听器接口,接口中声明了事件处理方法。如ActionEvent事件对应接口ActionListener。实现特定类型监听器的类常被称作监听器,具备处理特定事件的能力。事件源不处理事件,而是通过与监听器对象建立关联,将事件传给(或者说委托给)监听器对象进行处理,故这种方式又称委托代理模式,见图4.4。


■ 图4.4  委托事件处理模型


java.awt.Component是按钮、标签、文本框、容器、选择框、列表框等的超类,其中定义了一组关联方法,如addActionListener(ActionListener x)、addKeyListener(KeyListener x)等。因此,各可视化组件能方便地与监听器建立关联。


01

综合示例:文本框式计算器1.0


下面示例将使用到网格布局GridLayout。该布局把容器分成m行n列的网格,每个格子只能放置一个组件,组件将自动占满格子。注意:无法将组件放到指定位置上。默认情况下,各组件将依照从左至右,自上而下次序填充各个网格。图4.6展示了3行2列的网格,放置7个按钮。


■ 图4.6  GridLayout界面示例


另外,当放置的组件数目超过m*n时,将自动增列;反之,若组件太少,则自动减少列数,而行数保持不变。若希望在一个网格中放多个组件,则应先在网格上放置一面板(Panel),面板可以重新设定布局方式。GridLayout也有三个构造函数,分别为:


GridLayout(int r, int c, int hgap, int vgap):r行c列,以及纵横间隙
GridLayout(int r, int c):相当于调用GridLayout(r, c, 0, 0)
GridLayout():相当于调用GridLayout(1, 1, 0, 0)


【例4.5】设计文本计算器,见图4.7。为确保文本框的运算信息与结果的一致性,在单击“=”后,需要将操作数/操作符文本框禁止输入,并将按钮改成“clear”,单击clear后还原成初始状态。另外,还需加入如下异常处理:

(1)当操作数文本框/运算符文本框中的字符串,在剔除首尾空格后,若字符串长度为0,则抛出自定义异常NoneException,提示“第1/2操作数为空”/“运算符为空”;

(2)当运算符框中的字符串剔除首尾空格后,若包含多个字符,或只包含一个字符,但该字符不是+-*/等字符时,抛出自定义异常OpCharException,提示“运算符过多”或“无法识别的运算符”;

(3)Double.parseDouble(s)可将s转换成double值。但若无法正确转换时,如s是"1.2.3"、"a.b"、"a3b",或是转换后的数值越界时,将抛出非检查型异常NumberFormatException,提示“数据格式有错”。类似地,Integer.parseInt(s),若无法将s转换成int,也将抛出“数据格式有错”。产生除零错时将抛出非检查型异常ArithmeticException,提示“除零错”。


■ 图4.7 简单计算器运行效果


目的:①理解和掌握网格布局GridLayout;②结合实例,掌握和应用异常处理机制;③进一步熟悉委托事件处理模型。

设计:在界面布局方面,本例使用了2*1的网格布局,其中在第一个网格放置一个面板,容纳操作数、操作符、按钮、小数位等组件,采用流式布局,第二个网格中直接放置一标签,用于显示错误信息。基于网格布局的特点,该标签会自动填满所处网格。

总体设计策略是:设计getDouble(…)、getInt(…)、getChar(…)可从文本框提取double、int、char型数据(若不能正确提取则抛出相关异常对象)。设计compute(…)实现计算并返回String型计算结果。另外,设计clickEq()封装单击“=”按钮时的处理,包括提取数据、实施计算、结果反馈等,若出现异常,则将异常显示在错误信息标签。

本例定义了三个异常类,当操作数/符文本框为空时抛出NoneException异常,当运算符多余一个字符或是不包含+-*/时抛出OpCharException异常,在小数位整数超出[0-4]范围时抛出DotNumberException异常。将文本框中的字符串转换成double/int时可能发生数据格式异常NumberFormatException,在捕获后重新创建(以便填入中文信息)并抛出,类似处理的还有ArithmeticException(除零异常)。上述异常的创建和外抛放置在getDouble(…)、getInt(…)、getChar(…)、compute(…)等方法中。

另外,为简化字体控制,本例使用了类SetDefaultFont,其设计详见4.3.1节。



/* 类的导入,略 */
class NoneException extends Exception{//当操作数或运算符文本框为空时抛出此异常
     public NoneException(String msg){ super(msg); }
}
class OpCharException extends Exception{//运算符过多、运算符不是+-*/时抛出此异常
     public OpCharException(String msg){ super(msg); }
}
class DotNumberException extends Exception{//小数位超出范围[0~4]时抛出此异常
     public DotNumberException(String msg){ super(msg); }
}
class Ch_4_5 extends JFrame implements ActionListener{
     private JButton bt_ok; //在 = 和clear之间切换
     private JTextField num1,num2,result,opChar,dotNum; //两个操作数、运算结果、运算符、小数位数
     private JLabel errorMsg; //用于显示错误信息的标签
     public Ch_4_5() { //以下为GUI界面设计部分
          super("简单文本计算器"); setSize(1000,150); setLocation(300,240);
          this.setLayout(new GridLayout(2,1)); //将窗体设为两行一列的网格
          JPanel p1=new JPanel(); p1.setLayout(new FlowLayout(FlowLayout.LEFT));
          num1=new JTextField(10); num2=new JTextField(10);
          opChar=new JTextField(2);
          result=new JTextField(20); result.setEditable(false);
          bt_ok = new JButton(" = ");
          dotNum=new JTextField(3); dotNum.setText("2"); //小数位数默认为2
          //先将各组件加入p1,之后将p1加入窗体
          p1.add(num1); p1.add(opChar); p1.add(num2);
          p1.add(bt_ok); p1.add(result);
          p1.add(new JLabel("保留:")); p1.add(dotNum); p1.add(new JLabel("位小数"));
          this.add(p1); //p1加入窗体
          errorMsg=new JLabel(" ");
          this.add(errorMsg); //将显示错误信息的标签加入第二个网格
          setVisible(true);
          setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置单击关闭按钮:退出程序
          bt_ok.addActionListener(this);
    }
     private double getDouble(JTextField jf,int num)throws NoneException{//从jf获取操作数
          double val; String s=jf.getText().trim(); //先剔除文本框的首尾空格
          if(s.length()==0)throw new NoneException("错误:第"+num+"个操作数为空!");
          try { val=Double.parseDouble(s); }
          catch(NumberFormatException e)//写入错误信息后重新抛出
           { throw new NumberFormatException("错误:第"+num+"个操作数数据格式错误!"); }
          return val;
    }
     private int getInt(JTextField jf)throws DotNumberException{//从jf获取小数位
          int val; String s=jf.getText().trim(); //先剔除文本框的首尾空格
          if(s.length()==0) return 0; //即小数位为0
          try {val=Integer.parseInt(s);}
          catch(NumberFormatException e)//写入错误信息后重新抛出
               { throw new NumberFormatException("错误:小数位格式错误!"); }
          if(val<0||val>4)throw new DotNumberException("错误:小数位取值范围是:0~4 !");
          return val;
     }
     private char getOpChar(JTextField jf)throws NoneException,OpCharException{//从jf获取操作符
          String s=jf.getText().trim();
          if(s.length()==0)throw new NoneException("错误:运算符框为空!");
          if(s.length()>1) throw new OpCharException("错误:运算符过多!");
          if("+-*/".indexOf(s)<0)throw new OpCharException("错误:无法识别的运算符!");
          return s.charAt(0);
     }
     private String compute(double x, double y,char op,int dotN){
          double r=0;
          if(y==0&&op=='/') throw new ArithmeticException("错误:除零错!");
          //注:为了显示中文信息,在捕获除零异常后,基于中文信息重新创建除零异常并抛出
          switch (op){
               case '+': r=x+y; break;
               case '-': r=x-y; break;
               case '*': r=x*y; break;
               case '/': r=x/y; break;
          }
          return String.format("%15."+dotN+"f",r); //总宽度15,dotN为小数位,右对齐
     }
     private void clickEq(){//单击=
          double a,b; char c; int dotN; String r;
          try{ a=getDouble(num1,1); b=getDouble(num2,2);
                    c=getOpChar(opChar); dotN=getInt(dotNum);
                    r=compute(a,b,c,dotN); result.setText(r);
                    errorMsg.setText(" ");//清空错误信息
     }catch(Exception x){ result.setText(""); errorMsg.setText(x.getMessage()); }
          bt_ok.setText("Clear");
          num1.setEditable(false);num2.setEditable(false);
          opChar.setEditable(false);dotNum.setEditable(false);
     }
     public void actionPerformed(ActionEvent e){ //单击按钮的处理
          if (e.getSource()==bt_ok)
          if( e.getActionCommand().equals(" = "))clickEq();
          else{//单击clear按钮
               num1.setText(""); num2.setText(""); result.setText("");
               opChar.setText(""); dotNum.setText("2");//默认保留两位小数
               errorMsg.setText(" "); bt_ok.setText(" = ");
               num1.setEditable(true); num2.setEditable(true);
               opChar.setEditable(true); dotNum.setEditable(true);
               num1.requestFocusInWindow(); //将焦点定位在第一个操作数
          }
     }
     public static void main(String[] args) {
          SetDefaultFont.setAll(new Font("宋体",Font.BOLD,26)); new Ch_4_5();
     }
}


02

示例剖析


本例目的之一是融入异常处理。总体策略为:在异常对象构造时传入期望输出的信息,在捕获后通过getMessage()获取该信息,继而将其标签的文本内容进行显示。其中,各文本框提取数据时可能产生自定义异常对象,通过throws声明;也可能产生的非检查型异常对象,通过捕获后新建(这样才能输入期望的信息)并重新抛出。鉴于非检查型异常可自动传播,故未用throws声明。

保留小数位数,通过String.format(…)来实现,如String.format("%6.2f",12.345);表示总宽度(含小数点和小数位)为6,2位小数,保留小数时会四舍五入,默认右对齐,结果为:"#12.35"(其中#表示空格)


实例讲解

Java面向对象程序设计

思想·方法·应用

精彩回顾

模拟银行存取款

模拟生产者-消费者问题


下期预告

二人间对话示例



03

参考书籍


Java面向对象程序设计:思想·方法·应用(微课视频版)

提供PPT课件,教学大纲,源码,视频,咨询QQ:2301891038(仅限教师)

ISBN:9787302590668

作者:化志章 揭安全 石海鹤 王岚

定价:59.8元

扫描,优惠购书

内容简介

本书基于Java语言,以案例为核心,问题求解为主线,快速深入地介绍面向对象程序设计的基本思想、方法和应用,以及GUI编程、线程、IO流等高级应用框架。

全书包括三部分:第1部分Java入门,对应第1章和第2章,讨论Java概况、JDK配置,从C过渡到Java,并涉及一些面向对象的基本概念、理念和语法元素;第2部分面向对象程序设计,对应第3章,结合案例,系统阐述面向对象程序设计方法及其语法支撑机制,还包括异常处理、内部类等辅助机制;第3部分实用技术和框架,包括第4~10章,涉及图形用户编程、线程机制、IO流、网络通信、泛型和集合框架、Java连接数据库、反射机制与代理模式等内容。

本书在内容组织上,基于案例介绍内容,直观、高效;在内容设计上,所有案例均有目的、设计、源码和分析,便于快速深入地理解、领会;在内容表述上,结合丰富的图解和形象的比喻,破解技术难点。各章的章首配有导引,指明本章的设置目的、内容组织的逻辑主线、重点和难点等内容;章末配有小结,进行简单梳理、提炼;“思考与练习”中提供一组问答题,用于回顾和检测对前期内容的理解,并提供一些综合型编程作业。

本书适合作为高等院校计算机、软件工程专业和各种软件培训机构的教材,也特别适合广大程序员及其他Java开发爱好者自学、参考。

04

精彩推荐


文章转载自清华计算机学堂,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论