2015-05-12 3 views
5

Надеюсь, я не дублирую вопрос, но я не мог найти его специально для моей проблемы. Я разрабатываю небольшое приложение для флеш-карт, используя JavaFX для создания графического интерфейса. Программа должна работает следующим образом:Подождите, а затем получите ввод текстового поля без замораживания GUI

  1. пользователь выбирает настройки, а затем нажимает начала кнопку.
  2. gui отображает вопрос и текстовое поле для ввода пользователем.
  3. пользовательские входы отвечают в течение X секунд или gui автоматически переходят к следующему вопросу - в качестве альтернативы, пользователь может сразу перейти к следующему вопросу, нажав следующий.
  4. GUI отображает оценку и среднее значение.

проблемы является getText() от пользователя TextField обрабатывается как только начала нажата кнопка, не давая пользователю возможность ввести ответ. Как заставить программу ждать X секунд или для кнопки , следующей за кнопкой, которую нужно нажать перед обработкой ответа пользователя? Вот мой код:

//start button changes view and then runs startTest() 
start.setOnAction(e -> { 

     setLeft(null); 
     setRight(null); 

     setCenter(test_container); 
     running_program_title.setText(getDifficulty().name() + " Test"); 
     buttons_container.getChildren().clear(); 
     buttons_container.getChildren().addAll(next, quit, submit); 

     startTest(); 
    }); 

Вот код проблемы ... по крайней мере, как я его вижу.

//startTest method calls askAdd() to ask an addition question 
void startTest() { 

    int asked = 0; 
    int correct = 0; 

    while (asked < numberOfQuestions) { 
     if(askAdd()){ 
     correct++; 
     asked++; 
    } 
} 

boolean askAdd() { 

    int a = (int) (Math.random() * getMultiplier()); 
    int b = (int) (Math.random() * getMultiplier()); 

    //ask question 
    question.setText("What is " + a + " + " + b + "?"); 

    //code needed to pause method and wait for user input for X seconds 

    //retrieve user answer and return if its correct 
    return answer.getText().equalsIgnoreCase(String.valueOf(a+b)); 
} 

Я попытался с помощью Thread.sleep(X) но замораживает графический интерфейс для сколь угодно долго я указываю, а затем проходит через метод addAsk() и петли перед выходом на экран тестирования. (Я знаю, потому что у меня была программа, предназначенная для печати вопросов и ответов на консоль). Он показывает последний вопрос, и все.

Я не включил следующий код, потому что я не могу заставить gui перейти на тестовую страницу в любом случае.

Любая помощь по любому из кодов оценивается.

ответ

0

Для таймера вы должны (IMO) использовать Timeline. Вот пример:

public class MultiGame extends Application { 
    ProgressBar progressBar; 

    final int allowedTime = 5; //seconds 
    final DoubleProperty percentOfTimeUsed = new SimpleDoubleProperty(0); 
    final Timeline timer = 
      new Timeline(
       new KeyFrame(
         Duration.ZERO, new KeyValue(percentOfTimeUsed, 0)), 
       new KeyFrame(
         Duration.seconds(allowedTime), new KeyValue(percentOfTimeUsed, 1)) 
      ); 

    public static void main(String[] args) { 
     launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) { 
     BorderPane root = new BorderPane(); 

     progressBar = new ProgressBar(); 
     progressBar.progressProperty().bindBidirectional(percentOfTimeUsed); 
     root.setTop(progressBar); 

     Button answer = new Button("Answer"); 
     answer.setOnAction(ae -> restart());// the on answer handler 

     Button skip = new Button("Skip"); 
     skip.setOnAction(ae -> restart());// the skip question handler 

     HBox mainContent = new HBox(15, 
       new Label("Your Question"), new TextField("The answer"), answer, skip); 
     root.setCenter(mainContent); 

     timer.setOnFinished(ae -> restart());// the end of timer handler 

     primaryStage.setScene(new Scene(root)); 
     primaryStage.show(); 

     restart(); 
    } 

    void restart() { timer.stop(); timer.playFromStart(); } 

    void pause() { timer.pause(); } 

    void resume() { timer.play(); } 
} 

Вам просто нужно, чтобы захватить текст от входа в между начальным временной шкалой и методой restart.

+0

У вас есть несколько недоразумений в своем ответе. Вероятно, вы хотите установить разрешенное время на пять секунд, а не на 500 секунд. ['ProgressProperty'] (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ProgressIndicator.html#progressProperty--) должно быть числом от нуля до единицы, поэтому вы не должен двунаправленно связывать его со значением, которое варьируется от нуля до ста. Здесь предпочтительнее однонаправленное связывание: 'progressBar.progressProperty(). Bind (percentOfTimeUsed.divide (100.0));' – jewelsea

+0

@jewelsea Это объясняет проблему с допустимым временем - Спасибо, что указали это. Пример сверху. –

+0

Именно то, что я искал. Спасибо. – gabe2390

1

Это может быть достигнуто различными способами.

PauseTransition является одним из множества современных решений. Он ждет X time interval, а затем выполняет команду Task. Он может start, restart, stop at any moment.

Вот пример того, как он может использоваться для достижения аналогичного результата.

enter image description here

Полный код

import javafx.animation.PauseTransition; 
import javafx.application.Application; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.event.ActionEvent; 
import javafx.geometry.Insets; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.control.ScrollPane; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.HBox; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

import java.util.stream.IntStream; 

public class Main extends Application { 

    int questionIndex = 0; 
    int noOfQuestions = 10; 

    @Override 
    public void start(Stage stage) { 

     VBox box = new VBox(10); 
     box.setPadding(new Insets(10)); 
     Scene scene = new Scene(new ScrollPane(box), 500, 200); 
     ObservableList<String> questions = 
       FXCollections.observableArrayList("1) Whats your (full) name?", 
                "2) How old are you?", 
                "3) Whats your Birthday?", 
                "4) What starsign does that make it?", 
                "5) Whats your favourite colour?", 
                "6) Whats your lucky number?", 
                "7) Do you have any pets?", 
                "8) Where are you from?", 
                "9) How tall are you?", 
                "10) What shoe size are you?"); 

     ObservableList<String> answers = FXCollections.observableArrayList(); 

     final PauseTransition pt = new PauseTransition(Duration.millis(5000)); 

     Label questionLabel = new Label(questions.get(questionIndex)); 
     Label timerLabel = new Label("Time Remaining : "); 
     Label time = new Label(); 
     time.setStyle("-fx-text-fill: RED"); 
     TextField answerField = new TextField(); 

     Button nextQuestion = new Button("Next"); 

     pt.currentTimeProperty().addListener(new ChangeListener<Duration>() { 
      @Override 
      public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) { 
       time.setText(String.valueOf(5 - (int)newValue.toSeconds())); 
      } 
     }); 

     box.getChildren().addAll(questionLabel, answerField, new HBox(timerLabel, time), nextQuestion); 

     nextQuestion.setOnAction((ActionEvent event) -> { 
      answers.add(questionIndex, answerField.getText()); 

      //Check if it is the last question 
      if(questionIndex == noOfQuestions-1) { 
       pt.stop(); 
       box.getChildren().clear(); 
       IntStream.range(0, noOfQuestions).forEach(i -> { 
        Label question = new Label("Question : " + questions.get(i)); 
        question.setStyle("-fx-text-fill: RED"); 
        Label answer = new Label("Answer : " + answers.get(i)); 
        answer.setStyle("-fx-text-fill: GREEN"); 
        box.getChildren().addAll(question, answer); 
       }); 
      } 
      // All other time 
      else { 
       //Set new question 
       questionLabel.setText(questions.get(++questionIndex)); 
       answerField.clear(); 
       pt.playFromStart(); 
      } 
     }); 

     pt.setOnFinished((ActionEvent event) -> { 
      nextQuestion.fire(); 
     }); 
     pt.play(); 

     stage.setScene(scene); 
     stage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
}