Как переместить VBox внутри стековой панели

#java #javafx #layout

#java #javafx #макет

Вопрос:

Я бы хотел, чтобы вертикальная отметка времени следовала за курсором мыши по нескольким хронограммам, чтобы указать отметку времени, но setLayoutX() или relocate() вообще не влияют на StackPane.

Я написал следующий минимально воспроизводимый пример:

 public class VerticalTimeMarkIsNotRelocated extends Application {

   @FXML private StackPane timeMarkContainer;
   @FXML private Label     label;
   @FXML private VBox      timeMark;

   @FXML
   private void initialize() {
      StackPane.clearConstraints( timeMark );
      StackPane.setAlignment( label, Pos.BOTTOM_CENTER );
   }

   @FXML
   private void moveTimeMark( MouseEvent e ) {
      final double x = e.getX();
      System.err.printf( "%7.2fn", x );
      timeMark.relocate( x, 0 );
   }

   @Override
   public void start( Stage primaryStage ) throws Exception {
      final Class<?> clazz = getClass();
      primaryStage.setScene( new Scene( FXMLLoader.load( clazz.getResource( clazz.getSimpleName()   ".fxml" ))));
      primaryStage.show();
   }

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

VerticalTimeMarkIsNotRelocated.fxml:

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

<?import java.net.URL?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>

<StackPane xmlns:fx="http://javafx.com/fxml" fx:controller="so.VerticalTimeMarkIsNotRelocated"
   fx:id="timeMarkContainer" prefWidth="420" prefHeight="140" onMouseMoved="#moveTimeMark">
   <stylesheets>
      <URL value="@VerticalTimeMarkIsNotRelocated.css" />
   </stylesheets>
   <Label fx:id="label" text="Replacement for several chronogram widgets" />
   <VBox  fx:id="timeMark" minWidth="1.0" maxWidth="1.0" />
</StackPane>
 

VerticalTimeMarkIsNotRelocated.css:

 #timeMark {
  -fx-background-color: red;
}
#label {
  -fx-background-color: bisque;
  -fx-padding: 40px;
}
 

На следующем снимке экрана в консоли Eclipse мы видим, что мышь перемещается, но вертикальная красная метка по-прежнему находится в середине стековой панели:

Вертикальная временная метка не перемещается

Комментарии:

1. по сути, вы боретесь с макетом (и заставляете его делать то, что вы хотите, неправильно используя margin is .. evil 😉 — поиск управляемого дочернего элемента с помощью некоторого внешнего кода будет отменен при каждом проходе макета.

2. Похоже, у вас есть Controller код в классе, который расширяется Application .

3. @kleopatra: какой макет лучше использовать?

Ответ №1:

Установите поля программно и используйте вставки (двойной верх, двойной правый, двойной нижний, двойной левый)

    @FXML
   private void moveTimeMark( MouseEvent e ) {
      final double x = e.getX();
      System.err.printf( "%7.2fn", x );
      StackPane.setMargin(timeMark, new Insets(0,x,0,0));
   }
 

Комментарии:

1. Нет, это не решает проблему. Запустите его.

Ответ №2:

setMargin решает проблему с помощью небольшого исчисления:

 @FXML
private void moveTimeMark( MouseEvent e ) {
   StackPane.setMargin( timeMark,
      new Insets( 0.0, 0.0, 0.0, -timeMarkContainer.getWidth() 2.0*e.getX()));
}
 

Зачем нужно это исчисление?