ScrollPane 没有 "know" 何时展开

ScrollPane doesnt "know" when to expand

我不确定如何称呼这个问题,但你一定会明白我的意思... 至少我希望你会。

首先:我的 Pane 中有一个 ScrollPane。此窗格还包含两个按钮,我可以在其上在我的 ScrollPane 中创建矩形。

我可以四处拖动这些矩形,然后将它们移出视图。到目前为止,除了 ScrollPane 之外,一切正常。通常你让 ScrollPane 展开他的 Scroll 这样你就可以,如果你放开 Rectangle,滚动到那个 Rectangle 并再次抓住它但是友好的 JavaFX 不知道如何展开 Scroll 所以我无法再次到达这个 Rectangle。

或者我只是错过了一些重要的部分(这是更有可能发生的事情)

关于我的代码的一些话:我认为这不是我现有代码中的问题,而是一个需要解决方法的问题。我为 ScrollPane 所做的唯一更改是我将 ScrollBarPolicy 设置为始终并设置 ScrollPane Pannable 但当我单击 Rectangle 时会消耗它,因此我可以移动它们而不平移 ScrollPane。

您在上面看到的是一个完整大小的矩形和一个部分超出 ScrollPane 边界但 ScrollPane 没有展开 ScrollBar 的矩形。 不管我将 Rectangle 移离这些边界多远,Scrollbar 都不会改变,这是我选择 ScrollPane 的唯一原因,而且我认为这是实现此目的的唯一(最简单)窗格 "editor like" 视图。

是的,至少感谢您阅读到这里,并且总是为我的英语蹩脚感到抱歉^^。我希望你能给我一个如何解决这个问题的建议!

编辑:

这是一个最小的例子: Controller.java

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;

import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;

public class Controller implements Initializable{
    @FXML ScrollPane actionWin;
    Rectangle r;
    Double orgTranslateX, orgTranslateY, orgSceneX, orgSceneY, newTranslateX, newTranslateY, offsetY, offsetX;
    int i = 50;
    List<Rectangle> recs = new ArrayList<Rectangle>();

@Override
public void initialize(URL arg0, ResourceBundle arg1) {
    actionWin.setPannable(true);
    actionWin.setHbarPolicy(ScrollBarPolicy.ALWAYS);
    actionWin.setVbarPolicy(ScrollBarPolicy.ALWAYS);
}

@FXML
public void createEntity(){

       Pane container = new Pane();

        // Button 1
        r = new Rectangle();
        r.addEventHandler(MouseEvent.ANY, event -> {
            if(event.getButton() != MouseButton.MIDDLE) event.consume();
        });

        r.setOnMousePressed(onMousePressedEventHandler);
        r.setOnMouseDragged(onMouseDraggedEventHandler);
        r.setX(i);
        r.setY(i);
        r.setWidth(50);
        r.setHeight(20);
        i+=30;
        recs.add(r);

        for(Rectangle rec : recs){
            container.getChildren().add(rec);
        }

        actionWin.setContent(container);
        try {
            AnchorPane root = (AnchorPane) FXMLLoader.load(getClass().getResource("Main.fxml"));
        } catch (IOException e) {
            e.printStackTrace();
        }
}

EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent arg0) {
        orgSceneX = arg0.getSceneX();
        orgSceneY = arg0.getSceneY();
        orgTranslateX = ((Rectangle) (arg0.getSource())).getTranslateX();
        orgTranslateY = ((Rectangle) (arg0.getSource())).getTranslateY();
    }};

EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent arg0) {
        offsetX = arg0.getSceneX() - orgSceneX;
        offsetY = arg0.getSceneY() - orgSceneY;
        newTranslateX = orgTranslateX + offsetX;
        newTranslateY = orgTranslateY + offsetY;
        ((Rectangle)(arg0.getSource())).setTranslateX(newTranslateX);
        ((Rectangle)(arg0.getSource())).setTranslateY(newTranslateY);
    }};
}

Main.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.Spinner?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane fx:id="root" maxHeight="720.0" maxWidth="1280.0" minHeight="720.0" minWidth="1280.0" prefHeight="720.0" prefWidth="1280.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
   <children>
      <Button fx:id="createEntity_B" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" onAction="#createEntity" text="Create Entity" />
      <ScrollPane fx:id="actionWin" layoutX="14.0" layoutY="39.0" prefHeight="672.0" prefWidth="996.0" />
   </children>
</AnchorPane>

Main.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;


public class Main extends Application {
    public void start(Stage primaryStage) {
        try {
            AnchorPane root = (AnchorPane) 
            FXMLLoader.load(getClass().getResource("Main.fxml"));
            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
            primaryStage.setResizable(false);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

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

将这三个 类 包装在一个名为 "application" 的包中,您就可以开始了。

您正在使用 translateXtranslateY 来确定 Rectangle 的新位置。

当 parent 确定其大小时,不考虑像翻译属性这样的转换。 child 被视为位于 (layoutX, layoutY)。如果您希望 Pane 正确调整大小,您需要修改这些属性。

createEntity 中的其他一些内容看起来很奇怪:

  • 您重新创建 Pane 而不是在 fxml 中创建一次。
  • 您加载了一个似乎从未被使用过的 fxml。

此外,除非您不进行任何算术运算或比较,否则您应该更喜欢原始类型 double 而不是引用类型 Double


<AnchorPane fx:id="root" maxHeight="720.0" maxWidth="1280.0" minHeight="720.0" minWidth="1280.0" prefHeight="720.0" prefWidth="1280.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
   <children>
      <Button fx:id="createEntity_B" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" onAction="#createEntity" text="Create Entity" />
      <ScrollPane fx:id="actionWin" layoutX="14.0" layoutY="39.0" prefHeight="672.0" prefWidth="996.0">
          <content>
              <Pane fx:id="container"/>
          </content>
      </ScrollPane>
   </children>
</AnchorPane>
@FXML
private Pane container;

@FXML
public void createEntity() {
    class DraggedHandler implements EventHandler<MouseEvent> {

        double offsetX;
        double offsetY;

        @Override
        public void handle(MouseEvent event) {
            Node source = (Node) event.getSource();
            Point2D pt = source.localToParent(event.getX(), event.getY());
            source.setLayoutX(pt.getX() + offsetX);
            source.setLayoutY(pt.getY() + offsetY);
        }

    }

    Rectangle rect = new Rectangle(i, i, 50, 20);
    i += 30;
    container.getChildren().add(rect);

    rect.addEventHandler(MouseEvent.ANY, event -> {
        if (event.getButton() != MouseButton.MIDDLE) {
            event.consume();
        }
    });

    DraggedHandler handler = new DraggedHandler();
    rect.setOnMouseDragged(handler);
    rect.setOnMousePressed(evt -> {
        Node source = (Node) evt.getSource();
        Point2D pt = source.localToParent(evt.getX(), evt.getY());
        handler.offsetX = source.getLayoutX() - pt.getX();
        handler.offsetY = source.getLayoutY() - pt.getY();
    });
}