2016-08-26 5 views
0

Рассмотрите следующий MCVE. Конечно, функциональность этого MCVE совершенно бессмысленна, но мне нужно, чтобы он работал таким образом в реальной реализации.Stage.show() изменяет значение ComboBox

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.concurrent.Task; 
import javafx.scene.Scene; 
import javafx.scene.control.ComboBox; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 

@SuppressWarnings("all") 
public class MCVE extends Application { 

    private static final String OPTION_1 = "Option 1 (www.option1.com)"; 
    private static final String OPTION_2 = "Option 2 (www.option2.com)"; 
    private static final String OPTION_3 = "Option 3 (www.option3.com)"; 
    private static final String OPTION_4 = "Option 4 (www.option4.com)"; 
    private static final String OPTION_5 = "Option 5 (www.option5.com)"; 

    ComboBox<String> cb; 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     VBox outer = new VBox(); 

     cb = new ComboBox<String>(); 
     outer.getChildren().add(cb); 

     Scene scene = new Scene(outer, 640, 480); 
     primaryStage.setScene(scene); 

     Task<Void> task = new Task<Void>() { 
      @Override 
      public Void call() { 
       cb.getItems().addAll(OPTION_1, OPTION_2, OPTION_3, OPTION_4, OPTION_5); 
       cb.setEditable(true); 

       // Adds a listener to the selectedItemProperty that gets the 
       // value inside the parenthesis of the selected item and sets 
       // this as the text of the ComboBox. 
       cb.getSelectionModel().selectedItemProperty().addListener((obs, oldValue, newValue) -> { 
        String[] valSplit = newValue.split("[\\(\\)]"); 
        if (valSplit.length > 1) { 
         Platform.runLater(() -> cb.getEditor().setText(valSplit[1])); 
        } 
       }); 

       cb.getEditor().textProperty().addListener((obs, oldValue, newValue) -> { 
        System.out.println("CB value: " + newValue); 
       }); 

       setURL("www.option2.com"); 

       return null; 
      } 
     }; 

     task.setOnSucceeded(e -> { 
      primaryStage.show(); 
     }); 

     new Thread(task).start(); 
    } 

    public void setURL(String url) { 
     // First we check if the classValue is the URL of one of the options in 
     // the ComboBox. If it is we select that option. 
     for (String option : cb.getItems()) { 
      // We retrieve the URL of the option. 
      String opURL = option.split("[\\(\\)]")[1]; 
      // If the URL of the option is equals to the provided URL, we select 
      // this option and break the for loop. 
      if (opURL.equals(url)) { 
       cb.getSelectionModel().select(option); 
       break; 
      } 
     } 
    } 

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

Поскольку я призываю setURL("www.option2.com"), я ожидаю, что сначала выбрать опцию в ComboBox с этим URL, а затем получить значение внутри скобок и установить, что в тексте ComboBox. Поэтому я исключаю окончательное значение ComboBox как «www.option2.com». Но этого не происходит. Вместо этого конечным значением является «Вариант 2 (www.option2.com)».

Поскольку я добавил слушателя в textProperty из ComboBox, я вижу, что это значение является первым ожидаемым «www.option2.com», но затем возвращается к «Варианту 2 (www.option2.com) ». После некоторого дальнейшего исследования я обнаружил, что это вызов primaryStage.show(), который изменяет значение. Более конкретно, это вызов устаревшего Parent.impl_processCSS, который изменяет значение.

Так что, если я установил URL-адрес после primaryStage.show(), все работает как я, кроме. Но если я хочу выполнить всю работу до того, как я покажу диалог, как и сейчас, это не так.

Так почему же primaryStage.show() измените значение моего ComboBox и как я могу предотвратить это? Должен ли я использовать другой подход при попытке установить значение ComboBox?

ответ

1

Вы можете обменять часть вас код, который устанавливает текст editor в ComboBox с некоторым кодом, который устанавливает cell factory и converter.

cb.setConverter(new StringConverter<String>(){ 
    @Override 
    public String toString(String object) { 
     if(object != null) { 
      String[] valSplit = object.split("[\\(\\)]"); 
      return valSplit[1]; 
     } else 
      return null; 

    } 

    @Override 
    public String fromString(String string) { 

     List<String> collect = cb.getItems().stream().filter(s -> s.contains(string)).collect(Collectors.toList()); 
     if(collect.size() == 1) 
      return collect.get(0); 
     else 
      return null; 
    } 
}); 

cb.setCellFactory(item -> { 
    return new ListCell<String>(){ 
     @Override 
     protected void updateItem(String item, boolean empty) { 
      super.updateItem(item, empty); 

      if(item == null || empty) 
       setText(""); 
      else 
       setText(item); 
     } 
    }; 
}); 

toString метод конверторе будет форматировать выбранный элемент в нужной форме, и клетка завод гарантирует, что элементы в выпадающем списке отображаются в оригинальном формате.

Примечание: Я также заполнил метод преобразователя fromString. Этот метод выполняется, когда пользователь вводит в редактор, затем нажимает enter. Эта реализация проверяет все элементы в списке, и если есть только один элемент, который содержит введенную строку, этот элемент будет выбран.

 Смежные вопросы

  • Нет связанных вопросов^_^