JavaFX窗格不会在已调整大小的区域上绘制形状

时间:2017-10-06 08:27:35

标签: javafx javafx-8 window-resize pane

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

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

我还在屏幕截图下面加了一个示例代码。代码与录制屏幕上的代码不同,但它会产生同样的问题。

原始尺寸的窗口

调整大小的窗口,其中包含未正确绘制形状的区域

名为view.fxml 的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>

扩展应用程序的主类

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 个答案:

答案 0 :(得分: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--;
                }
            }
        }
    }
}