题型添加
parent
eeebf4bcb1
commit
1aaf69fbdf
|
|
@ -5,18 +5,23 @@ import com.alibaba.fastjson.JSONArray;
|
|||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.zhangmeng.online.exam.ui.api.ApiUtils;
|
||||
import com.zhangmeng.online.exam.ui.utils.HttpUtils;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.WritableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.css.StyleableProperty;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.AccessibleRole;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Font;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* 考试组件
|
||||
*
|
||||
* @author zm
|
||||
|
|
@ -25,10 +30,33 @@ import java.util.*;
|
|||
*/
|
||||
public class ExamComponent extends ScrollPane {
|
||||
|
||||
//计数器
|
||||
private final SimpleIntegerProperty SINGLE_CHOICE_COUNT = new SimpleIntegerProperty(1);
|
||||
private final SimpleIntegerProperty MULTIPLE_CHOICE_COUNT = new SimpleIntegerProperty(1);
|
||||
private final SimpleIntegerProperty JUDGMENT_COUNT = new SimpleIntegerProperty(1);
|
||||
private final SimpleIntegerProperty NUMERICAL_COUNT = new SimpleIntegerProperty(1);
|
||||
private final SimpleIntegerProperty Fill_IN_THE_BLANKS_COUNT = new SimpleIntegerProperty(1);
|
||||
private final SimpleIntegerProperty SHORT_ANSWER_COUNT = new SimpleIntegerProperty(1);
|
||||
|
||||
// 单选题
|
||||
private final ObservableList<SingleChoiceComponent> singleChoiceComponents = FXCollections.observableArrayList();
|
||||
// 多选题
|
||||
private final ObservableList<MultiChoiceComponent> multiChoiceComponents = FXCollections.observableArrayList();
|
||||
// 判断题
|
||||
private final ObservableList<TrueFalseComponent> judgmentComponents = FXCollections.observableArrayList();
|
||||
// 计算题
|
||||
private final ObservableList<NumericalComponent> numericalComponents = FXCollections.observableArrayList();
|
||||
// 填空题
|
||||
private final ObservableList<FillBlankComponent> fillInBlankComponents = FXCollections.observableArrayList();
|
||||
// 简答题
|
||||
private final ObservableList<ShortAnswerComponent> shortAnswerComponents = FXCollections.observableArrayList();
|
||||
|
||||
private VBox vBox;
|
||||
|
||||
public ExamComponent() {
|
||||
|
||||
this.vBox = new VBox(5);
|
||||
this.vBox.setPadding(new Insets(10));
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("pageNum", ApiUtils.PAGE_NUM);
|
||||
|
|
@ -39,48 +67,126 @@ public class ExamComponent extends ScrollPane {
|
|||
JSONArray data = jsonObject.getJSONArray("data");
|
||||
int total = jsonObject.getIntValue("total");
|
||||
int index = 1;
|
||||
|
||||
|
||||
for (Object datum : data) {
|
||||
JSONObject question = (JSONObject) datum;
|
||||
String type = question.getString("type");
|
||||
|
||||
switch (type) {
|
||||
case "单选题" -> {
|
||||
String list = question.getString("options");
|
||||
List<Map> maps = JSONArray.parseArray(list, Map.class);
|
||||
String correctAnswer = null;
|
||||
List<Map<String,Object>> optionList = new ArrayList<>();
|
||||
for (Map map : maps) {
|
||||
boolean isAnswer = (boolean) map.get("isAnswer");
|
||||
|
||||
Map<String,Object> option = new HashMap<>();
|
||||
option.put("id", map.get("id"));
|
||||
option.put("text",map.get("name").toString()+ map.get("content").toString());
|
||||
option.put("isAnswer",isAnswer);
|
||||
optionList.add(option);
|
||||
}
|
||||
SingleChoiceComponent singleChoiceComponent = new SingleChoiceComponent(index + "." + question.getString("name"), optionList);
|
||||
singleChoiceComponent.setCorrectAnswer(correctAnswer);
|
||||
Map<String,Object> context = new HashMap<>();
|
||||
context.put("question_id", question.getString("id"));
|
||||
context.put("paper_id",1);
|
||||
singleChoiceComponent.setContext(context);
|
||||
this.vBox.getChildren().add(singleChoiceComponent);
|
||||
index ++;
|
||||
}
|
||||
// case "多选题" -> MULTIPLE_CHOICE_SCORE.set(MULTIPLE_CHOICE_SCORE.get() + score);
|
||||
// case "判断题" -> JUDGMENT_SCORE.set(JUDGMENT_SCORE.get() + score);
|
||||
// case "计算题" -> NUMERICAL_SCORE.set(NUMERICAL_SCORE.get() + score);
|
||||
// case "填空题" -> Fill_IN_THE_BLANKS.set(Fill_IN_THE_BLANKS.get() + score);
|
||||
// case "简答题" -> SHORT_ANSWER_SCORE.set(SHORT_ANSWER_SCORE.get() + score);
|
||||
// default -> throw new IllegalStateException("Unexpected value: " + type.get());
|
||||
case "单选题" -> singleChoice(question);
|
||||
case "多选题" -> multiChoice(question);
|
||||
case "判断题" -> judgment(question);
|
||||
case "计算题" -> numerical(question);
|
||||
case "填空题" -> fillInBlank(question);
|
||||
case "简答题" -> shortAnswer(question);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + type);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Label label = new Label("一. 选择题");
|
||||
label.setFont(new Font("黑体", 18));
|
||||
this.vBox.getChildren().add(label);
|
||||
this.vBox.getChildren().addAll(singleChoiceComponents);
|
||||
this.vBox.getChildren().addAll(multiChoiceComponents);
|
||||
this.vBox.getChildren().addAll(judgmentComponents);
|
||||
this.vBox.getChildren().addAll(fillInBlankComponents);
|
||||
this.vBox.getChildren().addAll(shortAnswerComponents);
|
||||
// this.getChildren().addAll(numericalComponents);
|
||||
|
||||
this.setContent(vBox);
|
||||
this.setFitToWidth(true);
|
||||
this.setFitToHeight(true);
|
||||
|
||||
}
|
||||
|
||||
//简答题
|
||||
private void shortAnswer(JSONObject question) {
|
||||
String list = question.getString("options");
|
||||
List<Map> maps = JSONArray.parseArray(list, Map.class);
|
||||
List<Map<String, Object>> optionList = new ArrayList<>();
|
||||
for (Map map : maps) {
|
||||
boolean isAnswer = (boolean) map.get("isAnswer");
|
||||
Map<String, Object> option = new HashMap<>();
|
||||
option.put("id", map.get("id").toString());
|
||||
option.put("text", map.get("name").toString() + map.get("content").toString());
|
||||
option.put("isAnswer", isAnswer);
|
||||
option.put("option", map.get("name").toString().trim().replace(".", ""));
|
||||
option.put("content", map.get("content").toString());
|
||||
optionList.add(option);
|
||||
}
|
||||
ShortAnswerComponent shortAnswerComponent = new ShortAnswerComponent(SINGLE_CHOICE_COUNT.get() + "." + question.getString("name"), optionList);
|
||||
Map<String, Object> context = new HashMap<>();
|
||||
context.put("question_id", question.getString("id"));
|
||||
context.put("paper_id", 1);
|
||||
shortAnswerComponent.setContext(context);
|
||||
shortAnswerComponents.add(shortAnswerComponent);
|
||||
SHORT_ANSWER_COUNT.set(SHORT_ANSWER_COUNT.get() + 1);
|
||||
}
|
||||
|
||||
//填空题
|
||||
private void fillInBlank(JSONObject question) {
|
||||
}
|
||||
|
||||
//计算题
|
||||
private void numerical(JSONObject question) {
|
||||
}
|
||||
|
||||
//判断题
|
||||
private void judgment(JSONObject question) {
|
||||
|
||||
String list = question.getString("options");
|
||||
List<Map> maps = JSONArray.parseArray(list, Map.class);
|
||||
String correctAnswer = null;
|
||||
List<Map<String, Object>> optionList = new ArrayList<>();
|
||||
for (Map map : maps) {
|
||||
boolean isAnswer = (boolean) map.get("isAnswer");
|
||||
Map<String, Object> option = new HashMap<>();
|
||||
option.put("id", map.get("id").toString());
|
||||
option.put("text", map.get("name").toString() + map.get("content").toString());
|
||||
option.put("isAnswer", isAnswer);
|
||||
option.put("option", map.get("name").toString().trim().replace(".", ""));
|
||||
option.put("content", map.get("content").toString());
|
||||
optionList.add(option);
|
||||
}
|
||||
TrueFalseComponent trueFalseComponent = new TrueFalseComponent(SINGLE_CHOICE_COUNT.get() + "." + question.getString("name"), optionList);
|
||||
Map<String, Object> context = new HashMap<>();
|
||||
context.put("question_id", question.getString("id"));
|
||||
context.put("paper_id", 1);
|
||||
trueFalseComponent.setContext(context);
|
||||
judgmentComponents.add(trueFalseComponent);
|
||||
JUDGMENT_COUNT.set(JUDGMENT_COUNT.get() + 1);
|
||||
|
||||
}
|
||||
|
||||
//多选题
|
||||
private void multiChoice(JSONObject question) {
|
||||
|
||||
}
|
||||
|
||||
//单选题
|
||||
private void singleChoice(JSONObject question) {
|
||||
String list = question.getString("options");
|
||||
List<Map> maps = JSONArray.parseArray(list, Map.class);
|
||||
String correctAnswer = null;
|
||||
List<Map<String, Object>> optionList = new ArrayList<>();
|
||||
for (Map map : maps) {
|
||||
boolean isAnswer = (boolean) map.get("isAnswer");
|
||||
Map<String, Object> option = new HashMap<>();
|
||||
option.put("id", map.get("id").toString());
|
||||
option.put("text", map.get("name").toString() + map.get("content").toString());
|
||||
option.put("isAnswer", isAnswer);
|
||||
option.put("option", map.get("name").toString().trim().replace(".", ""));
|
||||
option.put("content", map.get("content").toString());
|
||||
optionList.add(option);
|
||||
}
|
||||
SingleChoiceComponent singleChoiceComponent = new SingleChoiceComponent(SINGLE_CHOICE_COUNT.get() + "." + question.getString("name"), optionList);
|
||||
singleChoiceComponent.setCorrectAnswer(correctAnswer);
|
||||
Map<String, Object> context = new HashMap<>();
|
||||
context.put("question_id", question.getString("id"));
|
||||
context.put("paper_id", 1);
|
||||
singleChoiceComponent.setContext(context);
|
||||
singleChoiceComponents.add(singleChoiceComponent);
|
||||
SINGLE_CHOICE_COUNT.set(SINGLE_CHOICE_COUNT.get() + 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.zhangmeng.online.exam.ui.components;
|
||||
|
||||
import com.zhangmeng.online.exam.ui.utils.OptionsUtils;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -25,6 +27,12 @@ public class MultiChoiceComponent extends VBox {
|
|||
|
||||
private List<CheckBox> checkBoxes = new ArrayList<>();
|
||||
|
||||
private HBox hBox = new HBox();
|
||||
|
||||
private int number_of_responses = 0;//作答次数
|
||||
|
||||
private final SimpleStringProperty result_answer = new SimpleStringProperty(); // 最终答案
|
||||
|
||||
|
||||
public MultiChoiceComponent(String question, Set<String> options) {
|
||||
Set<String> selected = new HashSet<>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package com.zhangmeng.online.exam.ui.components;
|
||||
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
/**
|
||||
* @author zm
|
||||
* @date 2025/3/21 9:51
|
||||
* @version: 1.0
|
||||
*/
|
||||
public class NumericalComponent extends VBox {
|
||||
}
|
||||
|
|
@ -359,7 +359,12 @@ public class PaperViewComponent extends SplitPane {
|
|||
|
||||
private void reloadData(List<Map<String, SimpleStringProperty>> changeList) {
|
||||
for (Map<String, SimpleStringProperty> chooseTableDatum : changeList) {
|
||||
int score = Integer.parseInt(chooseTableDatum.get("score").get());
|
||||
int score = 0;
|
||||
|
||||
if (chooseTableDatum.get("score").get() != null){
|
||||
score = Integer.parseInt(chooseTableDatum.get("score").get());
|
||||
}
|
||||
|
||||
SimpleStringProperty type = chooseTableDatum.get("type");
|
||||
|
||||
switch (type.get()) {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
package com.zhangmeng.online.exam.ui.components;
|
||||
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @Description: 简答题组件
|
||||
|
|
@ -16,30 +19,55 @@ import java.util.List;
|
|||
* @version: 1.0
|
||||
*/
|
||||
public class ShortAnswerComponent extends VBox {
|
||||
// 题目数据模型
|
||||
private static class Question {
|
||||
String content; // 题目内容
|
||||
List<String> keywords; // 参考答案关键词(如 ["封装","继承","多态"])
|
||||
|
||||
private Map<String,Object> context = new HashMap<>();
|
||||
|
||||
public Map<String, Object> getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
// 示例题目
|
||||
private final Question currentQuestion = new Question();
|
||||
{
|
||||
currentQuestion.content = "简述面向对象编程的三大特性";
|
||||
currentQuestion.keywords = Arrays.asList("封装", "继承", "多态");
|
||||
public void setContext(Map<String, Object> context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public ShortAnswerComponent() {
|
||||
private String correctAnswer = null; // 预设正确答案
|
||||
|
||||
private int number_of_responses = 0;//作答次数
|
||||
|
||||
private final SimpleStringProperty result_answer = new SimpleStringProperty(); // 最终答案
|
||||
|
||||
private HBox hBox = new HBox();
|
||||
|
||||
private Label questionLabel;
|
||||
|
||||
private TextArea answerArea;
|
||||
|
||||
private List<String> keywords = new ArrayList<>(); // 参考答案关键词(如 ["封装","继承","多态"])
|
||||
|
||||
public ShortAnswerComponent(String question, List<Map<String, Object>> options) {
|
||||
|
||||
this.setStyle("-fx-background-color: white; -fx-border-color: #eadcdc;" +
|
||||
"-fx-border-radius: 10px; -fx-border-width: 1px; -fx-border-style: solid;-fx-background-radius: 10px;");
|
||||
|
||||
for (Map<String, Object> option : options) {
|
||||
keywords.add( option.get("content").toString());
|
||||
}
|
||||
|
||||
// 题目展示
|
||||
Label questionLabel = new Label(currentQuestion.content);
|
||||
questionLabel.setStyle("-fx-font-size: 16px; -fx-font-weight: bold;");
|
||||
questionLabel = new Label(question);
|
||||
|
||||
hBox.getChildren().add(questionLabel);
|
||||
this.getChildren().add(hBox);
|
||||
this.setPrefHeight(240);
|
||||
|
||||
|
||||
// 输入组件
|
||||
TextArea answerArea = new TextArea();
|
||||
answerArea = new TextArea();
|
||||
answerArea.setMinHeight(200);
|
||||
answerArea.setPromptText("在此输入答案(建议不少于50字)");
|
||||
answerArea.setPrefRowCount(8);
|
||||
answerArea.setWrapText(true); // 自动换行:ml-citation{ref="1" data="citationList"}
|
||||
this.getChildren().add(answerArea);
|
||||
|
||||
|
||||
// 功能组件
|
||||
Button submitBtn = new Button("提交答案");
|
||||
|
|
@ -57,7 +85,7 @@ public class ShortAnswerComponent extends VBox {
|
|||
// 关键词匹配验证
|
||||
StringBuilder missingKeys = new StringBuilder();
|
||||
int matchCount = 0;
|
||||
for (String keyword : currentQuestion.keywords) {
|
||||
for (String keyword : keywords) {
|
||||
if (userAnswer.contains(keyword)) {
|
||||
matchCount++;
|
||||
} else {
|
||||
|
|
@ -66,22 +94,27 @@ public class ShortAnswerComponent extends VBox {
|
|||
}
|
||||
|
||||
// 反馈逻辑
|
||||
if (matchCount == currentQuestion.keywords.size()) {
|
||||
if (matchCount == keywords.size()) {
|
||||
resultLabel.setText("✅ 答案完整,包含所有关键词!");
|
||||
resultLabel.setStyle("-fx-text-fill: #2ecc71;");
|
||||
} else if (matchCount > 0) {
|
||||
resultLabel.setText("⚠ 部分正确(缺失:" + missingKeys.substring(1) + ")");
|
||||
resultLabel.setStyle("-fx-text-fill: #f1c40f;");
|
||||
} else {
|
||||
resultLabel.setText("❌ 参考答案关键词:" + String.join(",", currentQuestion.keywords));
|
||||
resultLabel.setText("❌ 参考答案关键词:" + String.join(",", keywords));
|
||||
resultLabel.setStyle("-fx-text-fill: #e74c3c;");
|
||||
}
|
||||
});
|
||||
|
||||
// 布局容器
|
||||
this.setSpacing(20);
|
||||
this.setPadding(new Insets(20));
|
||||
this.getChildren().addAll(questionLabel, answerArea, submitBtn, resultLabel);
|
||||
// this.setSpacing(20);
|
||||
// this.setPadding(new Insets(20));
|
||||
this.getChildren().addAll(submitBtn, resultLabel);
|
||||
|
||||
// 布局容器
|
||||
this.setSpacing(10);
|
||||
this.setPadding(new Insets(15));
|
||||
this.hBox.getChildren().add(1,resultLabel);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@ package com.zhangmeng.online.exam.ui.components;
|
|||
import com.zhangmeng.online.exam.ui.api.ApiUtils;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
|
@ -45,11 +43,21 @@ public class SingleChoiceComponent extends VBox {
|
|||
|
||||
private final SimpleStringProperty result_answer = new SimpleStringProperty(); // 最终答案
|
||||
|
||||
private HBox hBox = new HBox();
|
||||
|
||||
private Label questionLabel;
|
||||
|
||||
public SingleChoiceComponent(String question, List<Map<String, Object>> options) {
|
||||
|
||||
this.setStyle("-fx-background-color: white; -fx-border-color: #eadcdc;" +
|
||||
"-fx-border-radius: 10px; -fx-border-width: 1px; -fx-border-style: solid;-fx-background-radius: 10px;");
|
||||
|
||||
// 创建题目组件
|
||||
Label questionLabel = new Label(question);
|
||||
this.getChildren().add(questionLabel);
|
||||
questionLabel = new Label(question);
|
||||
|
||||
hBox.getChildren().add(questionLabel);
|
||||
|
||||
this.getChildren().add(hBox);
|
||||
ToggleGroup answerGroup = new ToggleGroup(); // 单选按钮组:ml-citation{ref="1,2" data="citationList"}
|
||||
// 创建选项按钮
|
||||
for (Map<String, Object> option : options) {
|
||||
|
|
@ -105,15 +113,15 @@ public class SingleChoiceComponent extends VBox {
|
|||
answerGroup.selectedToggleProperty().addListener((ov, old_value, new_value) -> {
|
||||
RadioButton selected = (RadioButton) new_value;
|
||||
if (selected != null) {
|
||||
String answer = selected.getText().substring(0, 1);
|
||||
result_answer.set(answer);
|
||||
|
||||
Map<String, Object> option = (Map<String, Object>) selected.getUserData();
|
||||
number_of_responses++;
|
||||
// resultLabel.setText("你的选择:"+ result_answer.get());
|
||||
// resultLabel.setStyle("-fx-text-fill: #2ecc71;");
|
||||
String id = (String) selected.getUserData();
|
||||
context.put("option_id", id);
|
||||
context.put("option_id", option.get("id"));
|
||||
result_answer.set(option.get("id").toString());
|
||||
//提交数据
|
||||
ApiUtils.submitAnswer(context, result_answer.get());
|
||||
ApiUtils.submitAnswer(context);
|
||||
resultLabel.setText("你的选择:"+ option.get("option"));
|
||||
resultLabel.setStyle("-fx-text-fill: #2ecc71;");
|
||||
|
||||
} else {
|
||||
resultLabel.setText("⚠ 请先选择答案");
|
||||
|
|
@ -123,7 +131,8 @@ public class SingleChoiceComponent extends VBox {
|
|||
// 布局容器
|
||||
this.setSpacing(10);
|
||||
this.setPadding(new Insets(15));
|
||||
this.getChildren().addAll(resultLabel);
|
||||
this.hBox.getChildren().add(1,resultLabel);
|
||||
|
||||
}
|
||||
|
||||
// 封装单选按钮创建方法:ml-citation{ref="2,3" data="citationList"}
|
||||
|
|
@ -131,7 +140,7 @@ public class SingleChoiceComponent extends VBox {
|
|||
RadioButton rb = new RadioButton(option.get("text").toString());
|
||||
rb.setToggleGroup(group);
|
||||
rb.setPadding(new Insets(5));
|
||||
rb.setUserData(option.get("id"));
|
||||
rb.setUserData(option);
|
||||
return rb;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,69 +1,134 @@
|
|||
package com.zhangmeng.online.exam.ui.components;
|
||||
|
||||
import com.zhangmeng.online.exam.ui.api.ApiUtils;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 判断题组件
|
||||
*
|
||||
* @author zm
|
||||
* @date 2025/3/4 15:06
|
||||
* @version: 1.0
|
||||
*/
|
||||
public class TrueFalseComponent extends VBox {
|
||||
|
||||
// 预设正确答案
|
||||
private final boolean correctAnswer = true;
|
||||
private static final String TRUE_TEXT = "✔ 正确";
|
||||
private static final String FALSE_TEXT = "✘ 错误";
|
||||
|
||||
private Map<String, Object> context = new HashMap<>();
|
||||
|
||||
public Map<String, Object> getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void setContext(Map<String, Object> context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private String correctAnswer = null; // 预设正确答案
|
||||
|
||||
private int number_of_responses = 0;//作答次数
|
||||
|
||||
private final SimpleStringProperty result_answer = new SimpleStringProperty(); // 最终答案
|
||||
|
||||
private HBox hBox = new HBox();
|
||||
|
||||
private Label questionLabel;
|
||||
|
||||
|
||||
public TrueFalseComponent(String question, List<Map<String, Object>> options) {
|
||||
|
||||
this.setStyle("-fx-background-color: white; -fx-border-color: #eadcdc;" + "-fx-border-radius: 10px; -fx-border-width: 1px; -fx-border-style: solid;-fx-background-radius: 10px;");
|
||||
|
||||
public TrueFalseComponent() {
|
||||
|
||||
// 题目组件
|
||||
Label questionLabel = new Label("1. JavaFX 是 Oracle 官方提供的 GUI 框架吗?");
|
||||
questionLabel.setStyle("-fx-font-size: 16px; -fx-font-weight: bold;");
|
||||
questionLabel = new Label(question);
|
||||
hBox.getChildren().add(questionLabel);
|
||||
this.getChildren().add(hBox);
|
||||
|
||||
// 单选按钮组
|
||||
ToggleGroup answerGroup = new ToggleGroup();
|
||||
RadioButton trueButton = createRadioButton("✔ 正确", answerGroup);
|
||||
RadioButton falseButton = createRadioButton("✘ 错误", answerGroup);
|
||||
|
||||
// 创建选项按钮
|
||||
for (Map<String, Object> option : options) {
|
||||
boolean isAnswer = (boolean) option.get("isAnswer");
|
||||
if (isAnswer) {
|
||||
RadioButton trueButton = createRadioButton(TRUE_TEXT, answerGroup,option);
|
||||
this.getChildren().add(trueButton);
|
||||
} else {
|
||||
RadioButton falseButton = createRadioButton(FALSE_TEXT, answerGroup,option);
|
||||
this.getChildren().add(falseButton);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 功能组件
|
||||
Button submitBtn = new Button("提交答案");
|
||||
// Button submitBtn = new Button("提交答案");
|
||||
Label resultLabel = new Label();
|
||||
|
||||
// 提交事件处理
|
||||
submitBtn.setOnAction(e -> {
|
||||
if (answerGroup.getSelectedToggle() == null) {
|
||||
resultLabel.setText("⚠ 请先选择答案");
|
||||
resultLabel.setStyle("-fx-text-fill: #e67e22;");
|
||||
return;
|
||||
}
|
||||
// submitBtn.setOnAction(e -> {
|
||||
// if (answerGroup.getSelectedToggle() == null) {
|
||||
// resultLabel.setText("⚠ 请先选择答案");
|
||||
// resultLabel.setStyle("-fx-text-fill: #e67e22;");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// boolean userAnswer = ((RadioButton) answerGroup.getSelectedToggle()).getText().contains("正确");
|
||||
// if (userAnswer == correctAnswer) {
|
||||
// resultLabel.setText("✅ 回答正确!");
|
||||
// resultLabel.setStyle("-fx-text-fill: #2ecc71;");
|
||||
// } else {
|
||||
// resultLabel.setText("❌ 正确答案:" + (correctAnswer ? "正确" : "错误"));
|
||||
// resultLabel.setStyle("-fx-text-fill: #e74c3c;");
|
||||
// }
|
||||
// });
|
||||
|
||||
boolean userAnswer = ((RadioButton) answerGroup.getSelectedToggle()).getText().contains("正确");
|
||||
if (userAnswer == correctAnswer) {
|
||||
resultLabel.setText("✅ 回答正确!");
|
||||
answerGroup.selectedToggleProperty().addListener((ov, old_value, new_value) -> {
|
||||
RadioButton selected = (RadioButton) new_value;
|
||||
if (selected != null) {
|
||||
|
||||
Map<String, Object> option = (Map<String, Object>) selected.getUserData();
|
||||
number_of_responses++;
|
||||
context.put("option_id", option.get("id"));
|
||||
result_answer.set(option.get("id").toString());
|
||||
//提交数据
|
||||
ApiUtils.submitAnswer(context);
|
||||
boolean isAnswer = (boolean) option.get("isAnswer");
|
||||
if (isAnswer){
|
||||
resultLabel.setText("你的选择:"+ TRUE_TEXT);
|
||||
}else {
|
||||
resultLabel.setText("你的选择:"+ FALSE_TEXT);
|
||||
}
|
||||
resultLabel.setStyle("-fx-text-fill: #2ecc71;");
|
||||
} else {
|
||||
resultLabel.setText("❌ 正确答案:" + (correctAnswer ? "正确" : "错误"));
|
||||
resultLabel.setStyle("-fx-text-fill: #e74c3c;");
|
||||
resultLabel.setText("⚠ 请先选择答案");
|
||||
}
|
||||
});
|
||||
|
||||
// 布局容器
|
||||
this.setSpacing(15);
|
||||
this.setPadding(new Insets(20));
|
||||
this.getChildren().addAll(questionLabel, trueButton, falseButton, submitBtn, resultLabel);
|
||||
|
||||
|
||||
this.setSpacing(10);
|
||||
this.setPadding(new Insets(15));
|
||||
this.hBox.getChildren().add(1, resultLabel);
|
||||
}
|
||||
|
||||
// 创建带样式的单选按钮:ml-citation{ref="1,3" data="citationList"}
|
||||
private RadioButton createRadioButton(String text, ToggleGroup group) {
|
||||
private RadioButton createRadioButton(String text, ToggleGroup group,Map<String, Object> option) {
|
||||
RadioButton rb = new RadioButton(text);
|
||||
rb.setToggleGroup(group);
|
||||
rb.setStyle("-fx-font-size: 14px; -fx-padding: 5px;");
|
||||
rb.setUserData(option);
|
||||
return rb;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue