2017-01-14 2 views
1

У меня есть несколько ярлыков в моем VBox и при нажатии кнопки я хочу заменить все эти ярлыки текстовыми полями.Замените метку текстовым полем в javafx в том же положении

+1

Просим предоставить дополнительную информацию. Существуют ли какие-либо особые условия на ярлыках, такие как макет, стиль, текст, .. Может оказаться полезным [рабочий пример] (http://stackoverflow.com/help/mcve). – hotzst

+0

На этикетках нет особых условий. Они просто отображают текст, который я читаю из базы данных. При нажатии кнопки (или флажок) эти метки будут меняться в редактируемых текстовых полях. Я хочу, чтобы мои текстовые поля были заменены в одной позиции ярлыка. скажем, label1 будет заменен textfielld1 в позиции label1. –

+0

Что вы пробовали? – n247s

ответ

0

Вы можете итерацию над VBox и заменить:

VBox vBox = ... 
int currentPos = 0; 
Map<Integer, TextField> toInsert = new HashMap<>(); // map with TextFields that need to be inserted at position 
for (Iterator<Node> iterator = vBox.getChildren().iterator(); iterator.hasNext();) { 
    Node child = iterator.next(); 
    if (child instanceof Label) { 
     Label lbl = (Label)child; 
     TextField text = new TextField(lbl.getText()); 
     iterator.remove(); // remove the label that is at index currentPos 
     toInsert.put(currentPos, text); 

    } 
    currentPos++; 
} 
for (Integer pos : toInsert.keySet()) { 
    TextField field = toInsert.get(pos); 
    vBox.getChildren().add(pos, field); // Add the Text field at the old position of the Label 
} 

В первом цикле удалить ярлыки и создать замену TextField сек и помните, в каком положении вы должны вставить их в дальнейшем. Это не может произойти в одном цикле. Затем во втором цикле вы добавляете те TextField s в VBox в положение, которое вы им назначили.

Редактировать: Основанный на действительных комментариях @ fabian, предложенное выше решение может вызвать проблемы. Вот альтернативный подход, который создает второй VBox, где все узлы non Label копируются и Label s заменяются на TextField. Я предполагаю, что исходный VBox является дочерним элементом от Parent.

Parent parent = ... // Parent of VBox 
VBox vbox = ... 
// Find the index of vBox in Parent 
int position = 0; 
for (int i = 0; i<parent.getChildren().size(); i++) { 
    if (parent.getChildren().equals(vBox)) { 
     position = i; 
     break; // found our position, no need to look further 
    } 
} 
VBox copyVBox = new VBox(); 
for (Node child : vBox.getChildren()) { 
    if (child instanceof Label) { 
     Label lbl = (Label)child; 
     TextField text = new TextField(lbl.getText()); 
     copyVBox.getChildren().add(text);   
    } else { 
     copyVBox.getChildren().add(child); 
    } 
} 
parent.getChildren().remove(vBox); 
parent.getChildren().add(position, copyVBox); 
+0

Необходимо изменить этот код, поскольку заказ в наборе ключей непредсказуем и вставляется в любом порядке, но в порядке возрастания приведет к неправильным результатам. Вы можете, например, замените детей, используя 'set' во втором цикле и не удаляя элементы в первом цикле, используйте' .stream(). sorted(). forEach (...) 'вместо второго цикла или используйте' LinkedHashMap' , – fabian

+0

Большое спасибо, он работает абсолютно идеально. –

+0

BTW: вы ** можете ** изменять список во время итерации по нему, но вам нужно будет использовать ['ListIterator'] (https://docs.oracle.com/javase/8/docs/api/java /util/ListIterator.html) для этого ... – fabian

3

Я бы не рекомендовал использовать VBox, так как замена детей, вероятно, изменит расположение вызывает эффект, который может ввести в заблуждение пользователя.
Вместо этого я рекомендую использовать GridPane, что позволяет размещать несколько дочерних элементов в одной ячейке. Таким образом, вы можете поместить все Label s и VBox es в сетку, но установить свойство visibleTextField s на false. Это означает, что как Label и TextField будет использоваться для расчета макета и вы можете просто переключаться между «режимом редактирования» и «нормальным режимом», переворачивая visible свойства всех детей:

FXML

<HBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="fxml.LabelReplaceController"> 
    <children> 
     <GridPane fx:id="grid"> 
      <children> 
       <TextField fx:id="t1" text="Hello World!" visible="false" GridPane.rowIndex="0"/> 
       <Label text="${t1.text}" GridPane.rowIndex="0" /> 
       <TextField fx:id="t2" text="foo" visible="false" GridPane.rowIndex="1"/> 
       <Label text="${t2.text}" GridPane.rowIndex="1" /> 
       <TextField fx:id="t3" text="bar" visible="false" GridPane.rowIndex="2"/> 
       <Label text="${t3.text}" GridPane.rowIndex="2" /> 
      </children> 
     </GridPane> 
     <ToggleButton selected="false" onAction="#selectionChanged" text="edit"/> 
    </children> 
</HBox> 
public class LabelReplaceController { 

    @FXML 
    private Pane grid; 

    @FXML 
    private void selectionChanged(ActionEvent event) { 
     for (Node child : grid.getChildren()) { 
      child.setVisible(!child.isVisible()); 
     } 
    } 

} 
+0

Да, вы правы. Но держать в моих дальнейших функциях, чтобы быть менее сложной сеткой, является лучшим вариантом. –

+0

Большое спасибо за столь необходимую помощь –

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