2015-08-20 2 views
0

В моем приложении TextField связан двунаправленно с макетом панели. Любые изменения в текстовом поле немедленно обновят layoutX панели.JavaFX 8 Двойная привязка в одностороннем порядке

Например, если layoutX равен 500 и последний нуль удален, позиция панели переходит непосредственно к x = 50. Аналогично, если панель перетаскивается вокруг значения в поле tex, отображает значение layoutX на панели.

Связывание перетаскивания прекрасное, но теперь я хочу дождаться клавиши RETURN в текстовом поле до того, как будет обновлен layoutX панели (я хочу сначала проверить правильные граничные значения). Я попробовал ChangeListeners и привязку низкого уровня, но не могу заставить его работать удовлетворительно.

Есть ли у кого-нибудь идеи о том, как реализовать это. Мне кажется, что это будет обычным делом, но в этих книгах или в Интернете об этом очень мало информации. Может ли изменщик «использовать связующее событие»?

+0

Просто используйте два слушателя вместо привязки. Используйте прослушиватель для 'ActionEvent' на' TextField' –

ответ

1

Просто добавь слушатель в layoutX собственности, который обновляет текстовое поле и добавить обработчик для события действия на TextField, который выполняет проверку и обновляет layoutX свойства. Обработчик будет запущен, если пользователь нажмет Enter, но не раньше. Поскольку вы не хотите, чтобы layoutX обновлялся в любое время, когда текст обновляется, привязка здесь не подходит.

SSCCE:

import javafx.application.Application; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.geometry.Point2D; 
import javafx.scene.Scene; 
import javafx.scene.control.Label; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.Pane; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Rectangle; 
import javafx.stage.Stage; 

public class PaneCoordinatesInTextField extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     Label draggingLabel = createDraggingLabel(); 

     TextField textField = new TextField(); 
     draggingLabel.layoutXProperty().addListener((obs, oldLayoutX, newLayoutX) -> 
      textField.setText(newLayoutX.toString())); 

     textField.setOnAction(e -> { 
      try { 
       double x = Double.parseDouble(textField.getText()); 
       if (x < 0) { 
        x = 0 ; 
       } 
       if (x > 400) { 
        x = 400 ; 
       } 
       draggingLabel.setLayoutX(x); 
      } catch (NumberFormatException exc) { 
       textField.setText(Double.toString(draggingLabel.getLayoutX())); 
      } 
     }); 

     Pane pane = new Pane(draggingLabel); 
     pane.setMinSize(600, 600); 

     BorderPane root = new BorderPane(pane, textField, null, null, null); 
     primaryStage.setScene(new Scene(root)); 
     primaryStage.show(); 
    } 

    private Label createDraggingLabel() { 
     Label label = new Label("Drag me", new Rectangle(200, 200, Color.CORNFLOWERBLUE)); 
     label.setContentDisplay(ContentDisplay.CENTER); 
     label.setTextFill(Color.WHITE); 
     label.setAlignment(Pos.CENTER); 

     ObjectProperty<Point2D> mouseLocation = new SimpleObjectProperty<>(); 
     label.setOnDragDetected(e -> mouseLocation.set(new Point2D(e.getSceneX(), e.getSceneY()))); 
     label.setOnMouseReleased(e -> mouseLocation.set(null)); 
     label.setOnMouseDragged(e -> { 
      if (mouseLocation.get() == null) { 
       return ; 
      } 
      double deltaX = e.getSceneX() - mouseLocation.get().getX(); 
      double deltaY = e.getSceneY() - mouseLocation.get().getY(); 
      label.setLayoutX(label.getLayoutX() + deltaX); 
      label.setLayoutY(label.getLayoutY() + deltaY); 
      mouseLocation.set(new Point2D(e.getSceneX(), e.getSceneY())); 
     }); 
     return label; 
    } 

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

Это пример того, что другие люди могут оказаться очень полезными при поиске аналогичного решения - так хорошо сделано для публикации полного примера. – Frank

0

Я нашел решение «а», но это похоже на kludge.

Я приложил onMouseClicked и обработчик onActon к текстовому полю.

В текстовом поле onMouseClicked Я отвязываю текстовое поле и дождитесь нажатия клавиши RETURN. В onAction я обновляю ранее связанное значение с новым значением текстового поля, а затем снова привязываю его в двух направлениях. И вуаля ... это работает.

Я могу проверить допустимые значения в обработчике onAction.

Но, как я уже сказал, это кажется немного решением для бандажей. Кто-нибудь хочет прокомментировать?

+0

Да, я вроде как сам попал туда. Мне по-прежнему нравится концепция единственного связывания (для согласованности с другими полями), поэтому я буду привязывать «перетаскивание обновления», а другой - к прослушивателю для обработчика Action. – Frank

+0

Если вы не хотите, чтобы он менялся всякий раз, когда текст меняется, привязка не то, что вы хотите. Просто используйте прослушиватели для непосредственного обновления значений. –

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