JavaFx:如何在GridPane中更新动态创建的TextField文本? [英] JavaFx: How to update text of dynimically created TextFields inside GridPane?

查看:171
本文介绍了JavaFx:如何在GridPane中更新动态创建的TextField文本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JavaFx开发一个应用程序,其中我在GridPane中动态创建TextFeids和CheckBoxes,如下所示:





我正在添加用户将在TextField 1和TextField 2中输入并使用侦听器在TextField 3中显示的数字:





问题:我想要的是当用户检查CheckBox时,它应该将的TextField 3中已存在的值(与触发的CheckBox相同的行)添加10并更新TextField 3的文本,并在用户取消选中CheckBox时它应该从的TextField 3中的值中减去10 (与触发的CheckBox相同的行)并更新TextField 3的文本。我试图这样做但它不起作用(不添加和删除):





这就是我创建GridPane的方式:

  public static GridPane table(int rows){
GridPane table = new GridPane();

for(int i = 0; i< rows; i ++){
TextField textField = new TextField();
textField.setAlignment(Pos.CENTER);
TextField textField2 = new TextField();
textField2.setAlignment(Pos.CENTER);
CheckBox checkBox = new CheckBox(Check Box);
checkBox.setTextFill(Color.WHITE);
checkBox.setAlignment(Pos.CENTER);
TextField textField3 = new TextField();
textField3.setAlignment(Pos.CENTER);

table.add(textField,0,i);
table.add(textField2,1,i);
table.add(checkBox,2,i);
table.add(textField3,3,i);

GridPane.setMargin(textField,new Insets(5));
GridPane.setMargin(textField2,new Insets(5));
GridPane.setMargin(checkBox,new Insets(5));
GridPane.setMargin(textField3,new Insets(5));
}
table.setAlignment(Pos.CENTER);

返回表;
}

从特定行和列的表返回组件的方法

  public static Node getComponent(int row,int column,GridPane table){
for(Node component:table.getChildren() ){
if(GridPane.getRowIndex(component)== row&&
GridPane.getColumnIndex(component)== column){
return component;
}
}

返回null;
}

这就是我要添加的内容:

  public void add(GridPane table,int numRows){

for(int i = 0; i< numRows; i ++){
try {

int valueA = Integer.parseInt(((TextField)(getComponent(i,0,table)))。getText());
System.out.println(valueA);
int valueB = Integer.parseInt(((TextField)(getComponent(i,1,table)))。getText());
System.out.println(valueB);

int add = valueA + valueB;

String addToString = Integer.toString(add);

((TextField)(getComponent(i,3,table)))。setText(addToString);

} catch(NullPointerException e){
System.out.print(抓住NullPointerException);
}
}

}

问题:使用CheckBox进行加法和减法:

  public void addPause(GridPane table,int numRows){

for(int i = 0; i< numRows; i ++){

boolean pause =((CheckBox)(getComponent(i,2,table)))。isSelected() ;
int getTextValue = Integer.parseInt(((TextField)(getComponent(i,3,table)))。getText());

int addPause = getTextValue + 10;
int removePause = addPause-10;

String addPToString = Integer.toString(addPause);
String removePToString = Integer.toString(removePause);

if(pause){
((TextField)(getComponent(i,3,table)))。setText(addPToString);
} else {
((TextField)(getComponent(i,3,table)))。setText(removePToString);
}
}
}

这就是我的方式使用侦听器触发:

  for(节点node:table.getChildren()){
if(node instanceof TextField) {
((TextField)node).textProperty()。addListener((obs,old,newV) - > {
add(table,numRows);
});
}
else if(node instanceof CheckBox){
((CheckBox)node).selectedProperty()。addListener((obs,old,newV) - > {
addPause (table,numRows);
});
}
}


解决方案

As我建议您在



由于Java是一种面向对象的语言,因此在面向对象的方式中执行此操作似乎更合适。第一名。我不知道你在这个视图中代表了什么数据,但是你应该定义一个将数据封装在一行中的类:

  import javafx.beans.binding.Bindings; 
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;

//显然为类使用更合理的名称:
public class RowData {

private final IntegerProperty firstValue = new SimpleIntegerProperty();
private final IntegerProperty secondValue = new SimpleIntegerProperty();
private final BooleanProperty includePause = new SimpleBooleanProperty();
private final ReadOnlyIntegerWrapper total = new ReadOnlyIntegerWrapper();

public RowData(){
total.bind(Bindings.createIntegerBinding(() - > {
int total = getFirstValue()+ getSecondValue();
if(isIncludePause()){
total + = 10;
}
return total;
},firstValue,secondValue,includePause));
}

public final IntegerProperty firstValueProperty(){
return this.firstValue;
}


public final int getFirstValue(){
return this.firstValueProperty()。get();
}


public final void setFirstValue(final int firstValue){
this.firstValueProperty()。set(firstValue);
}


public final IntegerProperty secondValueProperty(){
return this.secondValue;
}


public final int getSecondValue(){
return this.secondValueProperty()。get();
}


public final void setSecondValue(final int secondValue){
this.secondValueProperty()。set(secondValue);
}


public final BooleanProperty includePauseProperty(){
return this.includePause;
}


public final boolean isIncludePause(){
return this.includePauseProperty()。get();
}


public final void setIncludePause(final boolean includePause){
this.includePauseProperty()。set(includePause);
}


public final ReadOnlyIntegerProperty totalProperty(){
return this.total.getReadOnlyProperty();
}


public final int getTotal(){
return this.totalProperty()。get();
}

}

然后是一个显示这些数据的类:

  import javafx.beans.binding.Bindings; 
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;

公共类RowDataView {

private final TextField firstValueField;
private final TextField secondValueField;
私有final CheckBox includePauseBox;
private final TextField totalField;

public RowDataView(RowData data){

firstValueField = new TextField();
bindToStringProperty(data.firstValueProperty(),firstValueField.textProperty());

secondValueField = new TextField();
bindToStringProperty(data.secondValueProperty(),secondValueField.textProperty());

includePauseBox = new CheckBox();
data.includePauseProperty()。bind(includePauseBox.selectedProperty());

totalField = new TextField();
totalField.setEditable(false);
totalField.textProperty()。bind(data.totalProperty()。asString());
}

public void addToGridPane(GridPane窗格,int row,int firstValueColumn,int secondValueColumn,int checkboxColumn,int totalColumn){
pane.add(firstValueField,firstValueColumn,row) ;
pane.add(secondValueField,secondValueColumn,row);
pane.add(includePauseBox,checkboxColumn,row);
pane.add(totalField,totalColumn,row);
}

public void addToGridPane(GridPane pane,int row,int column){
addToGridPane(窗格,行,列,列+ 1,列+ 2,列+ 3) );
}

public void addToGridPane(GridPane pane,int row){
addToGridPane(pane,row,0);
}

private void bindToStringProperty(IntegerProperty p,StringProperty s){
p.bind(Bindings.createIntegerBinding(
() - > {
if(s.get()。matches(\\\\ +)){
返回Integer.parseInt(s.get());
}
返回0;
},s));
}
}

这里有一些测试代码:

  import java.util.ArrayList; 
import java.util.List;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

公共类TableOfControlsInGridPane扩展Application {

private final List< RowData> data = new ArrayList<>();

@Override
public void start(Stage primaryStage){
场景场景=新场景(表(10),800,800);
scene.getStylesheets()。add(style.css);
primaryStage.setScene(scene);
primaryStage.show();
}

public GridPane table(int rows){
GridPane table = new GridPane();
table.getStyleClass()。add(data-grid);

data.clear();

for(int i = 0; i< rows; i ++){

RowData rowData = new RowData();
data.add(rowData);

RowDataView rowDataView = new RowDataView(rowData);
rowDataView.addToGridPane(table,i);
}
table.setAlignment(Pos.CENTER);
返回表;
}

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

我将样式移到了样式表( style.css ):

  .data-网格{
-fx-background-color:purple;
-fx-hgap:10;
-fx-vgap:10;
}
.data-grid .text-field,.data-grid .check-box {
-fx-alignment:center;
}
.data-grid .check-box {
-fx-text-fill:white;
}


I'm developing an app in JavaFx, in which which I'm dynamically creating TextFeids and CheckBoxes inside GridPane like this:

I'm adding numbers which user will enter in TextField 1 and TextField 2 and displaying in TextField 3 like this using listener:

Problem: What I want is when user will check the CheckBox it should add 10 to the value already present in the TextField 3 of (same row as of triggered CheckBox) and update the text of TextField 3, and when user will uncheck the CheckBox it should subtract 10 from the value present in the TextField 3 of (same row as of triggered CheckBox) and update the text of TextField 3. I tried to do it but it's not working (not adding and removing):

This is how I'm creating GridPane:

 public static GridPane table(int rows){
        GridPane table = new GridPane();

        for(int i=0; i<rows; i++){
            TextField textField = new TextField();
            textField.setAlignment(Pos.CENTER);
            TextField textField2 = new TextField();
            textField2.setAlignment(Pos.CENTER);
            CheckBox checkBox = new CheckBox("Check Box");
            checkBox.setTextFill(Color.WHITE);
            checkBox.setAlignment(Pos.CENTER);
            TextField textField3 = new TextField();
            textField3.setAlignment(Pos.CENTER);

            table.add(textField, 0, i);
            table.add(textField2, 1, i);
            table.add(checkBox , 2, i);
            table.add(textField3,3, i);

            GridPane.setMargin(textField, new Insets(5));
            GridPane.setMargin(textField2, new Insets(5));
            GridPane.setMargin(checkBox, new Insets(5));
            GridPane.setMargin(textField3, new Insets(5));
         }
        table.setAlignment(Pos.CENTER);

        return table;
    }

A method to return a component from Table at specific row and column

public static Node getComponent (int row, int column, GridPane table) {
     for (Node component : table.getChildren()) { 
         if(GridPane.getRowIndex(component) == row && 
                         GridPane.getColumnIndex(component) == column) {
             return component;
         }
     }

     return null;
 }

This is how I'm adding:

    public void add(GridPane table, int numRows){

       for(int i=0; i<numRows; i++){
           try {

                int valueA = Integer.parseInt(((TextField)(getComponent (i, 0, table))).getText());
                System.out.println(valueA);
                int valueB = Integer.parseInt(((TextField)(getComponent (i, 1, table))).getText());
                System.out.println(valueB);

                int add = valueA+valueB;

                String addToString = Integer.toString(add);

                ((TextField)(getComponent (i, 3, table))).setText(addToString);

                } catch (NullPointerException e) {
                  System.out.print("Caught the NullPointerException");
                    }
       }

    }

Problem: Addition and subtraction using CheckBox:

     public void addPause(GridPane table, int numRows){

                for(int i=0; i<numRows; i++){

                boolean pause = ((CheckBox)(getComponent (i, 2, table))).isSelected();
                int getTextValue = Integer.parseInt(((TextField)(getComponent (i, 3, table))).getText());

                int addPause = getTextValue+10;
                int removePause = addPause-10;

                String addPToString = Integer.toString(addPause);
                String removePToString = Integer.toString(removePause);

                if (pause) {
                    ((TextField)(getComponent (i, 3, table))).setText(addPToString);
                } else {
                    ((TextField)(getComponent (i, 3, table))).setText(removePToString);
                }
       }
    }

This is how I'm triggering using listeners:

        for(Node node : table.getChildren()){ 
          if(node instanceof TextField){
             ((TextField)node).textProperty().addListener((obs, old, newV)->{
               add(table, numRows);
           });
         }
          else if(node instanceof CheckBox){
              ((CheckBox)node).selectedProperty().addListener((obs, old, newV)->{ 
                addPause(table, numRows);
             });
           }
       }

解决方案

As I suggested in your previous question, just register the listeners for the controls at the point you create them.

You can actually just use a single listener (in each row) for the two text fields and check box, and update the third text box when any of those change. For example:

public static GridPane table(int rows){
    GridPane table = new GridPane();

    for(int i=0; i<rows; i++){
        TextField textField = new TextField();
        textField.setAlignment(Pos.CENTER);
        TextField textField2 = new TextField();
        textField2.setAlignment(Pos.CENTER);
        CheckBox checkBox = new CheckBox("Check Box");
        checkBox.setTextFill(Color.WHITE);
        checkBox.setAlignment(Pos.CENTER);
        TextField textField3 = new TextField();
        textField3.setAlignment(Pos.CENTER);

        table.add(textField, 0, i);
        table.add(textField2, 1, i);
        table.add(checkBox , 2, i);
        table.add(textField3,3, i);

        ChangeListener<Object> listener = (obs, oldValue, newValue) -> 
            updateTotalField(textField.getText(), textField2.getText(), checkBox.isSelected(), textField3);

        textField.textProperty().addListener(listener);
        textField2.textProperty().addListener(listener);
        checkBox.selectedProperty().addListener(listener);

        GridPane.setMargin(textField, new Insets(5));
        GridPane.setMargin(textField2, new Insets(5));
        GridPane.setMargin(checkBox, new Insets(5));
        GridPane.setMargin(textField3, new Insets(5));
     }
    table.setAlignment(Pos.CENTER);

    return table;
}

private static void updateTotalField(String text1, String text2, boolean addPause, TextField output) {
    int value1 = parseText(text1);
    int value2 = parseText(text2);
    int total = value1 + value2 ;
    if (addPause) {
        total += 10 ;
    }
    output.setText(Integer.toString(total));
}

private static int parseText(String text) {
    // if text is a valid integer:
    if (text.matches("\\d+")) {
        return Integer.parseInt(text);
    } else {
        return 0 ;
    }
}

Now you can get rid of the add and addPause method, and the chunk of code you posted where you iterate through the child nodes of the grid pane and add listeners. You may be able to get rid of the getComponent() method to, unless you need it elsewhere.

Here is the code as a SSCCE

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class TableOfControlsInGridPane extends Application {

    @Override
    public void start(Stage primaryStage) {
        Scene scene = new Scene(table(10));
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public GridPane table(int rows){
        GridPane table = new GridPane();

        for(int i=0; i<rows; i++){
            TextField textField = new TextField();
            textField.setAlignment(Pos.CENTER);
            TextField textField2 = new TextField();
            textField2.setAlignment(Pos.CENTER);
            CheckBox checkBox = new CheckBox("Check Box");
            checkBox.setTextFill(Color.WHITE);
            checkBox.setAlignment(Pos.CENTER);
            TextField textField3 = new TextField();
            textField3.setAlignment(Pos.CENTER);

            table.add(textField, 0, i);
            table.add(textField2, 1, i);
            table.add(checkBox , 2, i);
            table.add(textField3,3, i);

            ChangeListener<Object> listener = (obs, oldValue, newValue) -> 
                updateTotalField(textField.getText(), textField2.getText(), checkBox.isSelected(), textField3);

            textField.textProperty().addListener(listener);
            textField2.textProperty().addListener(listener);
            checkBox.selectedProperty().addListener(listener);

            GridPane.setMargin(textField, new Insets(5));
            GridPane.setMargin(textField2, new Insets(5));
            GridPane.setMargin(checkBox, new Insets(5));
            GridPane.setMargin(textField3, new Insets(5));
         }
        table.setAlignment(Pos.CENTER);

        return table;
    }

    private void updateTotalField(String text1, String text2, boolean addPause, TextField output) {
        int value1 = parseText(text1);
        int value2 = parseText(text2);
        int total = value1 + value2 ;
        if (addPause) {
            total += 10 ;
        }
        output.setText(Integer.toString(total));
    }

    private int parseText(String text) {
        // if text is a valid integer:
        if (text.matches("\\d+")) {
            return Integer.parseInt(text);
        } else {
            return 0 ;
        }
    }

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

and a screenshot:

Since Java is an object-oriented language, it would probably seem more appropriate to do this in an object-oriented way in the first place. I have no idea what data you are representing in this view, but you should define a class that encapsulates the data in a single row:

import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;

// Obviously use a more sensible name for the class:
public class RowData {

    private final IntegerProperty firstValue = new SimpleIntegerProperty();
    private final IntegerProperty secondValue = new SimpleIntegerProperty();
    private final BooleanProperty includePause = new SimpleBooleanProperty();
    private final ReadOnlyIntegerWrapper total = new ReadOnlyIntegerWrapper();

    public RowData() {
        total.bind(Bindings.createIntegerBinding(() -> {
            int total = getFirstValue() + getSecondValue() ;
            if (isIncludePause()) {
                total += 10 ;
            }
            return total ;
        }, firstValue, secondValue, includePause));
    }

    public final IntegerProperty firstValueProperty() {
        return this.firstValue;
    }


    public final int getFirstValue() {
        return this.firstValueProperty().get();
    }


    public final void setFirstValue(final int firstValue) {
        this.firstValueProperty().set(firstValue);
    }


    public final IntegerProperty secondValueProperty() {
        return this.secondValue;
    }


    public final int getSecondValue() {
        return this.secondValueProperty().get();
    }


    public final void setSecondValue(final int secondValue) {
        this.secondValueProperty().set(secondValue);
    }


    public final BooleanProperty includePauseProperty() {
        return this.includePause;
    }


    public final boolean isIncludePause() {
        return this.includePauseProperty().get();
    }


    public final void setIncludePause(final boolean includePause) {
        this.includePauseProperty().set(includePause);
    }


    public final ReadOnlyIntegerProperty totalProperty() {
        return this.total.getReadOnlyProperty();
    }


    public final int getTotal() {
        return this.totalProperty().get();
    }

}

Then a class to display those data:

import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;

public class RowDataView {

    private final TextField firstValueField ;
    private final TextField secondValueField ;
    private final CheckBox includePauseBox ;
    private final TextField totalField ;

    public RowDataView(RowData data) {

        firstValueField = new TextField();
        bindToStringProperty(data.firstValueProperty(), firstValueField.textProperty());

        secondValueField = new TextField();
        bindToStringProperty(data.secondValueProperty(), secondValueField.textProperty());

        includePauseBox = new CheckBox();
        data.includePauseProperty().bind(includePauseBox.selectedProperty());

        totalField = new TextField();
        totalField.setEditable(false);
        totalField.textProperty().bind(data.totalProperty().asString());
    }

    public void addToGridPane(GridPane pane, int row, int firstValueColumn, int secondValueColumn, int checkboxColumn, int totalColumn) {
        pane.add(firstValueField, firstValueColumn, row);
        pane.add(secondValueField, secondValueColumn, row);
        pane.add(includePauseBox, checkboxColumn, row);
        pane.add(totalField, totalColumn, row);
    }

    public void addToGridPane(GridPane pane, int row, int column) {
        addToGridPane(pane, row, column, column+1, column+2, column+3);
    }

    public void addToGridPane(GridPane pane, int row) {
        addToGridPane(pane, row, 0);
    }

    private void bindToStringProperty(IntegerProperty p, StringProperty s) {
        p.bind(Bindings.createIntegerBinding(
                () -> {
                    if (s.get().matches("\\d+")) {
                        return Integer.parseInt(s.get());
                    }
                    return 0 ;
                }, s));
    }
}

and here is some test code:

import java.util.ArrayList;
import java.util.List;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

public class TableOfControlsInGridPane extends Application {

    private final List<RowData> data = new ArrayList<>();

    @Override
    public void start(Stage primaryStage) {
        Scene scene = new Scene(table(10), 800, 800);
        scene.getStylesheets().add("style.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public GridPane table(int rows){
        GridPane table = new GridPane();
        table.getStyleClass().add("data-grid");

        data.clear();

        for(int i=0; i<rows; i++){

            RowData rowData = new RowData();
            data.add(rowData);

            RowDataView rowDataView = new RowDataView(rowData);
            rowDataView.addToGridPane(table, i);
         }
        table.setAlignment(Pos.CENTER);
        return table;
    }

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

I moved the styles to the style sheet (style.css):

.data-grid {
    -fx-background-color: purple ;
    -fx-hgap: 10 ;
    -fx-vgap: 10 ;  
}
.data-grid .text-field, .data-grid .check-box {
    -fx-alignment: center ;
}
.data-grid .check-box {
    -fx-text-fill: white ;
}

这篇关于JavaFx:如何在GridPane中更新动态创建的TextField文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆