2016-12-06 2 views
3

Изображение ниже приведено описание того, что происходит:JavaFX Текст внутри Pane Layout перекрывает другие элементы при использовании translateX() и translateY()

enter image description here


У меня есть Pane, который содержит a Text, и я использую код ниже, чтобы сделать marquee like effectText. Поэтому, когда Pane не хватает места для отображения текста, начинается анимация, и текст должен идти туда и обратно, чтобы пользователь мог видеть его целиком.

Проблема в том, что я ожидал, что текст при переходе влево с помощью setTranslateX() исчезнуть и не overlape другого elements.For примера здесь перекрывают StackPane слева.

Код исходит от ->JavaFX Marquee Animation вопрос.

  • Почему это происходит?
  • мне нужно решение и краткое описание для этого :)

Ниже приведен код:

Marquee.java [класс]:

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

    } 

} 

Marquee.fxml:

<?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> 

И наконец Main.java [класс]:

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


Редактировать после Fabians Ответ:

.fxml сейчас:

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

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

<fx:root fx:id="root" maxHeight="25.0" minHeight="25.0" prefHeight="25.0" prefWidth="100.0" style="-fx-border-color: orange; -fx-background-color: white;" 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" style="-fx-text-fill: black; -fx-font-weight: bold;" text="Stopped" /> 
    </children> 
    <clip> 
    <Rectangle width="${root.width}" height="${root.height}"/> 
    </clip> 
</fx:root> 

ответ

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> 
+0

Удивительно! Могу ли я сделать это с помощью SceneBuilder или мне нужно написать код вручную, как вы это сделали?Если вы можете включить, и это вызывает любопытство, это будет полный ответ :) – GOXR3PLUS

+0

@ GOXR3PLUS К сожалению, SceneBuilder не поддерживает привязку выражения и afaik, он не поддерживает присвоение свойства 'clip' либо ... – fabian

+0

Отредактировал мой вопрос. Я добавил «.fxml» после вашего ответа, но я получаю черный ящик, в котором должна появиться «Панель». Что не так? Что-то с встроенным стилем? – GOXR3PLUS

Смежные вопросы