2013-07-02 2 views
6

Wenn Sie sich den folgenden Test ansehen, werden Sie sehen, dass sich alle Kreise bewegen und nicht nur ein neuer hinzugefügt wird. Es passiert nicht jedes Mal. Ich denke, es ist nur, wenn das neue Kind außerhalb der bestehenden Grenzen ist. Aber wie bekomme ich es, damit es die Gruppe und all ihre Kinder nicht bewegt, wenn ich einen weiteren Kreis hinzufüge, unabhängig davon, wo ich den Kreis platziere?Wie kann eine JavaFX-Gruppe sich nicht bewegen, wenn nur Kinder hinzugefügt werden?

Beachten Sie, dass, wenn ich nicht die Skala auf der Gruppe einstellen, sie nicht alle verschieben werden. Es hängt also mit der Einstellung der Skala zusammen.

import javafx.application.*; 
import javafx.beans.value.*; 
import javafx.collections.*; 
import javafx.scene.*; 
import javafx.scene.layout.*; 
import javafx.scene.shape.*; 
import javafx.stage.*; 

import java.util.*; 


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

    public void start(Stage stage) { 
     Pane pane = new Pane(); 

     Group root = new Group(); 
     // NOTE: removing these two setScale* lines stops the undesirable behavior 
     root.setScaleX(.2); 
     root.setScaleY(.2); 
     root.setTranslateX(100); 
     root.setTranslateY(100); 

     root.layoutXProperty().addListener(new ChangeListener<Number>() { 
      @Override 
      public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2) { 
       System.out.println("root layout: " + root.getLayoutX() + ", " + root.getLayoutY()); 
      } 
     }); 

     root.getChildren().addListener(new ListChangeListener<Node>() { 
      @Override public void onChanged(Change<? extends Node> change) { 
       System.out.println("root: " + root.getBoundsInParent()); 
       System.out.println("root: " + root.getBoundsInLocal()); 
       System.out.println("root: " + root.getLayoutBounds()); 
       System.out.println("root: " + root.getLayoutX() + ", " + root.getLayoutY()); 
      } 
     }); 

     pane.getChildren().add(root); 
     Scene scene = new Scene(pane, 500, 500); 
     stage.setScene(scene); 
     stage.show(); 

     new Thread(() -> { 
      Random r = new Random(); 
      try { 
       while (true) { 
        expand = expand * 1.1; 
        Thread.sleep(700); 
        Platform.runLater(() -> { 
         root.getChildren().add(new Circle(r.nextInt((int)(1000*expand)) - 500*expand, r.nextInt((int)(1000*expand)) - 500*expand, r.nextInt(50)+30)); 
        }); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     }).start(); 
    } 

    static double expand = 1.0; 
} 
+1

wow, Lambda! :) –

Antwort

1

Weil Sie die Größe der Gruppe nach jedem hinzuzufügenden Kreis ändern, wodurch die Verschiebung der Gruppe innerhalb des Bereichs ausgelöst wird.

Sie können entweder:

  1. Kreisen hinzufügen direkt

    pane.getChildren().add(new Circle(... 
    
  2. fügen Sie einen großen Hintergrund Bereich Gruppengröße zu beheben:

    // numbers are huge because you are using 1/5 scaling 
    Rectangle base = new Rectangle(-10000, -10000, 20000, 20000); 
    base.setFill(Color.LIGHTGRAY); 
    root.getChildren().add(base); 
    
+0

Danke, aber keine Lösung ist akzeptabel. Ich könnte immer einen Kreis zu 30000 hinzufügen, also habe das gleiche Problem. Und ich muss in der Lage sein, die Gruppe als Ganzes zu verschieben, sodass ich die Kreise nicht zum Fenster hinzufügen kann. – mentics

5

Zuerst habe ich möchte sagen, dass das Verhalten, das Sie sehen, c Sie werden durch ein viel kleineres Programm erreicht, ganz zu schweigen von den Berechnungen, die Sie für die Kreise durchführen. r.nextInt(250) für die Positionen der Kreise wäre genug gewesen, um das Verhalten zu sehen und ist viel einfacher zu sehen, was passiert. Auch für das Debuggen, fügte ich ein sichtbares Rechteck an die Scheibe, die an die Gruppe layoutbounds gebunden ist, wo können Sie sehen, was passiert:

final Rectangle background = new Rectangle(0, 0, 0, 0); 

    root.layoutBoundsProperty().addListener(new ChangeListener<Bounds>() { 
     @Override 
     public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) { 
     background.setX(newValue.getMinX()); 
     background.setY(newValue.getMinY()); 
     background.setWidth(newValue.getWidth()); 
     background.setHeight(newValue.getHeight()); 
     } 
    }); 
    background.setFill(null); 
    background.setStroke(Color.RED); 
    pane.getChildren().add(background); 

Also, was passiert hier?

Von der Group ‚s API:

Jede Transformation, Wirkung oder Zustand auf eine Gruppe angewendet wird für alle Kinder dieser Gruppe angewendet werden. Solche Transformationen und Effekte werden NICHT in die Layoutgrenzen dieser Gruppe eingeschlossen. Wenn Transformationen und Effekte jedoch direkt auf untergeordnete Elemente dieser Gruppe gesetzt werden, werden diese in die Layoutgrenzen dieser Gruppe eingeschlossen.

im Ergebnis mit der Waage der Suche eingeschaltet:

enter image description here

Sie sehen, dass die Grenzen der Gruppe sind größer als was nach innen. Dies liegt daran, wie die Transformation angewendet wird: Die Kinder der Gruppe werden transformiert, aber für die Berechnung der Grenzen der Gruppe wird die Skalierung nicht berücksichtigt. Die Gruppe befindet sich also in dem Bereich, in dem sich die untransformierten Grenzen der Kreise befinden, und dann werden Transformationen für die Kreise angewendet.

mit dieser Aussage mit dem Ergebnis vergleichen, wenn die Skalierung ausgeschaltet ist:

enter image description here

Um es zusammenzufassen, ist dies durch Design und nicht ein seltsames Verhalten, weil die Gruppe ist immer so groß und entsprechend positioniert, wo die Union seiner untransformierten Kinder Grenzen sind.

EDIT

Wenn Sie wollen, dass die Knoten an der Position skaliert werden sie und die Gruppe nicht bewegen, schlage ich vor, die Kinder der Gruppe, die direkt zu skalieren. Diese Implementierung des Themas ändert die Skalierung der Kreise alle 5 Kreise, aber sie bleiben an der gleichen Position:

new Thread(new Runnable() { 
     private int count = 0; 
     private double scale1 = .5; 
     private double scale2 = .2; 
     private double currentScale = scale1; 
     @Override 
     public void run() { 
     final Random r = new Random(); 
     try { 
      while (true) { 
      expand = expand * 1.1; 
      Thread.sleep(700); 
      Platform.runLater(new Runnable() { 
       @Override 
       public void run() { 
       System.out.println(count); 
       Circle c = new Circle(r.nextInt(250), r.nextInt(250), 30); 
       c.setScaleX(currentScale); 
       c.setScaleY(currentScale); 
       root.getChildren().add(c); 
       count++; 
       if (count > 5){ 
        count = 0; 
        if (currentScale == scale1){ 
        currentScale = scale2; 
        } else { 
        currentScale = scale1; 
        } 
        Iterator<Node> iterator = root.getChildren().iterator(); 
        while (iterator.hasNext()) { 
        Node next = iterator.next(); 
        next.setScaleX(currentScale); 
        next.setScaleY(currentScale); 
        } 
       } 
       } 
      }); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     } 
    }).start(); 
+0

Große gründliche Erklärung des warum. Jetzt ... wie man es scheinbar nicht macht. Dies bedeutet, dass bestehende Knoten beim Hinzufügen eines neuen Knotens nicht verschoben werden. Es sollte einen Weg geben, irgendwie eine umgekehrte Transformation zu berechnen oder etwas, um es zum Laufen zu bringen. – mentics

+0

Ich verstehe Ihre Anforderung nicht genau, aber ich bearbeite meine Antwort, um ein Beispiel zu enthalten, das Skalierung verwendet und die Knoten bleiben an ihrer Position. – Sebastian

+0

Ich baue eine Schwenk/Zoom-Benutzeroberfläche. Es ist nicht möglich, jeden Knoten einzeln zu transformieren. – mentics

3

Das eigentliche Problem hier ist, dass der Drehpunkt der Gruppe - die relative Punkt für Rotation und Skalierung - - ist abhängig von den Layout-Grenzen des Konzerns. Wenn sich Layoutgrenzen daher ändern, weil neue untergeordnete Elemente hinzugefügt werden (oder vorhandene untergeordnete Objekte die Position, Größe oder Rotation ändern), ändert sich der relative Punkt für alle Transformationen in der Gruppe ebenfalls.

Im JavaFX-Quellcode finden Sie die Definition des Drehpunkts in der Node.java-Datei. Die Methoden impl_getPivotX() und impl_getPivotY() geben das Zentrum x bzw. Y-Koordinate der Layout-Grenzen.

Leider gibt es keine Option, den Pivot-Punkt manuell festzulegen. Aber wie jeder Knoten eine Liste von zusätzlichen Transformationen verwaltet, die auf der Standard-Transformationen angewendet werden, können Sie einfach das gewünschte Verhalten erreichen:

final Scale scale = new Scale(); 
group.getTransforms().add(scale); 

// change scale 
scale.setX(2); 
+0

@ taotree, Es wäre toll, Feedback zu bekommen. Löst das dein Problem? – Matthias

+0

es funktionierte für mich, thx – Chris

0

Ich hatte das gleiche Problem ein Signal Zeichnung, die einige Werte hat, die aus kam der Grenzen.

Verwenden Sie einen Bereich anstelle von Gruppe. Sie verwenden auch absolute Positionierung und bewegen sich nicht um die Grenzen. Pane JavaFx 8

-2

Verwenden Sie Pane statt Group - das hat für mich funktioniert.

Verwandte Themen