按钮与试题绑定,动态生效 2025年3月21日17:37:36
parent
b131f7da38
commit
3a6c6d1f1d
|
|
@ -3,6 +3,7 @@ package com.zhangmeng.online.exam.ui.components;
|
|||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
|
||||
|
|
@ -11,6 +12,7 @@ import java.util.Map;
|
|||
|
||||
/**
|
||||
* 考试按钮组件
|
||||
*
|
||||
* @author zm
|
||||
* @date 2025/3/21 13:59
|
||||
* @version: 1.0
|
||||
|
|
@ -23,7 +25,10 @@ public class ExamButtonComponent extends FlowPane {
|
|||
|
||||
private final Map<Button, Integer> buttonMap = new HashMap<>();
|
||||
|
||||
public ExamButtonComponent(int count,ExamComponent examComponent) {
|
||||
|
||||
public ExamButtonComponent(int count, ExamComponent examComponent) {
|
||||
|
||||
this.getStylesheets().add(getClass().getResource("/css/button.css").toExternalForm());
|
||||
this.examComponent = examComponent;
|
||||
this.countButton.set(count);
|
||||
this.setHgap(10);
|
||||
|
|
@ -33,15 +38,33 @@ public class ExamButtonComponent extends FlowPane {
|
|||
Button button = new Button(String.valueOf(i));
|
||||
button.setPrefWidth(45);
|
||||
button.setOnAction(event -> {
|
||||
|
||||
//滚动到指定题目
|
||||
int currentIndex = buttonMap.get(button);
|
||||
examComponent.scrollToIndex(currentIndex);
|
||||
|
||||
});
|
||||
buttonMap.put(button,i);
|
||||
buttonMap.put(button, i);
|
||||
Node node = examComponent.getNode(i);
|
||||
|
||||
if (node instanceof SingleChoiceComponent singleChoiceComponent) {
|
||||
singleChoiceComponent.setIndexButton(button);
|
||||
}
|
||||
if (node instanceof MultiChoiceComponent multiChoiceComponent) {
|
||||
multiChoiceComponent.setIndexButton(button);
|
||||
}
|
||||
if (node instanceof TrueFalseComponent judgementComponent) {
|
||||
judgementComponent.setIndexButton(button);
|
||||
}
|
||||
if (node instanceof FillBlankComponent fillBlankComponent) {
|
||||
fillBlankComponent.setIndexButton(button);
|
||||
}
|
||||
if (node instanceof ShortAnswerComponent shortAnswerComponent) {
|
||||
shortAnswerComponent.setIndexButton(button);
|
||||
}
|
||||
|
||||
this.getChildren().add(button);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ public class ExamComponent extends ScrollPane {
|
|||
private final ObservableList<ShortAnswerComponent> shortAnswerComponents = FXCollections.observableArrayList();
|
||||
|
||||
private final SimpleIntegerProperty totalCount = new SimpleIntegerProperty(0);
|
||||
private final SimpleIntegerProperty totalIndex = new SimpleIntegerProperty(1);
|
||||
|
||||
private VBox vBox;
|
||||
|
||||
|
|
@ -72,22 +73,35 @@ public class ExamComponent extends ScrollPane {
|
|||
int total = jsonObject.getIntValue("total");
|
||||
int index = 1;
|
||||
|
||||
List<JSONObject> singleChoice_list = new ArrayList<>();
|
||||
List<JSONObject> multiChoice_list = new ArrayList<>();
|
||||
List<JSONObject> judgment_list = new ArrayList<>();
|
||||
List<JSONObject> numerical_list = new ArrayList<>();
|
||||
List<JSONObject> fillInBlank_list = new ArrayList<>();
|
||||
List<JSONObject> shortAnswer_list = new ArrayList<>();
|
||||
|
||||
for (Object datum : data) {
|
||||
JSONObject question = (JSONObject) datum;
|
||||
String type = question.getString("type");
|
||||
|
||||
switch (type) {
|
||||
case "单选题" -> singleChoice(question);
|
||||
case "多选题" -> multiChoice(question);
|
||||
case "判断题" -> judgment(question);
|
||||
case "计算题" -> numerical(question);
|
||||
case "填空题" -> fillInBlank(question);
|
||||
case "简答题" -> shortAnswer(question);
|
||||
case "单选题" -> singleChoice_list.add(question);
|
||||
case "多选题" -> multiChoice_list.add(question);
|
||||
case "判断题" -> judgment_list.add(question);
|
||||
case "计算题" -> numerical_list.add(question);
|
||||
case "填空题" -> fillInBlank_list.add(question);
|
||||
case "简答题" -> shortAnswer_list.add(question);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
singleChoice_list.forEach(this::singleChoice);
|
||||
multiChoice_list.forEach(this::multiChoice);
|
||||
judgment_list.forEach(this::judgment);
|
||||
numerical_list.forEach(this::numerical);
|
||||
fillInBlank_list.forEach(this::fillInBlank);
|
||||
shortAnswer_list.forEach(this::shortAnswer);
|
||||
|
||||
int count = singleChoiceComponents.size() + multiChoiceComponents.size() + judgmentComponents.size() + numericalComponents.size() + fillInBlankComponents.size() + shortAnswerComponents.size();
|
||||
totalCount.set(count);
|
||||
|
||||
|
|
@ -96,7 +110,6 @@ public class ExamComponent extends ScrollPane {
|
|||
// 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);
|
||||
|
|
@ -132,6 +145,7 @@ public class ExamComponent extends ScrollPane {
|
|||
|
||||
//简答题
|
||||
private void shortAnswer(JSONObject question) {
|
||||
SHORT_ANSWER_COUNT.set(totalIndex.get());
|
||||
String list = question.getString("options");
|
||||
List<Map> maps = JSONArray.parseArray(list, Map.class);
|
||||
List<Map<String, Object>> optionList = new ArrayList<>();
|
||||
|
|
@ -152,6 +166,7 @@ public class ExamComponent extends ScrollPane {
|
|||
shortAnswerComponent.setContext(context);
|
||||
shortAnswerComponents.add(shortAnswerComponent);
|
||||
SHORT_ANSWER_COUNT.set(SHORT_ANSWER_COUNT.get() + 1);
|
||||
totalIndex.set(totalIndex.get() + 1);
|
||||
}
|
||||
|
||||
//填空题
|
||||
|
|
@ -164,7 +179,7 @@ public class ExamComponent extends ScrollPane {
|
|||
|
||||
//判断题
|
||||
private void judgment(JSONObject question) {
|
||||
|
||||
JUDGMENT_COUNT.set(totalIndex.get());
|
||||
String list = question.getString("options");
|
||||
List<Map> maps = JSONArray.parseArray(list, Map.class);
|
||||
String correctAnswer = null;
|
||||
|
|
@ -186,6 +201,7 @@ public class ExamComponent extends ScrollPane {
|
|||
trueFalseComponent.setContext(context);
|
||||
judgmentComponents.add(trueFalseComponent);
|
||||
JUDGMENT_COUNT.set(JUDGMENT_COUNT.get() + 1);
|
||||
totalIndex.set(totalIndex.get() + 1);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +226,7 @@ public class ExamComponent extends ScrollPane {
|
|||
option.put("content", map.get("content").toString());
|
||||
optionList.add(option);
|
||||
}
|
||||
SingleChoiceComponent singleChoiceComponent = new SingleChoiceComponent(SINGLE_CHOICE_COUNT.get() + "." + question.getString("name"), optionList);
|
||||
SingleChoiceComponent singleChoiceComponent = new SingleChoiceComponent(SINGLE_CHOICE_COUNT.get() + "." + question.getString("name"), optionList,SINGLE_CHOICE_COUNT.get());
|
||||
singleChoiceComponent.setCorrectAnswer(correctAnswer);
|
||||
Map<String, Object> context = new HashMap<>();
|
||||
context.put("question_id", question.getString("id"));
|
||||
|
|
@ -218,6 +234,7 @@ public class ExamComponent extends ScrollPane {
|
|||
singleChoiceComponent.setContext(context);
|
||||
singleChoiceComponents.add(singleChoiceComponent);
|
||||
SINGLE_CHOICE_COUNT.set(SINGLE_CHOICE_COUNT.get() + 1);
|
||||
totalIndex.set(totalIndex.get() + 1);
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
|
|
@ -232,5 +249,7 @@ public class ExamComponent extends ScrollPane {
|
|||
this.vBox = vBox;
|
||||
}
|
||||
|
||||
|
||||
public Node getNode(int index){
|
||||
return this.vBox.getChildren().get(index-1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import java.util.List;
|
|||
*/
|
||||
public class FillBlankComponent extends VBox {
|
||||
|
||||
private Button indexButton;
|
||||
|
||||
// 题目数据模型
|
||||
private static class Question {
|
||||
String content; // 如 "Java中多线程可通过实现__1__接口或继承__2__类"
|
||||
|
|
@ -92,4 +94,12 @@ public class FillBlankComponent extends VBox {
|
|||
this.setPadding(new Insets(20));
|
||||
this.getChildren().addAll(questionBox, submitBtn, resultLabel);
|
||||
}
|
||||
|
||||
public Button getIndexButton() {
|
||||
return indexButton;
|
||||
}
|
||||
|
||||
public void setIndexButton(Button indexButton) {
|
||||
this.indexButton = indexButton;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,4 +86,9 @@ public class MultiChoiceComponent extends VBox {
|
|||
cb.setStyle("-fx-font-size: 14px; -fx-text-fill: #444;");
|
||||
return cb;
|
||||
}
|
||||
|
||||
public void setIndexButton(Button button) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,12 @@ import javafx.geometry.Insets;
|
|||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.Background;
|
||||
import javafx.scene.layout.BackgroundFill;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.Paint;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
|
@ -20,6 +24,8 @@ import java.util.*;
|
|||
*/
|
||||
public class ShortAnswerComponent extends VBox {
|
||||
|
||||
private Button indexButton;
|
||||
|
||||
private Map<String,Object> context = new HashMap<>();
|
||||
|
||||
public Map<String, Object> getContext() {
|
||||
|
|
@ -44,6 +50,20 @@ public class ShortAnswerComponent extends VBox {
|
|||
|
||||
private List<String> keywords = new ArrayList<>(); // 参考答案关键词(如 ["封装","继承","多态"])
|
||||
|
||||
private static final String DEFAULT_STYLE_CLASS = "button";
|
||||
|
||||
public void setBackground() {
|
||||
indexButton.getStyleClass().remove("custom-button-cancel");
|
||||
indexButton.getStyleClass().add("custom-button-click");
|
||||
}
|
||||
|
||||
//取消
|
||||
public void cancelBackground() {
|
||||
indexButton.getStyleClass().remove("custom-button-click");
|
||||
indexButton.getStyleClass().add("custom-button-cancel");
|
||||
}
|
||||
|
||||
|
||||
public ShortAnswerComponent(String question, List<Map<String, Object>> options) {
|
||||
|
||||
this.setStyle("-fx-background-color: white; -fx-border-color: #eadcdc;" +
|
||||
|
|
@ -68,6 +88,17 @@ public class ShortAnswerComponent extends VBox {
|
|||
answerArea.setWrapText(true); // 自动换行:ml-citation{ref="1" data="citationList"}
|
||||
this.getChildren().add(answerArea);
|
||||
|
||||
answerArea.textProperty().addListener(new ChangeListener<String>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
|
||||
if (newValue.length() > 0) {
|
||||
setBackground();
|
||||
}else {
|
||||
cancelBackground();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 功能组件
|
||||
Button submitBtn = new Button("提交答案");
|
||||
|
|
@ -117,4 +148,12 @@ public class ShortAnswerComponent extends VBox {
|
|||
this.hBox.getChildren().add(1,resultLabel);
|
||||
|
||||
}
|
||||
|
||||
public Button getIndexButton() {
|
||||
return indexButton;
|
||||
}
|
||||
|
||||
public void setIndexButton(Button indexButton) {
|
||||
this.indexButton = indexButton;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ import java.util.Map;
|
|||
*/
|
||||
public class SingleChoiceComponent extends VBox {
|
||||
|
||||
private String TYPE = "single_choice";
|
||||
|
||||
private Button indexButton;
|
||||
|
||||
private int index;//该组件索引
|
||||
|
||||
private Map<String,Object> context = new HashMap<>();
|
||||
|
||||
public Map<String, Object> getContext() {
|
||||
|
|
@ -47,8 +53,12 @@ public class SingleChoiceComponent extends VBox {
|
|||
|
||||
private Label questionLabel;
|
||||
|
||||
public SingleChoiceComponent(String question, List<Map<String, Object>> options) {
|
||||
public void setBackground() {
|
||||
this.indexButton.setStyle("-fx-background-color: #4698ed;");
|
||||
}
|
||||
|
||||
public SingleChoiceComponent(String question, List<Map<String, Object>> options,int index) {
|
||||
this.index = index;
|
||||
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;");
|
||||
|
||||
|
|
@ -120,6 +130,11 @@ public class SingleChoiceComponent extends VBox {
|
|||
result_answer.set(option.get("id").toString());
|
||||
//提交数据
|
||||
ApiUtils.submitAnswer(context);
|
||||
|
||||
//改变颜色
|
||||
setBackground();
|
||||
|
||||
|
||||
resultLabel.setText("你的选择:"+ option.get("option"));
|
||||
resultLabel.setStyle("-fx-text-fill: #2ecc71;");
|
||||
|
||||
|
|
@ -151,4 +166,29 @@ public class SingleChoiceComponent extends VBox {
|
|||
public void setCorrectAnswer(String correctAnswer) {
|
||||
this.correctAnswer = correctAnswer;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
|
||||
public String getTYPE() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public void setTYPE(String TYPE) {
|
||||
this.TYPE = TYPE;
|
||||
}
|
||||
|
||||
public Button getIndexButton() {
|
||||
return indexButton;
|
||||
}
|
||||
|
||||
public void setIndexButton(Button indexButton) {
|
||||
this.indexButton = indexButton;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import java.util.Map;
|
|||
*/
|
||||
public class TrueFalseComponent extends VBox {
|
||||
|
||||
private Button indexButton;
|
||||
|
||||
private static final String TRUE_TEXT = "✔ 正确";
|
||||
private static final String FALSE_TEXT = "✘ 错误";
|
||||
|
||||
|
|
@ -47,6 +49,10 @@ public class TrueFalseComponent extends VBox {
|
|||
private Label questionLabel;
|
||||
|
||||
|
||||
public void setBackground() {
|
||||
this.indexButton.setStyle("-fx-background-color: #4698ed;");
|
||||
}
|
||||
|
||||
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;");
|
||||
|
|
@ -112,6 +118,7 @@ public class TrueFalseComponent extends VBox {
|
|||
resultLabel.setText("你的选择:"+ FALSE_TEXT);
|
||||
}
|
||||
resultLabel.setStyle("-fx-text-fill: #2ecc71;");
|
||||
setBackground();
|
||||
} else {
|
||||
resultLabel.setText("⚠ 请先选择答案");
|
||||
}
|
||||
|
|
@ -131,4 +138,12 @@ public class TrueFalseComponent extends VBox {
|
|||
rb.setUserData(option);
|
||||
return rb;
|
||||
}
|
||||
|
||||
public Button getIndexButton() {
|
||||
return indexButton;
|
||||
}
|
||||
|
||||
public void setIndexButton(Button indexButton) {
|
||||
this.indexButton = indexButton;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
.custom-button-click {
|
||||
-fx-background-color: #4698ed;
|
||||
}
|
||||
|
||||
.custom-button-cancel {
|
||||
-fx-background-color: #dadada43; /* 默认背景色 */
|
||||
-fx-border-color: #7e7676;
|
||||
-fx-border-width: 0.5px; /* 默认边框颜色 */
|
||||
-fx-border-radius: 3px; /* 默认边框圆角 */
|
||||
}
|
||||
|
||||
.custom-button-cancel:focused {
|
||||
-fx-background-color: derive(#e6e6e6, 20%); /* 焦点时略微变亮 */
|
||||
-fx-border-color: #0096C9;
|
||||
-fx-border-width: 1.5px; /* 默认边框颜色 */
|
||||
}
|
||||
|
||||
.custom-button-cancel:hover {
|
||||
-fx-background-color: derive(#dadada, 20%); /* 鼠标悬停时略微变亮 */
|
||||
}
|
||||
Loading…
Reference in New Issue