太长时间没写博客了,其实这期间学了很多东西,但都是在记笔记没发过博客,这次借着学校的作业学了个新东西javaFx,比swing界面好看很多也方便很多,所以根据这个小项目准备写一篇博客,记录一下初学的javaFx,因为只学了四天,掌握的只是皮毛,所以如果有什么不妥的地方欢迎指正!
要求:java编写小程序,完成随机生成50道一百以内的不重复的加减法,可能需要输出混合运算。
思路:首先要编写习题类,用于生成简单的两个数运算习题;再编写混合运算类继承习题类,用于生成混合的加减法运算习题;由于需要图形界面输出,所以两个类都需要编写打印方法用于打印出习题。
之后需要编写一个总的类,相当于习题本,包含一个习题数组的属性,这个习题数组既包含简单运算也包含混合运算(混合运算继承于简单运算),在这个类的构造函数中完成对习题的初始化,初始化的过程中检查重复性,由于生成是随机的,所以有几率习题会出现重复的情况,可以在出现重复的时候,在当前位置上重新生成习题。
在编写GUI的时候选择了javaFx,因为就算是缺省的基本工具样式也很好看,用起来也方便。主要分有四个Pane,一个是根节点Pane,做下面三个Pane的父节点;两个页面Pane,第一页和第二页;一个最右边的输出成绩和页面showPane。
在功能方面需要完成:
Exercise类:
public class Exercise {
private int left;
private int right;
private char operate;
private int result;
private Random random = new Random();
public Exercise(){
left = random.nextInt(101);
right = random.nextInt(101);
if(random.nextInt(2) == 0){
operate = '+';
result = left + right;
}else {
operate = '-';
result = left - right;
}
}
public String print(){
return (left+" "+operate+" "+right+ " = ");
}
public int getLeft() {
return left;
}
public int getRight() {
return right;
}
public char getOperate() {
return operate;
}
public String getResult() {
String res = Integer.toString(result);
return res;
}
}
mixExercise类:
public class mixExercise extends Exercise {//随机数个混合运算,混合运算包含的数字在(3,5)之间
private Random random = new Random();
private int size;
private ArrayList<Integer> numList;
private ArrayList<Character> opList;
private int result;
public mixExercise(){
size = random.nextInt(3) + 3;
numList = new ArrayList<>(size);
opList = new ArrayList<>(size - 1);
for(int i = 0; i < size - 1; i++){
numList.add(random.nextInt(101));
if(random.nextInt(2) == 0)opList.add('+');
else opList.add('-');
}
numList.add(random.nextInt(101));
result = numList.get(0);
for(int i = 0; i < opList.size(); i++){
if(opList.get(i) == '+'){
result += numList.get(i + 1);
}else {
result -= numList.get(i + 1);
}
}
}
public String print(){
String display = "";
for(int i = 0; i < opList.size(); i++){
display += numList.get(i);
display += " " + opList.get(i) + " ";
}
display += numList.get(size - 1);
return display + " = ";
}
@Override
public String getResult() {
String res = Integer.toString(result);
return res;
}
}
Operation类:
public class Operation {
public ArrayList<Exercise> exercises;
public Operation(int num_MixExercise){
exercises = new ArrayList<>(50);
for(int i = 0; i <= 50 - num_MixExercise;){
Exercise exercise = new Exercise();
if(!checkTheRepeat(exercise)){
exercises.add(exercise);
i++;
}
}
for(int i = 0; i < num_MixExercise; i++){
Exercise mixExercise = new mixExercise();
exercises.add(mixExercise);
}
}
public boolean checkTheRepeat(Exercise exercise){
for(Exercise e : exercises){
if(e.getLeft() == exercise.getLeft() && e.getRight() == exercise.getRight() && e.getResult() == exercise.getResult()){
return true;
}
}
return false;
}
}
GUI编程部分:
public class Frame extends Application{
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage){
AnchorPane root = new AnchorPane();
//第一页
AnchorPane page_1 = new AnchorPane();
page_1.setStyle("-fx-background-image: url(./background.jpg)");
page_1.setLayoutX(0);
page_1.setLayoutY(0);
page_1.setPrefWidth(1200);
page_1.setPrefHeight(1000);
//第二页
AnchorPane page_2 = new AnchorPane();
page_2.setStyle("-fx-background-image: url(./background.jpg)");
page_2.setLayoutX(0);
page_2.setLayoutY(0);
page_2.setPrefWidth(1200);
page_2.setPrefHeight(1000);
//右侧展示页
AnchorPane right = new AnchorPane();
right.setStyle("-fx-background-image: url(./rightBack.jpg)");
right.setPrefWidth(600);
right.setPrefHeight(1000);
right.setLayoutX(1200);
right.setLayoutY(0);
Button submit = new Button("提交");
submit.setPrefWidth(110);
submit.setPrefHeight(50);
submit.setFont(Font.font("Inconsolata",20));
submit.setCursor(Cursor.OPEN_HAND);
submit.setStyle("-fx-background-color:#929FD1;"+ "-fx-background-radius: 20;");
submit.setLayoutX(230);
submit.setLayoutY(120);
root.getChildren().add(page_1);
root.getChildren().add(right);
right.getChildren().add(submit);
//规定加减法混合运算的个数
int num_MixExercise = 3;
Operation operation = new Operation(num_MixExercise);
ArrayList<Text> textList = new ArrayList<>();
ArrayList<TextField> textFieldList = new ArrayList<>();
//从exercise中一一获取文本,并创造输入框
for(Exercise e : operation.exercises){
Text text = new Text();
text.setText(e.print());
textList.add(text);
TextField textField = new TextField();
textFieldList.add(textField);
}
//第一页布局
int num = 0;
for(int i = 0; i < 9; i++) { //九行五列(第一页)
for(int j = 0; j < 5; j++) {
Text text = textList.get(num);
TextField textField = textFieldList.get(num);
//调用统一的方法
HBox box = setStyle(text,textField,i,j);
HBox number = setNum(i,j,++num);
page_1.getChildren().add(box);
page_1.getChildren().add(number);
}
}
//第二页布局
//一行剩余简单运算
int i = 0;
for(; i < 5 - num_MixExercise; i++){
Text text = textList.get(45 + i);
TextField textField = textFieldList.get(45 + i);
//掉用统一的方法
HBox box = setStyle(text,textField,1,i);
HBox number = setNum(1,i,46+i);
page_2.getChildren().add(box);
page_2.getChildren().add(number);
}
//num_MixExercise行规定的混合运算,此时调用不了setStyle了,因为各个参数都需要另调
for(int j = 46 + i; j < 51; j++){
Text text = textList.get(j);
text.setX(50 + 220 );
text.setY(50 + 100*(j - 46));
text.setStyle("-fx-font-size: 20px;"+"-fx-font-family: STXihei;"+"-fx-font-weight: bolder");
TextField textField = textFieldList.get(j);
textField.setMaxWidth(70);
textField.setLayoutX(150 + 350);
textField.setLayoutY(29 + 100* (j - 46));
textField.setStyle("-fx-background-color: #FDF9ED");
HBox box = new HBox();
box.setStyle("-fx-background-color: #E7C7D7;"+"-fx-border-color: #F17173;"+"-fx-border-style: dashed;" + "-fx-border-width: 5px;");
box.getChildren().addAll(text,textField);
box.setLayoutX(50);
box.setLayoutY(50 + 100*(j - 46));
box.setPrefWidth(350);
box.setPrefHeight(40);
box.setPadding(new Insets(12));
page_2.getChildren().add(box);
int m = j;
Text n = new Text(String.valueOf(m));
n.setFont(Font.font("Adobe 黑体 Std R"));
HBox number = new HBox();
number.setStyle("-fx-background-color: #F5EEF8;" + "-fx-border-style: dashed;" + "-fx-border-width: 3px;" + "-fx-border-color: #D2B4DE; ");
number.getChildren().add(n);
number.setLayoutX(48);
number.setLayoutY(20 + 100*(j-46));
number.setPrefWidth(40);
number.setPrefHeight(12);
number.setPadding(new Insets(5));
page_2.getChildren().add(number);
}
Button slip = new Button("下一页");
slip.setPrefWidth(80);
slip.setPrefHeight(30);
slip.setFont(Font.font("Inconsolata",16));
slip.setCursor(Cursor.OPEN_HAND);
slip.setStyle("-fx-background-color:#929FD1;"+ "-fx-background-radius: 15;");
slip.setLayoutX(1100);
slip.setLayoutY(10);
page_1.getChildren().add(slip);
//点击下一页
slip.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
root.getChildren().add(page_2);
}
});
Button pils = new Button("上一页");
pils.setPrefWidth(80);
pils.setPrefHeight(30);
pils.setFont(Font.font("Inconsolata",16));
pils.setCursor(Cursor.OPEN_HAND);
pils.setStyle("-fx-background-color:#929FD1;"+ "-fx-background-radius: 15;");
pils.setLayoutX(1100);
pils.setLayoutY(10);
page_2.getChildren().add(pils);
//点击上一页
pils.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
root.getChildren().remove(page_2);
}
});
//红色提示
wrongAnswerTip(textFieldList);
//对窗口本身的设置
Scene scene = new Scene(root);
primaryStage.setScene(scene);
scene.setCursor(Cursor.DEFAULT);
primaryStage.setTitle("每日50题");
primaryStage.getIcons().add(new Image("./image50.jpg"));
primaryStage.setWidth(1800);
primaryStage.setHeight(1000);
//展示窗口
primaryStage.show();
//右侧展示成绩的方框
VBox showBox = new VBox();//-fx-background-color: #A9DFBF;
showBox.setStyle("-fx-background-image: url(./show.jpg);"+"-fx-border-color: #52BE80;"+"-fx-border-style: dashed;"+"-fx-border-width: 5px");
showBox.setLayoutX(45);
showBox.setLayoutY(218);
showBox.setPrefWidth(500);
showBox.setPrefHeight(700);
right.getChildren().add(showBox);
//提交按钮的事件:get所有输入框的内容,再与习题答案一一比较得出成绩,输出错题集
boolean[] correct = new boolean[51];
submit.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
int num = 0;
for(int i = 0; i < textFieldList.size(); i++){
if(textFieldList.get(i).getText().equals(operation.exercises.get(num).getResult())){
correct[num++] = true;
}else {
correct[num++] = false;
}
}
Text sore = new Text();
sore.setStyle("-fx-font-family: 'Adobe 黑体 Std R';"+"-fx-font-size: 25px;"+"-fx-font-weight: bolder");
showBox.setPadding(new Insets(70));
int res = 0;
for(boolean x : correct){
if(x){
res += 2;
}
}
//打印成绩和错题编号
sore.setText(" 成绩: " + res);
showBox.getChildren().add(sore);
Text detail = new Text();
detail.setText(" 错题:");
detail.setStyle("-fx-font-family: 'Adobe 黑体 Std R';" + "-fx-font-size: 20;" + "-fx-font-weight: bolder;" + "-fx-text-fill: #F17173");
TextArea wrong = new TextArea();
wrong.setStyle("-fx-font-family: 'Adobe 黑体 Std R';" + "-fx-font-size: 18;" + "-fx-font-weight: bolder;" + "-fx-text-fill: #F17173");
String wrongWork = "";
for(int i = 0; i < correct.length - 1; i++){
if( !correct[i] ){
wrongWork += (i+1)+" ";
}
}
wrong.setWrapText(true);
wrong.setText(wrongWork);
showBox.getChildren().add(detail);
showBox.getChildren().add(wrong);
}
});
//倒计时的功能
HBox timeBox = new HBox();
timeBox.setStyle("-fx-background-color: #FDF9ED");
timeBox.setLayoutX(90);
timeBox.setLayoutY(20);
timeBox.setPrefWidth(400);
timeBox.setPrefHeight(50);
timeBox.setPadding(new Insets(25));
Text time = new Text(" 倒计时: ");
time.setStyle("-fx-font-family: 'Adobe 黑体 Std R';"+"-fx-font-size: 25px;"+"-fx-font-weight: bolder;"+"-fx-text-fill: #2C4975");
Clock clock = new Clock();
clock.setPrefWidth(200);
clock.setPrefHeight(50);
right.getChildren().add(timeBox);
timeBox.getChildren().addAll(time,clock);
}
public void wrongAnswerTip(ArrayList<TextField> textFieldList){
//输入字符后输入框提示(变红)
for(TextField textField : textFieldList){
textField.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
String regex=".*[a-zA-Z]+.*";
Matcher m=Pattern.compile(regex).matcher(newValue);
if(m.matches()){
textField.setStyle("-fx-background-color: #F17173");
}else {
textField.setStyle("-fx-background-color: #FDF9ED");
}
}
});
}
}
public HBox setStyle(Text text, TextField textField, int i, int j){
text.setX(50 + 220 * j);
text.setY(50 + 100 * i);
text.setStyle("-fx-font-size: 20px;"+"-fx-font-family: STXihei;"+"-fx-font-weight: bolder");
textField.setMaxWidth(50);
textField.setLayoutX(150 + 220 * j);
textField.setLayoutY(29 + 100 * i);
textField.setStyle("-fx-background-color: #FDF9ED");
HBox box = new HBox();
box.setStyle("-fx-background-color: #E7C7D7;"+"-fx-border-color: #F17173;"+"-fx-border-style: dashed;" + "-fx-border-width: 5px;");
box.getChildren().addAll(text,textField);
box.setLayoutX(50 + 220*j);
box.setLayoutY(50 + 100*i);
box.setPrefWidth(190);
box.setPrefHeight(40);
box.setPadding(new Insets(12));
return box;
}
public HBox setNum(int i,int j,int count){
int num = count;
Text n = new Text(String.valueOf(num));
n.setFont(Font.font("Adobe 黑体 Std R"));
HBox number = new HBox();
number.setStyle("-fx-background-color: #F5EEF8;" + "-fx-border-style: dashed;" + "-fx-border-width: 3px;" + "-fx-border-color: #D2B4DE; ");
number.getChildren().add(n);
number.setLayoutX(48 + 220*j);
number.setLayoutY(20 + 100*i);
number.setPrefWidth(40);
number.setPrefHeight(12);
number.setPadding(new Insets(5));
return number;
}
}
注释什么的都在代码里标注了,可能方法还是不精练,之后javaFx再深入学习会回来再改写一下。