2017-10-06 64 views
0

我想使用JavaFX创建一个保镖应用程序。我用Pane来显示移动的形状(circle, Rectange)。当我将窗口调整到更大的区域时,会发生问题。当我这样做时,新创建的区域不会正确显示移动的形状。在这个新领域会发生什么:形状从黑色变成白色,并留下白色痕迹。JavaFX窗格不会在调整大小的区域上绘制形状

使用setTranslateX(和Y)方法移动形状。

我还在屏幕截图下方提供了一个示例代码。该代码与录制屏幕上的代码不同,但它会产生相同的问题。

按照原始大小的窗口

,面积大小的窗口,其中形状不正确绘制

命名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> 
的FXML文件

扩展应用程序的主类

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(); 
    } 
} 

** **控制器

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

请编辑您的问题以包含[MCVE]。 –

+0

我将代码添加到线程中。如果你创建一个javaFX项目并且使用Main.java和Controller.java + view.fxml,那么它应该可以工作。该软件包名为com.company.bouncer 该代码与动画中的代码不同,但它提供了相同的问题 –

+0

您试图从后台线程更新UI。当你这样做的时候结果是不确定的。为什么不为动画使用['Animation'](https://docs.oracle.com/javase/9​​/docs/api/javafx/animation/package-summary.html),而不是线程? –

回答

0

所以,这个问题实际上我是跑运动处理这可能产生我的问题后台线程。在@James_D的建议下,我实施了使用AnimationTimer的扩展的移动处理,现在被解决的问题已经消失。

新代码在文本下是int。我仍然必须实施一种机制来处理正确的时间,因为现在没有在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--; 
       } 
      } 
     } 
    } 
}