2017-10-06 6 views
0

Je souhaite créer une application de vidage à l'aide de JavaFX. J'ai utilisé Pane pour montrer des formes en mouvement (circle, Rectange) dessus. Le problème se produit lorsque je redimensionne la fenêtre à une plus grande zone. Lorsque je fais cela, la zone nouvellement créée ne montre pas correctement les formes en mouvement. Ce qui se passe dans cette nouvelle zone: les formes changent de couleur du noir au blanc et elles laissent une trace blanche.Le volet JavaFX ne dessine pas de formes sur une zone redimensionnée

Les formes sont déplacées à l'aide des méthodes setTranslateX (et Y). J'ai également inclus un exemple de code sous les captures d'écran. Le code n'est pas le même que celui sur les écrans enregistrés, mais il produit le même problème.

fenêtre avec la taille originale

fenêtre redimensionnée avec une zone où les formes ne sont pas dessinés correctement

Le document FXML nommé view.fxml

<?import javafx.scene.shape.*?> 
<?import javafx.geometry.*?> 
<?import javafx.scene.control.*?> 
<?import java.lang.*?> 
<?import javafx.scene.layout.*?> 
<?import javafx.scene.layout.AnchorPane?> 

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.company.bouncer.Controller"> 
    <center> 
     <Pane fx:id="paneField" prefHeight="344.0" prefWidth="600.0" BorderPane.alignment="CENTER" /> 
    </center> 
    <top> 
     <HBox alignment="CENTER_LEFT" prefHeight="56.0" prefWidth="600.0" spacing="30.0" BorderPane.alignment="CENTER"> 
     <children> 
      <Button fx:id="btnLaunch" mnemonicParsing="false" onAction="#handleBtn" text="Launch" /> 
     </children> 
     <opaqueInsets> 
      <Insets /> 
     </opaqueInsets> 
     <BorderPane.margin> 
      <Insets /> 
     </BorderPane.margin> 
     <padding> 
      <Insets left="30.0" /> 
     </padding> 
     </HBox> 
    </top> 
</BorderPane> 

classe principale qui étend l'application

package com.company.bouncer; 

import java.io.IOException; 

import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.stage.Stage; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 


public class Main extends Application { 
    @Override 
    public void start(Stage primaryStage) throws IOException { 
     Parent root = FXMLLoader.load(getClass().getResource("/view.fxml")); 
     primaryStage.setTitle("Bouncer"); 
     primaryStage.setScene(new Scene(root, 600, 400)); 
     primaryStage.show(); 
    } 

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

    /** 
    * called when the window is closed 
    */ 
    @Override 
    public void stop() throws Exception { 
     Controller.stopExecutor(); 
     super.stop(); 
    } 
} 

** Contrôleur **

package com.company.bouncer; 

import java.net.URL; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.ResourceBundle; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ScheduledExecutorService; 
import java.util.concurrent.TimeUnit; 

import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.geometry.Insets; 
import javafx.scene.control.Button; 
import javafx.scene.layout.Background; 
import javafx.scene.layout.BackgroundFill; 
import javafx.scene.layout.CornerRadii; 
import javafx.scene.layout.Pane; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Rectangle; 
import javafx.scene.shape.Shape; 

public class Controller implements Initializable { 

    @FXML 
    private Button btnLaunch; 
    @FXML 
    private Pane paneField; 

    private ShapePlatform shapeRunnable; 
    private static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); 

    @Override 
    public void initialize(URL location, ResourceBundle resources) { 
     shapeRunnable = new ShapePlatform(); 

     paneField.setBackground(new Background(new BackgroundFill(Color.web("#aaaaaa"), CornerRadii.EMPTY, Insets.EMPTY))); 

     executor.scheduleAtFixedRate(shapeRunnable, 0, 10, TimeUnit.MILLISECONDS); 
    } 

    @FXML 
    private void handleBtn(){ 
     shapeRunnable.generateShapeMover(); 
    } 

    public static void stopExecutor(){ 
     executor.shutdown(); 
    } 

    public class ShapePlatform implements Runnable { 

     private List<ShapeMover> shapeList = new ArrayList<>(); 

     /** 
     * Constructor 
     * @param parentPane Pane on which the shapes will be displayed 
     */ 
     public ShapePlatform(){ 
     } 

     /** 
     * creates a new shape and adds it to the shapeList 
     */ 
     public void generateShapeMover(){ 
      Shape newShape = new Rectangle(0, 0, 100, 80); 
      paneField.getChildren().add(newShape); 

      //position the object in some random location on the pane 
      newShape.setTranslateX(300); 
      newShape.setTranslateY(300); 

      //wrap it in shape mover 
      ShapeMover shapeMover = new ShapeMover(newShape); 
      shapeList.add(shapeMover); 
     } 

     /** 
     * executes one frame of moving objects 
     */ 
     private void moveAllOnce(){ 
      shapeList.forEach(sm -> sm.move()); 
     } 

     /** 
     * moves all objects, checks any intersections between objects 
     * and changes their direction if there is an intersection 
     */ 
     @Override 
     public void run() { 
      moveAllOnce(); 
     } 

     public class ShapeMover { 

      private Shape shape; 
      private int xDir = 1; 
      private int yDir = 1; 
      private int periodSpeed = 1; 
      private int periodSpeedCountDown = periodSpeed; 

      /** 
      * constructs the object 
      * @param shape - shape to be moved 
      */ 
      public ShapeMover(Shape shape){ 
       this.shape = shape; 
      } 

      /** 
      * moves object for one iteration 
      */ 
      public void move(){ 
       if(periodSpeedCountDown == 0){ 
        shape.setTranslateX(shape.getTranslateX() + xDir); 
        shape.setTranslateY(shape.getTranslateY() + yDir); 
        periodSpeedCountDown = periodSpeed; 
       } else { 
        periodSpeedCountDown--; 
       } 
      } 
     } 
    } 
} 
+1

S'il vous plaît [modifier] votre question d'inclure un [MCVE]. –

+0

J'ai ajouté du code au fil de discussion. Si vous créez un projet javaFX et avec Main.java et Controller.java + view.fxml, alors cela devrait fonctionner. Le paquet est nommé com.company.bouncer Le code n'est pas le même que celui des animations, mais il donne le même problème –

+0

Vous essayez de mettre à jour l'interface utilisateur à partir d'un thread d'arrière-plan. Les résultats ne sont pas définis lorsque vous faites cela. Pourquoi ne pas utiliser un ['Animation'] (https://docs.oracle.com/javase/9/docs/api/javafx/animation/package-summary.html) pour votre animation, au lieu d'un fil de discussion? –

Répondre

0

Ainsi, le problème était en fait que je courais le fil d'arrière-plan de manutention mouvement qui a probablement produit mon problème. Avec une suggestion de @James_D j'ai mis en œuvre la manipulation de mouvement en utilisant l'extension de AnimationTimer, et maintenant le problème menitoned est parti.

Le nouveau code est int sous le texte. Je dois encore mettre en place un mécanisme pour gérer le bon moment que maintenant il n'y a pas de périodes définies dans AnimationTimer

public class Controller implements Initializable { 

    @FXML 
    private Button btnLaunch; 
    @FXML 
    private Pane paneField; 

    private ShapePlatform shapeAnimTimer; 
    private static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); 

    @Override 
    public void initialize(URL location, ResourceBundle resources) { 
     paneField.setBackground(new Background(new BackgroundFill(Color.web("#aaaaaa"), CornerRadii.EMPTY, Insets.EMPTY))); 

     shapeAnimTimer = new ShapePlatform(); 
     shapeAnimTimer.start(); 
    } 

    @FXML 
    private void handleBtn(){ 
     shapeAnimTimer.generateShapeMover(); 
    } 

    public static void stopExecutor(){ 
     executor.shutdown(); 
    } 

    public class ShapePlatform extends AnimationTimer { 

     private List<ShapeMover> shapeList = new ArrayList<>(); 

     /** 
     * creates a new shape and adds it to the shapeList 
     */ 
     public void generateShapeMover(){ 
      Shape newShape = new Rectangle(0, 0, 100, 80); 
      paneField.getChildren().add(newShape); 

      //position the object in some random location on the pane 
      newShape.setTranslateX(300); 
      newShape.setTranslateY(300); 

      //wrap it in shape mover 
      ShapeMover shapeMover = new ShapeMover(newShape); 
      shapeList.add(shapeMover); 
     } 

     /** 
     * executes one frame of moving objects 
     */ 
     private void moveAllOnce(){ 
      shapeList.forEach(sm -> sm.move()); 
     } 

     /** 
     * moves all objects, checks any intersections between objects 
     * and changes their direction if there is an intersection 
     * @param now current frame 
     */ 
     @Override 
     public void handle(long now) { 
      System.out.println(now); 
      moveAllOnce(); 

     } 

     public class ShapeMover { 

      private Shape shape; 
      private int xDir = 1; 
      private int yDir = 1; 
      private int periodSpeed = 1; 
      private int periodSpeedCountDown = periodSpeed; 

      /** 
      * constructs the object 
      * @param shape - shape to be moved 
      */ 
      public ShapeMover(Shape shape){ 
       this.shape = shape; 
      } 

      /** 
      * moves object for one iteration 
      */ 
      public void move(){ 
       if(periodSpeedCountDown == 0){ 
        shape.setTranslateX(shape.getTranslateX() + xDir); 
        shape.setTranslateY(shape.getTranslateY() + yDir); 
        periodSpeedCountDown = periodSpeed; 
       } else { 
        periodSpeedCountDown--; 
       } 
      } 
     } 
    } 
}