使用translateX()和translateY()时,窗格布局中的JavaFX文本与其他元素重叠

时间:2016-12-06 07:48:55

标签: java javafx fxml

下图是对正在发生的事情的描述:

enter image description here

我有Pane,其中包含Text,我正在使用以下代码制作marquee like effect的{​​{1}}。因此,当Text没有足够的空间来显示文本时,动画正在启动,文本必须来回移动,以便用户可以完整地看到它。

问题是我在使用Pane向左移动时期望文本消失而不与其他元素重叠。例如,此处重叠setTranslateX()在左边。

代码来自 - > JavaFX Marquee Animation问题。

  • 为什么会这样?
  • 我需要一个解决方案和简要描述:)

以下是代码:

Marquee.java [class]:

StackPane

Marquee.fxml

import java.io.IOException;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.InvalidationListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;
import javafx.scene.text.Text;
import javafx.util.Duration;

/**
 * When the screen element is not big enough to show the text then an animation
 * will start automatically
 * 
 *
 */
public class Marquee extends Pane{

    @FXML
    private Text text;

    // minimum distance to Pane bounds
    private static final double OFFSET = 5;

    private Timeline timeline = new Timeline();

    /**
     * Constructor
     */
    public Marquee() {

        // FXMLLOADER
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Marquee.fxml"));
            loader.setController(this);
            loader.setRoot(this);
            loader.load();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }


    /**
     * Called when FXML is loaded
     */
    @FXML
    public void initialize() {

        startAnimation();
    }

    /**
     * This method changes the text of the Marquee
     * 
     * @param value
     * @return this
     */
    public Marquee setText(String value) {

        // text
        text.setText(value);

        return this;
    }

    /**
     * This method starts the Animation of the marquee
     */
    private final void startAnimation() {

        // KeyFrame
        KeyFrame updateFrame = new KeyFrame(Duration.millis(35), new EventHandler<ActionEvent>() {

            private boolean rightMovement;

              @Override
                public void handle(ActionEvent event) {
                    double textWidth = text.getLayoutBounds().getWidth();
                    double paneWidth = getWidth();
                    double layoutX = text.getLayoutX();

                    if (2 * OFFSET + textWidth <= paneWidth && layoutX >= OFFSET) {
                        // stop, if the pane is large enough and the position is correct
                        text.setLayoutX(OFFSET);
                        timeline.stop();
                    } else {
                        if ((rightMovement && layoutX >= OFFSET) || (!rightMovement && layoutX + textWidth + OFFSET <= paneWidth)) {
                            // invert movement, if bounds are reached
                            rightMovement = !rightMovement;
                        }

                        // update position
                        if (rightMovement) {
                            layoutX += 1;
                        } else {
                            layoutX -= 1;
                        }
                        text.setLayoutX(layoutX);
                    }
                }
        });
        timeline.getKeyFrames().add(updateFrame);
        timeline.setCycleCount(Animation.INDEFINITE);

        // listen to bound changes of the elements to start/stop the
        // animation
        InvalidationListener listener = o -> {
            double textWidth = text.getLayoutBounds().getWidth();
            double paneWidth = getWidth();
            if (textWidth + 2 * OFFSET > paneWidth && timeline.getStatus() != Animation.Status.RUNNING)
                timeline.play();
        };

        text.layoutBoundsProperty().addListener(listener);
        widthProperty().addListener(listener);

    }

}

最后 Main.java [class]

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

<?import javafx.scene.layout.Pane?>
<?import javafx.scene.text.Text?>

<fx:root maxHeight="25.0" minHeight="25.0" prefHeight="25.0" prefWidth="100.0" style="-fx-border-color: orange;" type="Pane" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Text fx:id="text" layoutX="5.0" layoutY="17.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Text" />
   </children>
</fx:root>

import javafx.application.Application; import javafx.scene.Scene; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage primaryStage) { Scene scene = new Scene(new Marquee().setText("Extra Biiggggggg Textttt"), 300, 300); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { launch(args); } } 回答后编辑:

.fxml 现在是:

Fabians

1 个答案:

答案 0 :(得分:3)

  

为什么这样做?

默认情况下,JavaFX还会在节点边界之外绘制子节点。

  

如何解决这个问题?

使用父级的clip属性剪切Pane边界内容:

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

<?import javafx.scene.layout.Pane?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.shape.Rectangle?>

<fx:root xmlns:fx="http://javafx.com/fxml/1" fx:id="root" maxHeight="25.0" minHeight="25.0" prefHeight="25.0" prefWidth="100.0" style="-fx-border-color: orange;" type="Pane" xmlns="http://javafx.com/javafx/8.0.60">
    <children>
        <Text fx:id="text" layoutX="5.0" layoutY="17.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Text"/>
    </children>
    <clip>
        <Rectangle width="${root.width}" height="${root.height}" />
    </clip>
</fx:root>