Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8117829

Jittery Stage Resizing

    XMLWordPrintable

Details

    • Bug
    • Resolution: Duplicate
    • P4
    • None
    • 8
    • javafx
    • None
    • JavaFX 8.0.0-ea-b92; Windows 7 64-bit

    Description

      Run the following, and resize the window horizontally. The listview, its contents and the label on the right are unstable and take on different positions.

      package hs.mediasystem;

      import java.util.ArrayList;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;

      import javafx.application.Application;
      import javafx.beans.InvalidationListener;
      import javafx.beans.Observable;
      import javafx.beans.WeakInvalidationListener;
      import javafx.beans.binding.Bindings;
      import javafx.beans.binding.BooleanBinding;
      import javafx.beans.binding.BooleanExpression;
      import javafx.beans.binding.ObjectBinding;
      import javafx.beans.binding.StringBinding;
      import javafx.beans.property.BooleanProperty;
      import javafx.beans.property.IntegerProperty;
      import javafx.beans.property.ObjectProperty;
      import javafx.beans.property.Property;
      import javafx.beans.property.SimpleBooleanProperty;
      import javafx.beans.property.SimpleIntegerProperty;
      import javafx.beans.property.SimpleObjectProperty;
      import javafx.beans.property.SimpleStringProperty;
      import javafx.beans.property.StringProperty;
      import javafx.beans.value.ChangeListener;
      import javafx.beans.value.ObservableValue;
      import javafx.collections.FXCollections;
      import javafx.collections.ListChangeListener;
      import javafx.collections.ObservableList;
      import javafx.collections.WeakListChangeListener;
      import javafx.geometry.Pos;
      import javafx.scene.Node;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.control.Label;
      import javafx.scene.control.ListView;
      import javafx.scene.layout.HBox;
      import javafx.scene.layout.Pane;
      import javafx.scene.layout.TilePane;
      import javafx.scene.layout.VBox;
      import javafx.stage.Stage;

      public class TitledBlockSample extends Application {
        private final ObjectProperty<Media> data = new SimpleObjectProperty<>();
        public ObjectProperty<Media> dataProperty() { return data; }

        protected final ObjectBinding<ObservableList<Casting>> castings = Bindings.select(dataProperty(), "castings");

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

        @Override
        public void start(Stage stage) throws Exception {
          VBox vbox = new VBox();
          HBox hbox = new HBox();

          ListView<Media> listView = new ListView<>();

          listView.getItems().add(new Media("Some title"));

          for(int i = 0; i < 1000; i++) {
            Media media = new Media("Title #" + i);

            ObservableList<Casting> list = FXCollections.observableArrayList();

            list.add(new Casting() {{
              characterName.set("Bambi");
            }});

            media.castings.set(list);
            listView.getItems().add(media);
          }

          data.bind(listView.getFocusModel().focusedItemProperty());

          CastingsRow castingsRow = createCastingsRow();

          vbox.getChildren().add(new Label("Detailed Information About the Selected Item:"));
          vbox.getChildren().add(createTitledBlock("Title", castingsRow, castingsRow.empty.not()));

          hbox.getChildren().addAll(vbox, listView);

          stage.setScene(new Scene(hbox));
      // stage.getScene().getStylesheets().add("default.css");
      // stage.getScene().getStylesheets().add("select-media/detail-pane.css");
      // stage.getScene().getStylesheets().add("select-media/media-detail-pane.css");

          stage.setWidth(1024);
          stage.setHeight(600);
          stage.show();
        }

        protected Pane createTitledBlock(final String title, final Node content, final BooleanExpression visibleCondition) {
          return new VBox() {{
            setFillWidth(true);
            getChildren().add(new Label(title) {{
              getStyleClass().add("header");
            }});
            getChildren().add(content);

            if(visibleCondition != null) {
              managedProperty().bind(visibleCondition);
              visibleProperty().bind(visibleCondition);
            }
            setStyle("-fx-border-color: red; -fx-border-width: 2px");
          }};
        }

        protected CastingsRow createCastingsRow() {
          CastingsRow castingsRow = new CastingsRow();

          castingsRow.castings.bind(castings);

          return castingsRow;
        }

        public class CastingsRow extends TilePane {
          public final ObjectProperty<ObservableList<Casting>> castings = new SimpleObjectProperty<>();
          public final BooleanProperty empty = new SimpleBooleanProperty(true);

          public CastingsRow() {
            getStyleClass().add("castings-row");

            widthProperty().addListener(new ChangeListener<Number>() {
              @Override
              public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                createCastingChildren(castings.get());
              }
            });

            castings.addListener(new ChangeListener<ObservableList<Casting>>() {
              private final ListChangeListener<Casting> listChangeListener = new ListChangeListener<Casting>() {
                @Override
                public void onChanged(ListChangeListener.Change<? extends Casting> c) {
                  createCastingChildren(c.getList());
                }
              };

              private final WeakListChangeListener<Casting> weakListChangeListener = new WeakListChangeListener<>(listChangeListener);

              @Override
              public void changed(ObservableValue<? extends ObservableList<Casting>> observable, ObservableList<Casting> old, ObservableList<Casting> current) {
                if(old != null) {
                  old.removeListener(weakListChangeListener);
                }

                createCastingChildren(current);

                if(current != null) {
                  current.addListener(weakListChangeListener);
                }
              }
            });
          }

          private final WeakBinder binder = new WeakBinder();

          private void createCastingChildren(ObservableList<? extends Casting> castings) {

            /*
             * Cleanup old children (setting the image to null reduces the chance that an unneeded image is loaded in the background):
             */

            for(Node node : getChildren()) {
        // ((CastingImage)node).image.set(null);
            }

            getChildren().clear();
            empty.set(true);

            /*
             * Create new children:
             */

            double castingSize = 100 + getHgap();

            if(castings != null) {
      // double space = getWidth() - castingSize;

              for(final Casting casting : castings) {
                empty.set(false);

      // if(space < 0) {
      // break;
      // }

                CastingImage castingImage = new CastingImage();

                castingImage.setStyle("-fx-border-color: black; -fx-border-width: 4px;");

      // binder.bind(castingImage.title, casting.person.get().name);
      // binder.bind(castingImage.image, casting.person.get().photo);

                binder.bind(castingImage.characterName, casting.characterName);

                getChildren().add(castingImage);

      // space -= castingSize;
              }
            }
          }
        }

        public class Media {
          public final StringProperty title = new SimpleStringProperty();
          public final ObjectProperty<ObservableList<Casting>> castings = new SimpleObjectProperty<>();
          public final ObjectProperty<ObservableList<Casting>> castingsProperty() { return castings; }

          public Media(String title) {
            this.title.set(title);
          }
        }

        public class CastingImage extends Button {
      // public final ObjectProperty<ImageHandle> image = new SimpleObjectProperty<>();
          public final StringProperty title = new SimpleStringProperty();
          public final StringProperty characterName = new SimpleStringProperty();

          private final StringBinding formattedCharacterName = new StringBinding() {
            {
              bind(characterName);
            }

            @Override
            protected String computeValue() {
              return characterName.get() == null ? null : "as " + formatCharacterName(characterName.get(), 40);
            }
          };

          public CastingImage() {
            getStyleClass().add("cast-item");

            VBox vbox = new VBox();
            Button imageView = new Button("?");

            Label label = new Label();

      // AsyncImageProperty photo = new AsyncImageProperty();

      // photo.imageHandleProperty().bind(image);

            imageView.getStyleClass().add("cast-photo");
      // imageView.imageProperty().bind(photo);
      // imageView.setSmooth(true);
      // imageView.setPreserveRatio(true);
            imageView.setMinHeight(122);
            imageView.setAlignment(Pos.CENTER);

            label.getStyleClass().add("cast-name");
            label.textProperty().bind(title);
            label.setMinWidth(100);
            label.setMaxWidth(100);

            vbox.getChildren().addAll(imageView, label);

            Label characterNameLabel = new Label();

            characterNameLabel.getStyleClass().add("cast-character-name");
            characterNameLabel.textProperty().bind(formattedCharacterName);
            characterNameLabel.setMinWidth(100);
            characterNameLabel.setMaxWidth(100);

            vbox.getChildren().add(characterNameLabel);

            BooleanBinding visibleBinding = characterName.isNotNull().and(characterName.isNotEqualTo(""));

            characterNameLabel.managedProperty().bind(visibleBinding);
            characterNameLabel.visibleProperty().bind(visibleBinding);

            setGraphic(vbox);
          }

          private String formatCharacterName(String rawCharacterName, int cutOffLength) {
            String characterName = rawCharacterName.replaceAll(" / ", "|");
            int more = 0;

            for(;;) {
              int index = characterName.lastIndexOf('|');

              if(index == -1) {
                return characterName;
              }

              if(index > cutOffLength) { // too long, cut it off
                characterName = characterName.substring(0, index).trim();
                more++;
              }
              else {
                if(more == 0) {
                  characterName = characterName.substring(0, index).trim() + " & " + characterName.substring(index + 1).trim();
                }
                else {
                  characterName = characterName.substring(0, index).trim() + " (" + (more + 1) + "\u00a0more)";
                }
                return characterName.replaceAll(" *\\| *", ", ");
              }
            }
          }
        }

        public class WeakBinder {
          private final List<Object> hardRefs = new ArrayList<>();
          private final Map<ObservableValue<?>, WeakInvalidationListener> listeners = new HashMap<>();

          public void unbindAll() {
            for(ObservableValue<?> observableValue : listeners.keySet()) {
              observableValue.removeListener(listeners.get(observableValue));
            }

            hardRefs.clear();
            listeners.clear();
          }

          public <T> void bind(final Property<T> property, final ObservableValue<? extends T> dest) {
            InvalidationListener invalidationListener = new InvalidationListener() {
              @Override
              public void invalidated(Observable observable) {
                property.setValue(dest.getValue());
              }
            };

            WeakInvalidationListener weakInvalidationListener = new WeakInvalidationListener(invalidationListener);

            listeners.put(dest, weakInvalidationListener);

            dest.addListener(weakInvalidationListener);
            property.setValue(dest.getValue());

            hardRefs.add(invalidationListener);
          }
        }

        public class Casting {
          public final StringProperty role = new SimpleStringProperty();
          public final StringProperty characterName = new SimpleStringProperty();
          public final IntegerProperty index = new SimpleIntegerProperty();

      // public final ObjectProperty<Person> person = object("person");
      // public final ObjectProperty<Media> media = object("media");
        }

      }

      Attachments

        Issue Links

          Activity

            People

              psafrata Pavel Ĺ afrata
              jhendrikx John Hendrikx
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:
                Imported: