一、课程设计目的和思路:
1、本次课程设计很好的帮助我们复习巩固Java语言的基础知识,进一步加深对Java语言的理解和掌握,通过本次课程设计,能够较全面的掌握面向对象程序设计的有关概念和开发方法,较全面地理解、掌握和综合运用所学的知识,以便提高自身的编程能力,锻炼我们分析解决实际问题的能力。
2、此次Java课程设计是关于图形用户界面的,图形用户界(Graphical User Interface,GUI)是使用图形方式借助菜单、编辑框、面板、按钮、标签等标准界面元素以及键盘、鼠标的操作,提供应用程序与用户进行数据交流的界面,实现人机交互,应用程序及能够显示数据,也能获得用户输入的数据和需要执行的命令。在Java中,图形用户界面的组件和事件由java.awt和java.swing包共同提供。java.awt称为抽象窗口工具集(Abstract Window Tookit,AWT),主要包括组件、事件处理模型、图形和图像工具、布局管理器等,其中的组件通常称为 AWT组件,而Swing组件扩展了AWT组件的功能;这里事件处理还直接用到了java.awt.event包。
3、此次的课程设计,我做的是一个简单计算器。拿到老师布置的作业时,最初的想法是做一个不仅能实现加减乘除等基本的运算,还能够实现四种进制之间的转换的计算器,但实际操作过程中,设计计算器界面时没能把进制的转换设计进去,又改变了策略,放弃了进制转换的实现;在添加按钮时,给各个按钮定义了算法,当鼠标点击某个按钮时就开始执行那个按钮所定义的算法,生成数据并显示在文本编辑框中。所以最终设计的计算器只实现了加、减、乘、除。开平方等简单运算的功能,但是我的计算器与标准计算器相比较大大的降低了数字计算的难度,并且提高了计算的准确度和精确度。
4、程序设计思路:
数字及运算符按钮组添加:private final String[] KEY
计算器命令键按钮组:private final String[] COMMAND
计算结果显示文本区,并将初始值设为零:JTextField RT = new JTextField(“0”);
构造方法: public Calculator()
初始化计算器方法 :private void init()
计算器菜单设计:private void Caidan()
处理事件方法:public void actionPerformed(ActionEvent e)
建立一个类,为菜单项“关于计算器(A)”添加说明;
class Shuoming extends JFrame
二、计算器界面及功能说明:
1、计算器的主界面:
计算器的界面用到了BorderLayout布局管理和GridLayout布局管理。计算机的总体布局是BorderLayout布局管理,边布局的北边放置了一个单行文本编辑框,用于显示数字及计算结果;边布局的中间放置了面板1;边布局的西边放置了面板2。程序代码如下:
getContentPane().setLayout(new BorderLayout(3, 5));
getContentPane().add("North", RT);
getContentPane().add("Center", jp1);
getContentPane().add("West", jp2);
其中,面板1使用了四行五列的GridLayout布局管理,用于放置计算器上数字及运算符建的按钮组,即keys[i],按钮组的背景颜色设置为蓝色,并且在此处的第7行代码是为该按钮组添加动作事件监听器,程序代码如下:
JPanel jp1 = new JPanel();
jp1.setLayout(new GridLayout(4, 5, 3, 3));
for (int i = 0; i < KEY.length; i++) {
keys[i] = new JButton(KEY[i]);
jp1.add(keys[i]);
keys[i].setForeground(Color.blue);
keys[i].addActionListener(this);
}
面板2使用了五行一列的GridLayout布局管理,用于放置计算器上命令建的按钮组,即comands[i],按钮组的背景颜色设置为绿色,并且在此处的第7行代码是为该按钮组添加动作事件监听器,程序代码如下:
JPanel jp2 = new JPanel();
jp2.setLayout(new GridLayout(5, 1, 3, 3));
for (int i = 0; i < COMMAND.length; i++) {
commands[i] = new JButton(COMMAND[i]);
jp2.add(commands[i]);
commands[i].setForeground(Color.green);
commands[i].addActionListener(this);
}
计算器还添加了菜单,有MenuBar菜单栏、Menu菜单和MenuItem菜单项,主要是m1编辑和m2帮助菜单,编辑菜单中添加了"复制© Ctrl+C "和"粘贴(V) Ctrl+V "菜单项,帮助菜单中添加了“帮助主题(H)”和“关于计算器(A)”菜单项,用Caidan类实现添加菜单,其中mb是指MenuBar菜单栏对象,此处代码第8行是为mi4“帮助主题(H)”菜单项添加动作事件监听器,程序代码如下:
private void Caidan() {
Menu m1 = new Menu("编辑(E)");
Menu m2 = new Menu("帮助(H)");
MenuItem mi1 = new MenuItem("复制(C) Ctrl+C ");
MenuItem mi2 = new MenuItem("粘贴(V) Ctrl+v ");
MenuItem mi3 = new MenuItem("帮助主题(H) ");
MenuItem mi4 = new MenuItem("关于计算器(A) ");
mi4.addActionListener(this);
mb.add(m1);
mb.add(m2);
m1.add(mi1);
m1.add(mi2);
m2.add(mi3);
m2.add(mi4);
}
计算器界面如下图:
2、计算器功能:
该计算器的功能是进行简单的加减乘除、求平方根、百分比、求倒数及正负数转换等运算。除数字的输入为直接输入外,运算符如:+、-、*、/、开平方等要求计算时通过内部较为复杂的运算将结果显示在文本编辑框上。
(1)对按钮组数字及运算符建的按钮组,即keys[i]的事件处理:
RT.setText(key)文本获取第一个数;输入小数点时,判断之前没有小数点,才能将小数点附在结果文本框的后面。代码如下:
private void handleNumber(String key) {
if (firstDigit) {
RT.setText(key); // 输入的第一个数字
}
else if((key.equals("."))&&(RT.getText().indexOf(".")< 0)) {
RT.setText(RT.getText() + "."); // 输入的是小数点,并且之前没有小数点,则将小数点附在结果文本框的后面
} else if (!key.equals(".")) {
RT.setText(RT.getText() + key);// 如果输入的不是小数点,则将数字附在结果文本框的后面
}
firstDigit = false; // 以后输入的肯定不是第一个数字了
}
(2)除法运算的实现:
if (operator.equals("/")) {
if (getNumberFromText() == 0.0)
{
operateValidFlag = false;
RT.setText("除数不能为零");
} else {
z /= getNumberFromText();
}
}
如果按操作符“/”按钮,再一次进行判断,如果除数为零,则判断操作不合法(false),此时文本框中显示“除数不能为零”;否则除数不为零,则进行除法运算;要进行连除运算且除数不为零时,这个算法是先保存计算结果,然后再与下一个数进行除法运算,z中保存最终计算结果,在文本框中显示出来。
(3)倒数运算的实现与处罚运算类同。
(4)加法运算的实现:
else if (operator.equals("+")) {
z += getNumberFromText();
}
如果按操作符“+”按钮,文本框中获取到的数字就做加法运算,并将计算结果保存到z中,这里的z表示中间计算结果;要进行连加运算时,这个算法是先保存计算结果,然后再与下一个数相加,z中保存最终计算结果,在文本框中显示出来。
(5)减法和乘法运算的原理与加法运算类同。
(6)其他运算符,sqrt、%、+/-运算的实现:按了对应操作符按钮时,文本框中获取到的数字直接进行相关运算,并将结果保存到z中,在文本框中显示出来。
(7)计算器Backspace键的功能:实现退格,即文本框中输入的字符总长度大于零时,按一次Backspace按钮,就将文本中最后一个字符去掉,字符总长度为零时,则文本框中显示数字“0”。
(8)计算器C键的功能:实现清除,即文本框中的字符不为零时,按一次C按钮,就将文本中的字符全部清零,当前文本显示结果为数字“0”。
(9)对菜单项“关于计算器(A)”添加事件监听,又加了一个说明小窗口,整体布局用了BorderLayout布局管理,其中间放置了一个面板,该面板采用四行一列的GridLayout布局管理,上面放置了两个标签,两个文本区;标签分别是“版本号”和“时间”的标签,两个文本区用来显示版本号和时间,这里的时间是指本次课程设计计算器的真正完成时间。附加的小窗口运行界面如下:
三、总结:
通过本次课程设计,对所学的java知识得到了巩固与应用,对java有了更进一步的认识与了解,不过设计过程中也遇到了很多问题。
首先,一开始写计算器界面时,各种组件是怎么加也加不上去,看似程序没啥问题,就是加不上面板、按钮等等,后来在同学的帮助下,我们的一起努力下,发现整体布局添加不正确,才导致加不上组件。
其次,计算器的功能实现时,对各组件添加完动作事件监听之后,对于计算器的各种运算如何正确实现,怎么写也实现不了,只好上百度查阅、借鉴,与同学相互交流,才得以实现计算器的各种运算功能。还有一个缺陷,菜单栏中虽然设计了“编辑—复制© Ctrl+C 、粘贴(V) Ctrl+V ”以及“帮助—帮助主题(H)、关于计算器(A)”,但是功能只实现了“关于计算器(A)”,其他的没有实现功能。还有存在的问题是,在关闭菜单项上附加的窗口时,计算器窗口同时被关闭,我没有想到问题的根源,问了老师后发现是源于下面这行代码
sm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
也就是关闭当前窗口时,整个系统都关闭。
总之,通过本次课程设计,进一步掌握了java程序编辑器、图形界面以及文件操作的实现;和同学之间的相互讨论也使我受益匪浅,深受启发;同时也深刻体会到学习Java更是要拓展知识面、拓展思维。但仍有不足之处,在解决实际问题上,还是缺乏思考。
完整源码如下:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Calculator extends JFrame implements ActionListener {
private final String[] KEY = { "7", "8", "9", "/", "sqrt", "4", "5", "6", "*", "%", "1", "2", "3", "-", "1/x", "0",
"+/-", ".", "+", "=" };
private final String[] COMMAND = { "Backspace", "CE", "C", "(", ")" };
JButton keys[] = new JButton[KEY.length];
JButton commands[] = new JButton[COMMAND.length];
MenuBar mb;
JTextField RT = new JTextField("0");
private boolean firstDigit = true;// 标志用户按的是否是整个表达式的第一个数字,或者是运算符后的第一个数字
private double z = 0.0; // 计算的中间结果。
private String operator = "="; // 当前运算的运算符
private boolean operateValidFlag = true; // 操作是否合法
public Calculator() {
init();
this.setBackground(Color.LIGHT_GRAY);
this.setTitle("计算器");
this.setLocation(400, 300);
mb = new MenuBar();
setMenuBar(mb);
this.setResizable(true);
Caidan();
this.pack(); // 计算器中各组件大小
}
private void init() {
RT.setHorizontalAlignment(JTextField.CENTER);
RT.setEditable(false);
RT.setBackground(Color.WHITE);
JPanel jp1 = new JPanel();
jp1.setLayout(new GridLayout(4, 5, 3, 3));
for (int i = 0; i < KEY.length; i++) {
keys[i] = new JButton(KEY[i]);
jp1.add(keys[i]);
keys[i].setForeground(Color.blue);
keys[i].addActionListener(this);
}
JPanel jp2 = new JPanel();
jp2.setLayout(new GridLayout(5, 1, 3, 3));
for (int i = 0; i < COMMAND.length; i++) {
commands[i] = new JButton(COMMAND[i]);
jp2.add(commands[i]);
commands[i].setForeground(Color.green);
commands[i].addActionListener(this);
}
getContentPane().setLayout(new BorderLayout(3, 5));
getContentPane().add("North", RT);
getContentPane().add("Center", jp1);
getContentPane().add("West", jp2);
}
private void Caidan() {
// TODO 自动生成的方法存根
Menu m1 = new Menu("编辑(E)");
Menu m2 = new Menu("帮助(H)");
MenuItem mi1 = new MenuItem("复制(C) Ctrl+C ");
MenuItem mi2 = new MenuItem("粘贴(V) Ctrl+v ");
MenuItem mi3 = new MenuItem("帮助主题(H) ");
MenuItem mi4 = new MenuItem("关于计算器(A) ");
mi4.addActionListener(this);
mb.add(m1);
mb.add(m2);
m1.add(mi1);
m1.add(mi2);
m2.add(mi3);
m2.add(mi4);
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
String label = e.getActionCommand();
if (label.equals(COMMAND[0])) {
handleBackspace(); // 按"Backspace"键
}
else if (label.equals(COMMAND[1])) {
RT.setText("0"); // 按"CE"键
}
else if (label.equals(COMMAND[2])) {
handleC(); // 按"C"键
}
else if ("0123456789.".indexOf(label) >= 0) {
handleNumber(label); // 按数字键或者小数点键
}
else if(label.equals("关于计算器(A) ")){
Shuoming sm=new Shuoming();
sm.setVisible(true);
//sm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
else {
handleOperator(label); // 按运算符键
}
}
private void handleBackspace() // 退格
{
String text = RT.getText();
int i = text.length();
if (i > 0) {
text = text.substring(0, i - 1); // 将文本最后一个字符去掉
if (text.length() == 0) {
RT.setText("0"); // 如果文本没有了内容,则初始化计算器的各种值
firstDigit = true;
operator = "=";
}
else {
RT.setText(text); // 显示新的文本
}
}
}
private void handleC() {
RT.setText("0"); // 初始化计算器的各种值
firstDigit = true;
operator = "=";
}
private void handleNumber(String key) {
if (firstDigit) {
RT.setText(key); // 输入的第一个数字
} else if ((key.equals(".")) && (RT.getText().indexOf(".") < 0)) {
RT.setText(RT.getText() + "."); // 输入的是小数点,并且之前没有小数点,则将小数点附在结果文本框的后面
} else if (!key.equals(".")) {
RT.setText(RT.getText() + key);// 如果输入的不是小数点,则将数字附在结果文本框的后面
}
firstDigit = false; // 以后输入的肯定不是第一个数字了
}
private void handleOperator(String key) {
if (operator.equals("/")) {
if (getNumberFromText() == 0.0) // 如果当前结果文本框中的值等于0
{
operateValidFlag = false;
RT.setText("除数不能为零");
} else {
z /= getNumberFromText();
}
}
else if (operator.equals("1/x")) {
if (z == 0.0) {
operateValidFlag = false;
RT.setText("零没有倒数");
}
else {
z = 1 / z;
}
}
else if (operator.equals("+")) {
z += getNumberFromText();
}
else if (operator.equals("-")) {
z -= getNumberFromText();
}
else if (operator.equals("*")) {
z *= getNumberFromText();
}
else if (operator.equals("sqrt")) {
z = Math.sqrt(z);
}
else if (operator.equals("%")) {
z = z / 100;
}
else if (operator.equals("+/-")) { // 正负数
z = z * (-1);
}
else if (operator.equals("=")) { // 赋值
z = getNumberFromText();
}
if (operateValidFlag) {
// 双精度浮点数的运算
long t1;
double t2;
t1 = (long) z;
t2 = z - t1;
if (t2 == 0) {
RT.setText(String.valueOf(t1));
} else {
RT.setText(String.valueOf(z));
}
}
// 运算符等于用户按的按钮
operator = key;
firstDigit = true;
operateValidFlag = true;
}
private double getNumberFromText() {
double result = 0;
try {
result = Double.valueOf(RT.getText()).doubleValue();
} catch (NumberFormatException e) {
}
return result;
} // 从结果文本框中获取数字
public static void main(String args[]) {
Calculator cal = new Calculator();
cal.setVisible(true);
cal.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class Shuoming extends JFrame {
JPanel jp=new JPanel();
JTextArea text1=new JTextArea("20.1705.1301.1");
JTextArea text2=new JTextArea("2017.11.19");
JLabel b1=new JLabel("版本号:");
JLabel b2=new JLabel("时间");
public Shuoming(){
this.setBackground(Color.LIGHT_GRAY);
this.setTitle("说明");
this.setBounds(300,200,300,200);
getContentPane().setLayout(new BorderLayout(3, 5));
getContentPane().add("Center", jp);
jp.setLayout(new GridLayout(4, 1, 3, 3));
jp.add(b1);
jp.add(text1);
jp.add(b2);
jp.add(text2);
}
}