今天我们来学习做一个桌面的简单计算器。之所以说简单,是因为能完成的运算简单,只有加减乘除四则运算,远远不能跟那些功能完备的科学计算器相比。而且其中实现的思路也很简单。
关键词:java计算器,简单计算器,java程序设计,设置监听器。
前期需要:IDE ,javafx包
思路:分为两个方面,第一是计算器的界面怎么做,需要什么元素、控件。第二是对运算的实现。
1、首先来分析一下计算器的基本界面,完成四则运算,基本上就是0~9十个按钮、一个小数点、一个等号、四个加减乘除按钮,还有一个显示文本的Text。大概就长这个样子:
这个布局首先是一个上下结构,上面是一个text文本框,下面是各种按钮,所以我们可以用一个VBox把text放上面,把下面的其他组件放下面。而下面是一个4*4的矩阵,矩阵里放着4*4个按钮(Button)。所以下面的按钮需要一个矩阵来装,这就要用到GridPane,大家可以去稍微看看这个布局管理器,主要是按照按照网格状进行布局。
GridPane的使用方法大概是这样:
gridpane = new GridPane();
gridpane.add(bt_4, 0,1); // 对其添加元素,第一个参数是控件,或者是其他东西,第二三个是其所在的竖直,水平位置。
需要注意的是,add的时候必须从0,0开始一直到n,n 。不能从中间 或者末尾开始,即n,n 到0,0
ok,布局的分析大概到这里,来数一下,大概就是用一个text,一个GridPane,一个VBox,还有4*4个Button。将button放进gridpane里,将text,gridpane放进vbox里。
2、接下来我们来分析一下运算怎么搞,大家可以先想想平时我们算四则运算需要什么,他们出现的先后顺序。没错,我们需要知道第一个数,然后一个操作,然后第二个数,最后只要点击了等号就会出现结果。所以我们需要几个串:firstInput,secondInput,ansOutput。同时我们需要判断一下当前是第一个还是第二个串输入,所以需要一个isSecond(boolean),最后需要一个operation(char)来记录选中的操作。
模拟一下:输入第一个串(点击一下数字在串的末尾加一个数),点击操作(点一下记录一下当前操作,把标志改为第二个串),输入第二个串,点击等号出结果(两个串转为double类型进行运算装在ansS(String)里再更新text内容)。
//--------------------------------------------------------------------------------------------------------------------------------
以上为大体分析,接下来对界面进行布置。
1、新建一个工程,创建包,再建一个.java文件
2、继承Application
然后大概是这样的:
import javafx.application.*;
import javafx.stage.Stage;
public class test2 extends Application{
public static void main(String[] args){
}
@Override
public void start(Stage arg0) throws Exception {
// TODO Auto-generated method stub
}
}
3、将所有布局空间都声明出来:
import javafx.application.*;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class test2 extends Application{
public HBox hbox ;
public VBox vbox ;
public TextField tfAns;
public GridPane gridpane;
//---------------------------------
//----------Buttons----------------
public Button bt_add;
public Button bt_sub;
public Button bt_mul;
public Button bt_div;
public Button bt_ans;
public Button bt_0;
public Button bt_1;
public Button bt_2;
public Button bt_3;
public Button bt_4;
public Button bt_5;
public Button bt_6;
public Button bt_7;
public Button bt_8;
public Button bt_9;
public Button bt_dot;
public Scene scene ;
//记录scene的宽高
public double Height;
public double Width;
public static void main(String[] args){
}
@Override
public void start(Stage arg0) throws Exception {
}
}
3、接下来对控件进行绑定,这里我们用两个函数(initBundles(); initGridPane();)绑定,这样好让结构清晰一点:
import javafx.application.*;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class test2 extends Application{
public HBox hbox ;
public VBox vbox ;
public TextField tfAns;
public GridPane gridpane;
//---------------------------------
//----------Buttons----------------
public Button bt_add;
public Button bt_sub;
public Button bt_mul;
public Button bt_div;
public Button bt_ans;
public Button bt_0;
public Button bt_1;
public Button bt_2;
public Button bt_3;
public Button bt_4;
public Button bt_5;
public Button bt_6;
public Button bt_7;
public Button bt_8;
public Button bt_9;
public Button bt_dot;
public Scene scene ;
//记录scene的宽高
public double Height;
public double Width;
public static void main(String[] args){
Application.launch(args);
}
@Override
public void start(Stage arg0) throws Exception {
initBundles();
initGridPane();
//----------------------------------------
scene = new Scene(vbox,330,350);
arg0.setTitle("Calculator!");
arg0.setScene(scene);
arg0.show();
}
public void initBundles() {
tfAns = new TextField();
//禁止text可编辑 然后对button设置监听器
//这个TextField没有右对齐,需要右对齐的话改用 JTextField (javax.swing.JTextField)
tfAns.setEditable(false);
tfAns.setText("0");
//------------------------------------
hbox = new HBox();
gridpane = new GridPane();
//这两个方法可以设置gridpane里面的元素间的间隙,Vgap是垂直方向,Hgap是竖直方向
//gridpane.setHgap(4);
//gridpane.setVgap(4);
vbox = new VBox(tfAns,gridpane);
//------------------------------------
//---------for button-----------------
bt_add = new Button("+");
bt_sub = new Button("-");
bt_mul = new Button("*");
bt_div = new Button("/");
bt_0 = new Button("0");
bt_1 = new Button("1");
bt_2 = new Button("2");
bt_3 = new Button("3");
bt_4 = new Button("4");
bt_5 = new Button("5");
bt_6 = new Button("6");
bt_7 = new Button("7");
bt_8 = new Button("8");
bt_9 = new Button("9");
bt_dot = new Button(".");
//所有的button一定要new出来,我看了半个钟的exception才找出来,eclipse的检查还是很粗糙的,大家写的时候一定要考虑周全
bt_ans = new Button("=");
}
public void initGridPane() {
gridpane.add(bt_1, 0,0);
gridpane.add(bt_2, 1,0);
gridpane.add(bt_3, 2,0);
gridpane.add(bt_add, 3,0);
//-------------------------
gridpane.add(bt_4, 0,1);
gridpane.add(bt_5, 1,1);
gridpane.add(bt_6, 2,1);
gridpane.add(bt_sub, 3,1);
//-------------------------
gridpane.add(bt_7, 0,2);
gridpane.add(bt_8, 1,2);
gridpane.add(bt_9, 2,2);
gridpane.add(bt_mul, 3,2);
//-------------------------
gridpane.add(bt_0, 0,3);
gridpane.add(bt_dot, 1,3);
gridpane.add(bt_ans, 2,3);
gridpane.add(bt_div, 3,3);
//-------------------------
}
}
4、初步效果是这样的,接下来我们要把按钮的大小设置一下,这时就要用到上面声明的宽高两个东西了:
@Override
public void start(Stage arg0) throws Exception {
initBundles();
initGridPane();
//----------------------------------------
scene = new Scene(vbox,330,350);
//一定要在scene之后,因为函数内需要用到scene的宽高参数,如果放在之前会出现异常,大家可以试一下。
initBTSize();
arg0.setTitle("Calculator!");
arg0.setScene(scene);
arg0.show();
}
为防止有占用篇幅的嫌疑,下面我一部分一部分的贴。
/**
* 该函数用于设置button的大小
* 思路是从scene里拿到舞台的宽高,然后平分赋值给bt
*/
public void initBTSize() {
Height = scene.getHeight();
Width = scene.getWidth();
bt_add.setMinSize(Width/4, Width/4);
bt_sub.setMinSize(Width/4, Width/4);
bt_mul.setMinSize(Width/4, Width/4);
bt_div.setMinSize(Width/4, Width/4);
bt_0.setMinSize(Width/4, Width/4);
bt_1.setMinSize(Width/4, Width/4);
bt_2.setMinSize(Width/4, Width/4);
bt_3.setMinSize(Width/4, Width/4);
bt_4.setMinSize(Width/4, Width/4);
bt_5.setMinSize(Width/4, Width/4);
bt_6.setMinSize(Width/4, Width/4);
bt_7.setMinSize(Width/4, Width/4);
bt_8.setMinSize(Width/4, Width/4);
bt_9.setMinSize(Width/4, Width/4);
bt_dot.setMinSize(Width/4, Width/4);
bt_ans.setMinSize(Width/4, Width/4);
}
效果:
到此为止,界面布局已经搞好了,还是蛮简单的,接下来就是内部运算的问题了。
//--------------------------------------------------------------------------------------------------------------------------------
布局做好了,是不是就要对按钮进行监听器设置了呢?对的,下面我们写一个函数统一对几个按钮设置监听器。
1、在这之前,我们需要声明好上面说的几个关于运算的变量:
//--------for textfield-------
String firstInput = "";
String secondInput = "";
String ansOutput = "";
boolean isSecond;
char operations;
2、用一个函数统一对按钮设置监听器,先给数字:
public void initListener() {
//-----for number buttons-------------
bt_0.setOnAction(e->{
if(!isSecond) {
firstInput+="0";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="0";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_1.setOnAction(e->{
if(!isSecond) {
firstInput+="1";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="1";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_2.setOnAction(e->{
if(!isSecond) {
firstInput+="2";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="2";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_3.setOnAction(e->{
if(!isSecond) {
firstInput+="3";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="3";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_4.setOnAction(e->{
if(!isSecond) {
firstInput+="4";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="4";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_5.setOnAction(e->{
if(!isSecond) {
firstInput+="5";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="5";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_6.setOnAction(e->{
if(!isSecond) {
firstInput+="6";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="6";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_7.setOnAction(e->{
if(!isSecond) {
firstInput+="7";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="7";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_8.setOnAction(e->{
if(!isSecond) {
firstInput+="8";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="8";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_9.setOnAction(e->{
if(!isSecond) {
firstInput+="9";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="9";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_dot.setOnAction(e->{
if(!isSecond) {
firstInput+=".";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+=".";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
//------------------------------------}
设置数字的监听器很简单,思路是判断选择的是第一个串还是第二个串,然后对对应的串进行追加数字。
记得在start里面调用函数,效果:
还是在这个函数里,对四则运算加监听器:
//-------for operations---------------
bt_add.setOnAction(e->{
if(!isSecond) {
isSecond = true;
ansOutput += "+";
operations = '+';
}
});
bt_sub.setOnAction(e->{
if(!isSecond) {
isSecond = true;
ansOutput += "-";
operations = '-';
}
});
bt_mul.setOnAction(e->{
if(!isSecond) {
isSecond = true;
ansOutput += "*";
operations = '*';
}
});
bt_div.setOnAction(e->{
if(!isSecond) {
isSecond = true;
ansOutput += "/";
operations = '/';
}
});
这里注意,标志的变化,还有对操作的赋值。完成这步操作之后就已经完成了对两个串,一个操作数的安排了。接下来只需要一个等号就可以输出结果了。
//-------for ansString--------------
bt_ans.setOnAction(e->{
//将两个串转成double类型 然后根据不同的operations进行运算
double firstS = Double.parseDouble(firstInput);
double secondS = Double.parseDouble(secondInput);
double ansS = 0.0f;
if(operations == '+') {
ansS = firstS+secondS;
}else if (operations == '-') {
ansS = firstS - secondS;
}else if (operations == '*') {
ansS = firstS * secondS;
}else if (operations == '/') {
ansS = firstS / secondS;
}
//将ansS转串对tfAns赋值 则完成对结果的显示
tfAns.setText(ansS+"");
//完成操作后还要对isSecond标志进行初始化即变为false
//这里可以再改进一下,将上次的结果变为first串,这样就不用改标志isSecond,但是要加一个ClearButton来清零,表示运算重新开始
isSecond = false;
//对两个串进行清零,不然下一个操作的时候会错误
firstInput = "";secondInput = "";
});
简单来说,这个监听器就是把两个串转double,运算,然后结果转String再贴到tfAns。
//--------------------------------------------------------------------------------------------------------------------------------
好啦,一个完整的简单计算器已经出来了,能够实现两数字的四则运算。
但是这里还有许多bug,比如说text的对其方式是左对齐,如何才能让他右对齐?添加运算的时候运算操作并不会显示在text里,如何让两个串完完整整的显示出来如:255*255这样子?如果用户误点击多次操作,比如255*-+/+255,他们最后做的运算是怎么样?
这些bug在这没有修改,希望有兴趣的同学可以自己琢磨修改一下。
下面我给大家贴一下整个.java文件,里面有很多注释在博客中没有点到,大家可以看看。
//--------------------------------------------------------------------------------------------------------------------------------
import javafx.application.*;
import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.geometry.*;
/**
* 为了尽量让结构清晰,这个.java用来负责界面的渲染
*
* @author Frankie To
*
* 计算器总体的结构为上下结构,上面是一个显示文本的Text,下面是一个Pane,所以我们可以用一个VBox来吧两个东西装进去
* 下半部分因为是4*4结构,所以可以用GridPane并且把Button一个个都new出来 因为不只是做一个UI
* 界面,我们要把button全都new出来做运算
*
*
* =.= 这里被打脸了,这次是赶上学校要交一个计算器的UI的程序,所以想做一个功能基本能实现的简单计算器出来。
* 因为很少用eclipse,不清楚怎么对文件进行拆分,所以只能将所有东西放在一个.java里。正常工程里应该遵循软件工程的低耦合高聚合的理念来做
* 不过在这个工程里,也有一点点这种思想的体现,对不同模块的功能,都抽出来尽量做成一个方法或者类。
* 在以后的实战中这样的代码方便维护和理解。
*/
public class ScaleView extends Application {
public HBox hbox ;
public VBox vbox ;
public TextField tfAns;
public GridPane gridpane;
//---------------------------------
//----------Buttons----------------
public Button bt_add;
public Button bt_sub;
public Button bt_mul;
public Button bt_div;
public Button bt_ans;
public Button bt_0;
public Button bt_1;
public Button bt_2;
public Button bt_3;
public Button bt_4;
public Button bt_5;
public Button bt_6;
public Button bt_7;
public Button bt_8;
public Button bt_9;
public Button bt_dot;
public Scene scene ;
//记录scene的宽高
public double Height;
public double Width;
//----------------------------
//--------for textfield-------
String firstInput = "";
String secondInput = "";
String ansOutput = "";
boolean isSecond;
char operations;
//这几个变量主要是用来文本的输入输出的
//输入数分为第一个输入,第二个输入,所以夙瑶两个串来存,然后用一个串ans来更新
//用一个boolean 变量来记录是否是第二哥输入数,如果是第二个输入的数,则将第一个串跟第二个串变为整形计算输出到ans
//----------------------------
//---------------------------------
@Override
public void start(Stage arg0) throws Exception {
//用一个函数initBundles()来对基本控件进行初始化
//结构上更加清晰
initBundles();
initGridPane();
//----------------------------------------
scene = new Scene(vbox,330,350);
initBTSize();
initListener();
isSecond = false;
arg0.setTitle("Calculator!");
arg0.setScene(scene);
arg0.show();
}
public void initListener() {
//-----for number buttons-------------
bt_0.setOnAction(e->{
if(!isSecond) {
firstInput+="0";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="0";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_1.setOnAction(e->{
if(!isSecond) {
firstInput+="1";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="1";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_2.setOnAction(e->{
if(!isSecond) {
firstInput+="2";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="2";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_3.setOnAction(e->{
if(!isSecond) {
firstInput+="3";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="3";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_4.setOnAction(e->{
if(!isSecond) {
firstInput+="4";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="4";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_5.setOnAction(e->{
if(!isSecond) {
firstInput+="5";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="5";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_6.setOnAction(e->{
if(!isSecond) {
firstInput+="6";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="6";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_7.setOnAction(e->{
if(!isSecond) {
firstInput+="7";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="7";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_8.setOnAction(e->{
if(!isSecond) {
firstInput+="8";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="8";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_9.setOnAction(e->{
if(!isSecond) {
firstInput+="9";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+="9";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
bt_dot.setOnAction(e->{
if(!isSecond) {
firstInput+=".";
ansOutput = firstInput;
tfAns.setText(ansOutput);
}else {
secondInput+=".";
ansOutput = secondInput;
tfAns.setText(secondInput);
}
});
//------------------------------------
//-------for operations---------------
bt_add.setOnAction(e->{
if(!isSecond) {
isSecond = true;
ansOutput += "+";
operations = '+';
}
});
bt_sub.setOnAction(e->{
if(!isSecond) {
isSecond = true;
ansOutput += "-";
operations = '-';
}
});
bt_mul.setOnAction(e->{
if(!isSecond) {
isSecond = true;
ansOutput += "*";
operations = '*';
}
});
bt_div.setOnAction(e->{
if(!isSecond) {
isSecond = true;
ansOutput += "/";
operations = '/';
}
});
//-------for ansString--------------
bt_ans.setOnAction(e->{
//将两个串转成double类型 然后根据不同的operations进行运算
double firstS = Double.parseDouble(firstInput);
double secondS = Double.parseDouble(secondInput);
double ansS = 0.0f;
if(operations == '+') {
ansS = firstS+secondS;
}else if (operations == '-') {
ansS = firstS - secondS;
}else if (operations == '*') {
ansS = firstS * secondS;
}else if (operations == '/') {
ansS = firstS / secondS;
}
//将ansS转串对tfAns赋值 则完成对结果的显示
tfAns.setText(ansS+"");
//完成操作后还要对isSecond标志进行初始化即变为false
//这里可以再改进一下,将上次的结果变为first串,这样就不用改标志isSecond,但是要加一个ClearButton来清零,表示运算重新开始
isSecond = false;
//对两个串进行清零,不然下一个操作的时候会错误
firstInput = "";secondInput = "";
});
}
/**
* 该函数用于设置button的大小
* 思路是从scene里拿到舞台的宽高,然后平分赋值给bt
*/
public void initBTSize() {
Height = scene.getHeight();
Width = scene.getWidth();
bt_add.setMinSize(Width/4, Width/4);
bt_sub.setMinSize(Width/4, Width/4);
bt_mul.setMinSize(Width/4, Width/4);
bt_div.setMinSize(Width/4, Width/4);
bt_0.setMinSize(Width/4, Width/4);
bt_1.setMinSize(Width/4, Width/4);
bt_2.setMinSize(Width/4, Width/4);
bt_3.setMinSize(Width/4, Width/4);
bt_4.setMinSize(Width/4, Width/4);
bt_5.setMinSize(Width/4, Width/4);
bt_6.setMinSize(Width/4, Width/4);
bt_7.setMinSize(Width/4, Width/4);
bt_8.setMinSize(Width/4, Width/4);
bt_9.setMinSize(Width/4, Width/4);
bt_dot.setMinSize(Width/4, Width/4);
bt_ans.setMinSize(Width/4, Width/4);
}
public void initBundles() {
tfAns = new TextField();
//禁止text可编辑 然后对button设置监听器
//这个TextField没有右对齐,需要右对齐的话改用 JTextField (javax.swing.JTextField)
tfAns.setEditable(false);
tfAns.setText("0");
//------------------------------------
hbox = new HBox();
gridpane = new GridPane();
//这两个方法可以设置gridpane里面的元素间的间隙,Vgap是垂直方向,Hgap是竖直方向
//gridpane.setHgap(4);
//gridpane.setVgap(4);
vbox = new VBox(tfAns,gridpane);
//------------------------------------
//---------for button-----------------
bt_add = new Button("+");
bt_sub = new Button("-");
bt_mul = new Button("*");
bt_div = new Button("/");
bt_0 = new Button("0");
bt_1 = new Button("1");
bt_2 = new Button("2");
bt_3 = new Button("3");
bt_4 = new Button("4");
bt_5 = new Button("5");
bt_6 = new Button("6");
bt_7 = new Button("7");
bt_8 = new Button("8");
bt_9 = new Button("9");
bt_dot = new Button(".");
//所有的button一定要new出来,我看了半个钟的exception才找出来,eclipse的检查还是很粗糙的,大家写的时候一定要考虑周全
bt_ans = new Button("=");
}
public void initGridPane() {
gridpane.add(bt_1, 0,0);
gridpane.add(bt_2, 1,0);
gridpane.add(bt_3, 2,0);
gridpane.add(bt_add, 3,0);
//-------------------------
gridpane.add(bt_4, 0,1);
gridpane.add(bt_5, 1,1);
gridpane.add(bt_6, 2,1);
gridpane.add(bt_sub, 3,1);
//-------------------------
gridpane.add(bt_7, 0,2);
gridpane.add(bt_8, 1,2);
gridpane.add(bt_9, 2,2);
gridpane.add(bt_mul, 3,2);
//-------------------------
gridpane.add(bt_0, 0,3);
gridpane.add(bt_dot, 1,3);
gridpane.add(bt_ans, 2,3);
gridpane.add(bt_div, 3,3);
//-------------------------
}
public static void main(String[] args) {
Application.launch(args);
}
}
江湖再见!