mirror of
https://gitlab.com/kauron/jstudy
synced 2024-12-22 08:23:33 +01:00
Test: added stats (time, answer and q/a) after test.
This commit is contained in:
parent
56e1e42d65
commit
2f82568f46
6 changed files with 124 additions and 12 deletions
|
@ -1,6 +1,7 @@
|
|||
package es.kauron.jstudy.controller;
|
||||
|
||||
import es.kauron.jstudy.Main;
|
||||
import es.kauron.jstudy.model.AnsweredItem;
|
||||
import es.kauron.jstudy.model.AppPrefs;
|
||||
import es.kauron.jstudy.model.TestItem;
|
||||
import javafx.application.Platform;
|
||||
|
@ -356,7 +357,7 @@ public class Controller implements Initializable {
|
|||
FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/test.fxml"));
|
||||
Parent root = loader.load();
|
||||
|
||||
((TestController) loader.getController()).setList(new ArrayList<>(list));
|
||||
((TestController) loader.getController()).setData(new ArrayList<>(list), this);
|
||||
|
||||
theTest = new Tab("Test: " + tabPane.getSelectionModel().getSelectedItem().getText(), root);
|
||||
tabPane.getTabs().add(theTest);
|
||||
|
@ -367,6 +368,20 @@ public class Controller implements Initializable {
|
|||
}
|
||||
}
|
||||
|
||||
void createStatsTab(List<AnsweredItem> answers) {
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/stats.fxml"));
|
||||
Parent root = loader.load();
|
||||
((StatsController) loader.getController()).setData(answers);
|
||||
Matcher m = Pattern.compile("^Test: (.*)$").matcher(tabPane.getSelectionModel().getSelectedItem().getText());
|
||||
m.find();
|
||||
tabPane.getTabs().add(new Tab("Stats: " + m.group(1), root));
|
||||
tabPane.getSelectionModel().selectLast();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
protected void onAboutAction(ActionEvent event) {
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package es.kauron.jstudy.controller;
|
||||
|
||||
import es.kauron.jstudy.model.AnsweredItem;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableRow;
|
||||
import javafx.scene.control.TableView;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class StatsController implements Initializable {
|
||||
@FXML
|
||||
protected TableView<AnsweredItem> table;
|
||||
|
||||
@FXML
|
||||
protected TableColumn<AnsweredItem, String> numCol, questionCol, answerCol, userAnswerCol, timeCol;
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
numCol.setCellValueFactory(e -> e.getValue().indexProperty.asString());
|
||||
questionCol.setCellValueFactory(e -> e.getValue().item.questionProperty());
|
||||
answerCol.setCellValueFactory(e -> e.getValue().item.answerProperty());
|
||||
userAnswerCol.setCellValueFactory(e -> e.getValue().answerProperty);
|
||||
timeCol.setCellValueFactory(e -> Bindings.format("%.3f", e.getValue().timeProperty.divide(1e9)));
|
||||
}
|
||||
|
||||
public void setData(List<AnsweredItem> answers) {
|
||||
table.setItems(FXCollections.observableArrayList(answers));
|
||||
// Set wrong answers in bold
|
||||
table.setRowFactory(param -> {
|
||||
TableRow<AnsweredItem> row = new TableRow<>();
|
||||
row.itemProperty().addListener((obj, o, n) ->
|
||||
row.setStyle(n == null || n.isRight() ? "" : "-fx-font-weight: bold"));
|
||||
return row;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package es.kauron.jstudy.controller;
|
||||
|
||||
import es.kauron.jstudy.model.AnsweredItem;
|
||||
import es.kauron.jstudy.model.AppPrefs;
|
||||
import es.kauron.jstudy.model.TestItem;
|
||||
import es.kauron.jstudy.util.Clock;
|
||||
|
@ -12,6 +13,7 @@ import javafx.scene.control.*;
|
|||
import javafx.scene.layout.Pane;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
|
@ -36,6 +38,9 @@ public class TestController implements Initializable {
|
|||
private final IntegerProperty errors = new SimpleIntegerProperty(0);
|
||||
private final ObjectProperty<TestItem> item = new SimpleObjectProperty<>();
|
||||
private final IntegerProperty done = new SimpleIntegerProperty(0);
|
||||
private final List<AnsweredItem> answers = new ArrayList<>();
|
||||
private long timeQuestionStarted = 0;
|
||||
private Controller controller;
|
||||
// Time accounting
|
||||
private final Clock clock = new Clock();
|
||||
|
||||
|
@ -51,7 +56,8 @@ public class TestController implements Initializable {
|
|||
});
|
||||
}
|
||||
|
||||
void setList(List<TestItem> list) {
|
||||
void setData(List<TestItem> list, Controller controller) {
|
||||
this.controller = controller;
|
||||
this.list = list;
|
||||
int total = list.size();
|
||||
progressLabel.textProperty().bind(Bindings.format(
|
||||
|
@ -72,13 +78,18 @@ public class TestController implements Initializable {
|
|||
|
||||
@FXML
|
||||
private void onNextAction(ActionEvent event) {
|
||||
// Do not accept empty responses
|
||||
if (answer.getText().trim().isEmpty()) return;
|
||||
// Record the answer
|
||||
long timeElapsed = System.nanoTime() - timeQuestionStarted;
|
||||
AnsweredItem ai = new AnsweredItem(item.get(), answers.size() + 1, answer.getText().trim(), timeElapsed);
|
||||
answers.add(ai);
|
||||
prevAnswer.setText(answer.getText());
|
||||
|
||||
boolean right = item.get().checkAnswer(answer.getText());
|
||||
correctAnswer.setVisible(!right);
|
||||
correctLabel.setVisible(!right);
|
||||
correctAnswer.setVisible(!ai.isRight());
|
||||
correctLabel.setVisible(!ai.isRight());
|
||||
|
||||
if (!right) {
|
||||
if (!ai.isRight()) {
|
||||
errors.set(errors.get() + 1);
|
||||
prevAnswer.setStyle("-fx-text-fill: #C40000;");
|
||||
} else {
|
||||
|
@ -86,10 +97,10 @@ public class TestController implements Initializable {
|
|||
}
|
||||
|
||||
// Remove the question from the pool if the question was correctly answered or there is no repetition
|
||||
if (right || !AppPrefs.repeatWrong.get()) {
|
||||
if (ai.isRight() || !AppPrefs.repeatWrong.get()) {
|
||||
if (!correctingError.get())
|
||||
done.set(done.get() + 1);
|
||||
correctingError.set(!right && AppPrefs.repeatImmediately.get());
|
||||
correctingError.set(!ai.isRight() && AppPrefs.repeatImmediately.get());
|
||||
list.remove(item.get());
|
||||
if (list.size() == 0) {
|
||||
onEndAction(null);
|
||||
|
@ -105,6 +116,7 @@ public class TestController implements Initializable {
|
|||
}
|
||||
answer.setText("");
|
||||
answer.requestFocus();
|
||||
timeQuestionStarted = System.nanoTime();
|
||||
}
|
||||
|
||||
private void chooseQuestion() {
|
||||
|
@ -121,6 +133,7 @@ public class TestController implements Initializable {
|
|||
chooseQuestion();
|
||||
answer.setText("");
|
||||
answer.requestFocus();
|
||||
timeQuestionStarted = System.nanoTime();
|
||||
}
|
||||
|
||||
@FXML
|
||||
|
@ -130,6 +143,7 @@ public class TestController implements Initializable {
|
|||
pauseCheckBox.setSelected(true);
|
||||
pauseCheckBox.setDisable(true);
|
||||
clock.stop();
|
||||
controller.createStatsTab(answers);
|
||||
}
|
||||
|
||||
void stopTimer() {
|
||||
|
|
24
src/main/java/es/kauron/jstudy/model/AnsweredItem.java
Normal file
24
src/main/java/es/kauron/jstudy/model/AnsweredItem.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package es.kauron.jstudy.model;
|
||||
|
||||
import javafx.beans.property.ReadOnlyIntegerProperty;
|
||||
import javafx.beans.property.ReadOnlyIntegerWrapper;
|
||||
import javafx.beans.property.ReadOnlyLongWrapper;
|
||||
import javafx.beans.property.ReadOnlyStringWrapper;
|
||||
|
||||
public class AnsweredItem {
|
||||
public final ReadOnlyStringWrapper answerProperty;
|
||||
public final ReadOnlyLongWrapper timeProperty;
|
||||
public final ReadOnlyIntegerProperty indexProperty;
|
||||
public final TestItem item;
|
||||
|
||||
public AnsweredItem(TestItem item, int index, String answer, long timeNano) {
|
||||
this.item = item;
|
||||
this.indexProperty = new ReadOnlyIntegerWrapper(index);
|
||||
this.answerProperty = new ReadOnlyStringWrapper(answer);
|
||||
this.timeProperty = new ReadOnlyLongWrapper(timeNano);
|
||||
}
|
||||
|
||||
public boolean isRight() {
|
||||
return item.getAnswer().equals(answerProperty.get());
|
||||
}
|
||||
}
|
|
@ -49,10 +49,6 @@ public class TestItem {
|
|||
return !question.get().isEmpty() && !answer.get().isEmpty();
|
||||
}
|
||||
|
||||
public boolean checkAnswer(String answer) {
|
||||
return getAnswer().equals(answer);
|
||||
}
|
||||
|
||||
public static void saveTo(File file, List<TestItem> data) {
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(
|
||||
new FileOutputStream(file), StandardCharsets.UTF_8.newEncoder())) {
|
||||
|
|
21
src/main/resources/es/kauron/jstudy/view/stats.fxml
Normal file
21
src/main/resources/es/kauron/jstudy/view/stats.fxml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<VBox xmlns="http://javafx.com/javafx/8.0.202-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="es.kauron.jstudy.controller.StatsController">
|
||||
<children>
|
||||
<TableView fx:id="table" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="400.0" HBox.hgrow="ALWAYS" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="numCol" text="#" style="-fx-alignment: CENTER-RIGHT" />
|
||||
<TableColumn fx:id="questionCol" prefWidth="75.0" text="Question" />
|
||||
<TableColumn fx:id="answerCol" prefWidth="75.0" text="Correct answer" />
|
||||
<TableColumn fx:id="userAnswerCol" prefWidth="75.0" text="Your answer" />
|
||||
<TableColumn fx:id="timeCol" prefWidth="15.0" text="Time" style="-fx-alignment: CENTER-RIGHT" />
|
||||
</columns>
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
|
||||
</columnResizePolicy>
|
||||
</TableView>
|
||||
</children>
|
||||
</VBox>
|
Loading…
Reference in a new issue