按钮与试题绑定,动态生效 2025年3月21日17:37:36

master
qmstyle 2025-03-21 17:37:47 +08:00
parent b131f7da38
commit 3a6c6d1f1d
8 changed files with 186 additions and 15 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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) {
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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%); /* 鼠标悬停时略微变亮 */
}