我想使用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--;
}
}
}
}
}
答案 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--;
}
}
}
}
}