2013-12-11 3 views
0

У меня есть этот пример со списком с индикаторами выполнения.Combobox with Progress bar работает неправильно

package javafxapplication4; 

import javafx.application.Application; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.ComboBox; 
import javafx.scene.control.Label; 
import javafx.scene.control.ListCell; 
import javafx.scene.control.ListView; 
import javafx.scene.control.ProgressBar; 
import javafx.scene.layout.StackPane; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 
import javafx.util.Callback; 


public class JavaFXApplication4 extends Application 
{ 

    @Override 
    public void start(Stage primaryStage) 
    { 

    double y1 = 15; 
     ProgressBar p1 = new ProgressBar(); 
     p1.setLayoutY(y1); 
    VBox vb1 = new VBox(); 
    vb1.getChildren().addAll(new Label("Progressbar 1"), p1); 

    double y2 = 15; 
     ProgressBar p2 = new ProgressBar(); 
     p2.setLayoutY(y2); 
    VBox vb2 = new VBox(); 
    vb2.getChildren().addAll(new Label("Progressbar 2"), p2); 

    double y3 = 15; 
     ProgressBar p3 = new ProgressBar(); 
     p3.setLayoutY(y3); 
    VBox vb3 = new VBox(); 
    vb3.getChildren().addAll(new Label("Progressbar 3"), p3); 


    TextChooser textChooser = new TextChooser(
     vb1, vb2, vb3 
    ); 

    textChooser.setStyle("-fx-font: 10px \"Verdana\";"); 





     StackPane root = new StackPane(); 
     root.getChildren().add(textChooser); 

     Scene scene = new Scene(root, 300, 250); 

     primaryStage.setTitle("Hello World!"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 


    public static class TextChooser extends StackPane { 
    private Label label = new Label(); 

    private ComboBox<VBox> combo = new ComboBox<>(); 

    public TextChooser(VBox... options) { 
     StackPane.setAlignment(label, Pos.CENTER_LEFT); 
     StackPane.setAlignment(combo, Pos.CENTER_LEFT); 

     label.graphicProperty().bind(
      //combo.getSelectionModel().selectedItemProperty() 
      combo.getSelectionModel().selectedItemProperty() 
     ); 
     label.visibleProperty().bind(
      combo.visibleProperty().not() 
     ); 
     //label.setPadding(new Insets(0, 0, 0, 10)); 

     combo.getItems().setAll(options); 

     combo.setCellFactory(new Callback<ListView<VBox>, ListCell<VBox>>() { 
      @Override public ListCell<VBox> call(ListView<VBox> p) { 
       return new ListCell<VBox>() { 
        @Override protected void updateItem(VBox item, boolean empty) { 
         super.updateItem(item, empty); 

         if (item == null || empty) { 
          setGraphic(null); 
         } else { 
          setGraphic(item); 
         } 
        } 
       }; 
      } 
     }); 

     combo.getSelectionModel().select(0); 
     combo.setVisible(true); 

     label.setOnMouseEntered(event -> combo.setVisible(true)); 
     combo.showingProperty().addListener(observable -> { 
      if (!combo.isShowing()) { 
       combo.setVisible(false); 
      } 
     }); 
     combo.setOnMouseExited(event -> { 
      if (!combo.isShowing()) { 
       combo.setVisible(false); 
      } 
     }); 

     getChildren().setAll(label, combo); 
    } 

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

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

ответ

2

Как писал здесь https://stackoverflow.com/a/20630806/3110608

public class JavaFXApplication5 extends Application 
{ 
    public static void main(String[] args) 
    { 
     launch(args); 
    } 


    public class ProgressData 
    { 
     private final DoubleProperty progressProp = new SimpleDoubleProperty(); 
     private final StringProperty progressName = new SimpleStringProperty(); 

     public ProgressData(String name, double progress) 
     { 
      progressProp.set(progress); 
      progressName.set(name); 
     } 

     public DoubleProperty progressProperty() 
     { 
      return progressProp; 
     } 

     public StringProperty nameProperty() 
     { 
      return progressName; 
     } 

     @Override 
     // Lazy hack for the combo button. 
     public String toString() 
     { 
      return progressName.get(); 
     } 
    } 


    @Override 
    public void start(Stage primaryStage) 
    { 
     ProgressData vb1 = new ProgressData("Progressbar 1", -1); 
     ProgressData vb2 = new ProgressData("Progressbar 2", 0.2); 
     ProgressData vb3 = new ProgressData("Progressbar 3", 0.3); 

     TextChooser textChooser = new TextChooser(vb1, vb2, vb3); 

     textChooser.setStyle("-fx-font: 10px \"Verdana\";"); 

     StackPane root = new StackPane(); 
     root.getChildren().add(textChooser); 

     Scene scene = new Scene(root, 300, 250); 

     primaryStage.setTitle("Hello World!"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public static class TextChooser extends StackPane 
    { 
     private final Label label = new Label(); 

     private final ComboBox<ProgressData> combo = new ComboBox<>(); 

     public TextChooser(ProgressData... options) 
     { 
      StackPane.setAlignment(label, Pos.CENTER_LEFT); 
      StackPane.setAlignment(combo, Pos.CENTER_LEFT); 


      final ProgressBar labelBar = new ProgressBar(); 
      label.visibleProperty().bind(combo.visibleProperty().not()); 
      label.setContentDisplay(ContentDisplay.RIGHT); 
      label.setGraphic(labelBar); 


      combo.getItems().setAll(options); 

      // This will change the label's text and the progress bar value. 
      combo.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<ProgressData>() 
      { 
       @Override 
       public void changed(ObservableValue<? extends ProgressData> observable, ProgressData oldValue, ProgressData newValue) 
       { 
        if (labelBar.progressProperty().isBound()) 
        { 
         labelBar.progressProperty().unbind(); 
        } 

        labelBar.progressProperty().bind(newValue.progressProperty()); 
        label.setText(newValue.nameProperty().get()); 
       } 
      }); 

      combo.setCellFactory(new Callback<ListView<ProgressData>, ListCell<ProgressData>>() 
      { 
       @Override 
       public ListCell<ProgressData> call(ListView<ProgressData> p) 
       { 
        return new ListCell<ProgressData>() 
        { 
         private final ProgressBar cellBar = new ProgressBar(); 
         { 
          cellBar.setMouseTransparent(true); 
          setContentDisplay(ContentDisplay.RIGHT); 
          setGraphic(cellBar); 
         } 

         @Override 
         protected void updateItem(ProgressData item, boolean empty) 
         { 
          super.updateItem(item, empty); 

          if (item != null && ! empty) 
          { 
           if (cellBar.progressProperty().isBound()) 
           { 
            cellBar.progressProperty().unbind(); 
           } 
           cellBar.progressProperty().bind(item.progressProperty()); 
           setText(item.nameProperty().get()); 
          } 
         } 
        }; 
       } 
      }); 

      combo.getSelectionModel().select(0); 
      combo.setVisible(true); 

      label.setOnMouseEntered(new EventHandler<MouseEvent>() 
      { 
       @Override 
       public void handle(MouseEvent event) 
       { 
        combo.setVisible(true); 
       } 
      }); 

      combo.showingProperty().addListener(new InvalidationListener() 
      { 
       @Override 
       public void invalidated(Observable observable) 
       { 
        if (!combo.isShowing()) 
        { 
         combo.setVisible(false); 
        } 
       } 
      }); 

      combo.setOnMouseExited(new EventHandler<MouseEvent>() 
      { 
       @Override 
       public void handle(MouseEvent event) 
       { 
        if (!combo.isShowing()) 
        { 
         combo.setVisible(false); 
        } 
       } 
      }); 

      getChildren().setAll(label, combo); 
     } 

    } 

} 
+0

Очень хороший пример. Спасибо! –

3

Чтобы изменить отображение в «кнопки» (то есть дисплей для выбранного значения), необходимо использовать

combo.setButtonCell(...); 

Я не думаю, что он будет работать в вашем случае, однако. Проблема в том, что у вас есть подкласс Node (VBox) как тип для вашего ComboBox. Следовательно, выбранный элемент будет отображаться в двух местах графика сцены: один раз в выпадающем списке и один раз в кнопке ComboBox. В общем, это действительно плохая идея использовать узлы в качестве типа в поле со списком: см Javadocs:

узлов в реализация концепции списке элементов является настоятельно не рекомендуется.

Вместо этого вы должны использовать тип данных для ComboBox и создать VBox в реализациях ListCell.

+0

Не могли бы вы показать мне, как это исправить код. Это очень продвинуто для меня. –

+0

Просто посмотрите пример в Javadocs. Здесь также показан пример выполнения фоновых задач на https://gist.github.com/james-d/7722752. В этом примере используется ListView вместо ComboBox, но основная идея схожа. –

+0

Я не могу решить эту проблему. Можете ли вы изменить мое редактирование и исправить проблему? –