代码未优化版下载:点我下载全部代码
1、环境
- jdk1.8
- JavaFX Scene Builder 2.0
- idea
2、需求
- 实现四则运算:加减乘除
- 两数运算
- 良好界面
最终实现以下效果
3 使用JavaFX?
javafx是swing的升级换代产品,用过swing的可能知道,我们不管是写页面的代码还是写具体功能的代码都是放在同一个类中,这就导致了一个类的负担过重,它既需要处理页面,也需要进行具体业务的处理。
诚然你现在感受不出这样有什么弊端,在业务简单的情况下,如此实现效率会高很多,但是,开发一时爽,维护火葬场。我们试想一个场景,你的是完成了这个计算器功能,页面和业务都在同一个类中,你的代码有500行。假设你的页面代码是250行,业务代码是250行。
这时候你有一个很小的需求,要你改一个按钮的颜色,这时候,由于的页面代码和你的业务代码混杂在一起,这时候你需要在500行代码中去寻找有关这行代码的模块。
但是假如我们的页面和业务是分开的,你要修改按钮的颜色,那就去页面代码里找对应的模块就可以了,这时候你只需要找250行代码,维护的效率就提升了一倍!
这其实就是我们所说的MVC架构
- Model 模型
- View 视图
- Controller 控制器
大家分工明确,页面的显示是视图层的事,页面得到的数据传给控制器,控制器决定去调用哪个模型去进行计算。
言归正传,为什么要说MVC呢,因为javaFX就是MVC架构!如果不理解,还是和swing一样,那么javafx出现就没有意义了。
4、使用Java FX
4.1下载安装
-
官网下载
下载的时候会让你登录Oracle账号,如果没有,注册一个即可。 -
双击无脑安装
4.2在eclipse中使用
如果你习惯于使用eclipse,可以根据这里设置。
jdk7后就内置了javafx,但是在eclipse中我们并不能直接使用,参考这里进行配置
除此之外,要使用eclipse创建javafx项目,我们还需要安装一个插件:参考这里安装
4.3在idea中使用
在idea中就不必这么麻烦了,但是为了方便,我们需要配置scene builder的路径1
选择设置Settings
搜索javafx的配置
点击应用Apply,点击OK
5、创建项目
ok,我们正式开始,新建项目
创建javafx项目,然后点击下一步
项目名为Calculator
,我们看到默认会帮我们生成以下项目结构。
6、 计算器类
- 删除sample这个包,以及它下面的所有东西
- 创建包名
cn.butcher
(不是必须的哈)
我们只需要实现两数的四则运算,根据Java面向对象的思维,计算器是一个对象,它里面可以存两个数,有四个方法加减乘除,那么我们可以得出以下:
package cn.butcher;
/**
*
* 计算器类
* 包含第一个操作数(num1)、第二个操作数(num2)、运算符(operator)三个属性
* 以及对应得set、get方法
* 以及四则运算中加减乘除四个方法
*
*/
public class Calculator {
// 操作数1
private int num1;
// 操作数2
private int num2;
// 运算符赋初始值
private String operator="";
// alt+insert 自动生成代码
// 无参构造
public Calculator() {
}
// 有参构造
public Calculator(int num1, int num2, String operator) {
this.num1 = num1;
this.num2 = num2;
this.operator = operator;
}
/**
* 加法
* @return 结果
*/
public int add(){
return num1+num2;
}
/**
* 减法
* @return 结果
*/
public int subtract(){
return num1-num2;
}
/**
* 乘法
* @return 结果
*/
public int multiply(){
return num2*num1;
}
/**
* 除法
* @return 结果
*/
public double divide(){
// 排除0除异常
if (num2 == 0)return 0;
// 两个整数相除,除不尽会四舍五入,所以10/8 1.xxx 会舍掉后面小数,取整
// java向上转型
return num1/(num2*1.0);
}
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
public String getOperator() {
return operator;
}
public void setOperator(String operator) {
this.operator = operator;
}
}
测试,创建一个Test类
package cn.butcher;
public class Test {
public static void main(String[] args) {
Calculator calculator = new Calculator();
calculator.setNum1(99);
calculator.setNum2(3);
System.out.println(calculator.getNum1()+"+"+calculator.getNum2()+"="+calculator.add());
System.out.println(calculator.getNum1()+"-"+calculator.getNum2()+"="+calculator.subtract());
System.out.println(calculator.getNum1()+"x"+calculator.getNum2()+"="+calculator.multiply());
System.out.println(calculator.getNum1()+"÷"+calculator.getNum2()+"="+calculator.divide());
}
}
结果如下:
确定没问题
7、第一个窗体实现
- 创建CalController控制器
package cn.butcher;
/**
* 计算器控制器
*/
public class CalController {
}
- 创建场景视图calView.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<Vbox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="cn.butcher.CalController"
prefHeight="400.0" prefWidth="600.0">
</Vbox>
注意,需要在Vbox
这个标签中使用fx:controller="cn.butcher.CalController"
绑定我们的控制器,控制器需要写全类名
- 创建程序主入口Main
package cn.butcher;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
* 程序主入口
*/
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
// 加载场景视图
Parent parent = (Parent) FXMLLoader.load(getClass().getResource("calView.fxml"));
// 创建场景,宽度为600像素,高度为400像素
Scene scene = new Scene(parent,600, 400);
// 标题
primaryStage.setTitle("计算器");
// 将场景放入窗体
primaryStage.setScene(scene);
// 让窗体显示
primaryStage.show();
}
public static void main(String[] args) {
// 通过源码分析,它其实是启动了一个线程
launch(args);
}
}
完事启动main方法:
8、布局
主体我们使用VBox垂直线性布局,上半部分是我们的结果区,下半部分是我们的按键区
结果区我们放一个文本域就可以了,那么在按键区,它的布局一眼看去就很符合我们的网格布局Grid也就是:
好,我们开始布局:
按下面的顺序拖入组件,调整最终效果
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cn.butcher.CalController">
<children>
<TextField fx:id="textResult" alignment="CENTER_RIGHT" prefHeight="86.0" prefWidth="600.0" style="-fx-background-radius: 10px;" text="0">
<font>
<Font size="39.0" />
</font>
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
</TextField>
<GridPane prefHeight="311.0" prefWidth="594.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Button mnemonicParsing="false" onAction="#clickNum" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #45aaf2; -fx-background-radius: 10px;" text="4" textFill="WHITE" GridPane.halignment="CENTER" GridPane.rowIndex="1">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickNum" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #45aaf2; -fx-background-radius: 10px;" text="2" textFill="WHITE" GridPane.columnIndex="1" GridPane.halignment="CENTER">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickNum" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #45aaf2; -fx-background-radius: 10px;" text="3" textFill="WHITE" GridPane.columnIndex="2" GridPane.halignment="CENTER">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickNum" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #45aaf2; -fx-background-radius: 10px;" text="5" textFill="WHITE" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickNum" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #45aaf2; -fx-background-radius: 10px;" text="1" textFill="WHITE" GridPane.halignment="CENTER">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickNum" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #45aaf2; -fx-background-radius: 10px;" text="6" textFill="WHITE" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickNum" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #45aaf2; -fx-background-radius: 10px;" text="7" textFill="WHITE" GridPane.halignment="CENTER" GridPane.rowIndex="2">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickNum" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #45aaf2; -fx-background-radius: 10px;" text="8" textFill="WHITE" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickNum" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #45aaf2; -fx-background-radius: 10px;" text="9" textFill="WHITE" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="2">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickNum" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #45aaf2; -fx-background-radius: 10px;" text="0" textFill="WHITE" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="3">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickOperator" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #2f3542; -fx-background-radius: 10px;" text="+" textFill="WHITE" GridPane.columnIndex="3" GridPane.halignment="CENTER">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickOperator" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #2f3542; -fx-background-radius: 10px;" text="-" textFill="WHITE" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="1">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickOperator" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #2f3542; -fx-background-radius: 10px;" text="x" textFill="WHITE" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="2">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickOperator" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #2f3542; -fx-background-radius: 10px;" text="÷" textFill="WHITE" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="3">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickOperator" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #2f3542; -fx-background-radius: 10px;" text="=" textFill="WHITE" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="3">
<font>
<Font size="25.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#clickReturnZero" prefHeight="48.0" prefWidth="96.0" style="-fx-background-color: #1abc9c; -fx-background-radius: 10px;" text="CE" textFill="WHITE" GridPane.halignment="CENTER" GridPane.rowIndex="3">
<font>
<Font size="25.0" />
</font>
</Button>
</children>
</GridPane>
</children>
</VBox>
9、控制器类
编写控制器之前,我们应该理一下思路,首先点击数字键,点击运算符键,设置第一个操作数的值,点击等于键,设置第二个操作数的值,并计算结果
package cn.butcher;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
/**
* 计算器控制器
*/
public class CalController {
// 创建计算器对象
Calculator calculator = new Calculator();
// 结果文本域
@FXML
private TextField textResult;
// 用于拼接数字
String realText = "";
//导包快捷键(处理一些错误) alt+enter
@FXML
void clickNum(ActionEvent event) {
// event中有一个方法getSource()可以知道具体是那个按钮对象点击的
// 强行转换为button
Button source = (Button) event.getSource();
// 获取到这个按钮对象的文本信息
String text = source.getText();
// 拼接数字
realText+=text;
// 设置到文本域让它实时显示
textResult.setText(realText);
}
@FXML
void clickOperator(ActionEvent event) {
Button source = (Button) event.getSource();
// 赋值第一个操作数
if (calculator.getNum1() ==0 && !realText.equals("")){
calculator.setNum1(Integer.parseInt(realText));
}
String text = source.getText();
// 如果是等于,就设置第二个操作数,并计算结果,设置到文本域
if (text.equals("=")){
if (!realText.equals("")){
calculator.setNum2(Integer.parseInt(realText));
}
switch (calculator.getOperator()){
case "+":
textResult.setText(String.valueOf(calculator.add()));
break;
case "-":
textResult.setText(String.valueOf(calculator.subtract()));
break;
case "x":
textResult.setText(String.valueOf(calculator.multiply()));
break;
case "÷":
textResult.setText(String.valueOf(calculator.divide()));
break;
default:
textResult.setText("不是目标运算!");
}
}else {
// 否则说明是运算符
// 赋值运算符
calculator.setOperator(text);
textResult.setText(text);
}
// 清空数字
realText="";
}
@FXML
void clickReturnZero(ActionEvent event) {
// 归零
calculator.setNum1(0);
calculator.setNum2(0);
calculator.setOperator("");
textResult.setText("0");
}
}
10、运行测试
启动Main
11、总结
其实有很多地方是可以优化,我们编程不会是一蹴而就的。好的程序都是渐进优化而来。
那对于本次案例,在数字按钮那块其实是在做重复的工作,我们可以把它的监听事件都归为一个,同理运算符也是。
那通过这个例子,大家知道了,javafx基本使用,MVC架构的基本了解,程序优化的基本思想
星星之火,璀璨星光,你我都在路上!感谢你不厌其烦看完了本文