当前位置: 首页 > 知识库问答 >
问题:

JavaFx:如何实现动态网格窗格?

蔡默
2023-03-14

我正在JavaFx中开发一个应用程序,其中我有两个选项卡。

在第一个选项卡中,我有ComboBox:

在第二个选项卡中,我有这样的Gridpane:

我想要的是当用户从Tab A的组合框中选择3时,例如:

它应该在Tab B的Gridpane中添加3行,每列添加文本字段、复选框和datepicker。A列有文本字段,B列有复选框,C列有日期选择器,如下所示:

请帮助我如何才能实现这一点,实现后,我如何才能访问每个文本字段,复选框和日期选择器的数据

更新:尝试使用FXML执行@Yahya解决方案

主要.java

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            TabPane root = (TabPane)FXMLLoader.load(getClass().getResource("Sample.fxml"));
            Scene scene = new Scene(root,400,400);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

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

SampleController.java

public class SampleController {

    @FXML
    private TabPane root ;
    @FXML
    private Tab tabA ;
    @FXML
    private Tab tabB ;
    @FXML
    private ComboBox<Integer> comboBox ;
    @FXML
    private static GridPane gridPane ;
    @FXML
    private AnchorPane anchB ;


public void initialize() {

    // Create a comboBox, set its attributes and add it to container
    comboBox.getItems().addAll(1,2,3,4,5,6,7,8,9,10);
    comboBox.setValue(1);
    comboBox.setEditable(false);
   // anchA.getChildren().add(comboBox);

    // add listener to tabPane
    root.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>(){
         @Override
         public void changed(ObservableValue<? extends Tab> observable, Tab oldTab, Tab newTab){
              if(newTab == tabB) { // when tabB is selected
                  System.out.println(anchB.getChildren().size());
                  if(anchB.getChildren().size()<=0){ // if already contains a table

                      anchB.getChildren().add(table(comboBox.getValue())); 

                      table(comboBox.getValue());
                      System.out.println("hello");
                  }
                  else {
                  anchB.getChildren().remove(gridPane); // remove it
                  System.out.println("no");
                  }
            }
       }   
   });
}

//This static method shall create the table dynamically when it's called
// you can add, change and remove the attributes of the table components
// the colors and all other decoration(e.g. position) are for example
public static GridPane table(int rows){

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

        //add them to the GridPane
        gridPane.add(textField, 0, i+1); //  (child, columnIndex, rowIndex)
        gridPane.add(checkBox , 1, i+1);
        gridPane.add(datePicker,2, i+1);

        // margins are up to your preference
        GridPane.setMargin(textField, new Insets(5));
        GridPane.setMargin(checkBox, new Insets(5));
        GridPane.setMargin(datePicker, new Insets(5));
     }

    return gridPane;

}
}

Sample.fxml

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

<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Text?>

<TabPane fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" tabClosingPolicy="UNAVAILABLE" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.SampleController">
   <tabs>
      <Tab fx:id="tabA" text="Tab A">
         <content>
            <AnchorPane fx:id="anchA" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
               <children>
                  <ComboBox fx:id="comboBox" layoutX="225.0" layoutY="82.0" prefWidth="150.0" />
               </children>
            </AnchorPane>
         </content>
      </Tab>
      <Tab fx:id="tabB" text="Tab B">
         <content>
            <AnchorPane fx:id="anchB" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
               <children>
                  <GridPane fx:id="gridPane" gridLinesVisible="true" layoutX="150.0" layoutY="62.0">
                     <columnConstraints>
                        <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                        <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                        <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                     </columnConstraints>
                     <rowConstraints>
                        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                     </rowConstraints>
                     <children>
                        <Text strokeType="OUTSIDE" strokeWidth="0.0" text="A" textAlignment="CENTER" wrappingWidth="91.67529296875" />
                        <Text strokeType="OUTSIDE" strokeWidth="0.0" text="B" textAlignment="CENTER" wrappingWidth="93.5986328125" GridPane.columnIndex="1" />
                        <Text strokeType="OUTSIDE" strokeWidth="0.0" text="C" textAlignment="CENTER" wrappingWidth="95.287109375" GridPane.columnIndex="2" />
                     </children>
                  </GridPane>
               </children>
            </AnchorPane>
         </content>
      </Tab>
   </tabs>
</TabPane>

共有1个答案

慕容宏邈
2023-03-14

你可以这样做:

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class DynamicTable extends Application{

    @Override
    public void start(Stage ps) throws Exception {

        // Create a Tab A, create a container and add it 
        Tab tabA = new Tab("Tab A");
        StackPane containerA = new StackPane();

        // note that the colors are for example
        containerA.setBackground(new Background(
                new BackgroundFill(Color.MAROON,null,null)));
        // Create a comboBox, set its attributes and add it to container
        ComboBox<Integer> comboBox = new ComboBox<Integer>();
        comboBox.getItems().addAll(1,2,3,4,5,6,7,8,9,10);
        comboBox.setValue(1);
        comboBox.setEditable(false);
        containerA.getChildren().add(comboBox);

        //add the container to the tabA
        tabA.setContent(containerA);

        // Create Tab B, create a container and add it 
        Tab tabB = new Tab("Tab B");
        StackPane containerB = new StackPane();

        containerB.setBackground(new Background(
                        new BackgroundFill(Color.DARKMAGENTA,null,null)));
        tabB.setContent(containerB);
        // create TabPane and add the Tabs to it
        // all other values need manipulation (i.e. up to your preference)
        TabPane tabPane = new TabPane();
         tabPane.getTabs().addAll(tabA, tabB);
        //set size and other attributes (if any), for example 
        tabPane.setMinWidth(500);
        tabPane.setMinHeight(500);

         // add listener to tabPane
         tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>(){
              @Override
              public void changed(ObservableValue<? extends Tab> observable, Tab oldTab, Tab newTab){
                   if(newTab == tabB) { // when tabB is selected
                       if(containerB.getChildren().size()>0){ // if already contains a table
                           containerB.getChildren().remove(0); // remove it
                       }
                       containerB.getChildren().add(table(comboBox.getValue())); // create the table and add it   
                 }
            }   
        });

        // simple root to test 
        Pane root = new Pane();
        root.getChildren().add(tabPane);

        Scene scene = new Scene(root, 500,500);
        ps.setScene(scene);
        ps.setTitle("Dynamic Table In Tab");
        ps.show();
    }


    // This static method shall create the table dynamically when it's called
    // you can add, change and remove the attributes of the table components
    // the colors and all other decoration(e.g. position) are 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);
            CheckBox checkBox = new CheckBox("Check Box");
            checkBox.setTextFill(Color.WHITE);
            checkBox.setAlignment(Pos.CENTER);
            DatePicker datePicker = new DatePicker();

            //add them to the GridPane
            table.add(textField, 0, i); //  (child, columnIndex, rowIndex)
            table.add(checkBox , 1, i);
            table.add(datePicker,2, i);

            // margins are up to your preference
            GridPane.setMargin(textField, new Insets(5));
            GridPane.setMargin(checkBox, new Insets(5));
            GridPane.setMargin(datePicker, new Insets(5));
         }
        table.setAlignment(Pos.CENTER);

        return table;

    }

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

    }
}

测试

更新:如果要从 TabB 中的表中获取值,可以执行如下操作:

// first create a method like this
// this static 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()) { // loop through every node in the table
        if(GridPane.getRowIndex(component) == row && 
                        GridPane.getColumnIndex(component) == column) {
            return component;
        }
    }

    return null;
}

// Then use the method like this
// The textfield always at Column 0, check box column 1 and Date picker 2
// and the GridPane is in a StackPane(container) at index 0
// Note that you may NEED to add a button and wrap the following code with its Action Listener (i.e. button.setOnAction())
if(containerB.getChildren().size()>0){ // that means it contains a table    
    GridPane table = (GridPane) containerB.getChildren().get(0);
    for(int i=0 ; i<comboBox.getValue(); i++){
        String Text = ((TextField)getComponent (i, 0, table)).getText();
        boolean selected = ((CheckBox)getComponent (i, 1, table)).isSelected();
        LocalDate date = ((DatePicker)getComponent (i, 2, table)).getValue();

        System.out.println(Text + " " + selected + " " + date);
        System.out.println("Next Row");
    }

}

更新:

如果您希望您的程序仅在用户更改了< code>ComboBox中的值时才删除/创建表(< code>GridPane),那么您需要向您的< code>ComboBox添加一个ChangeListener来捕捉其中的更改,因此您需要一个全局的< code>boolean,当< code>ComboBox值更改时,它会从< code>true更改为< code>false,反之亦然,并且此< code >

boolean valueChanged = false; // its scope should be global and to be added to the ComboBox ChangeListener
if(containerB.getChildren().size()>0 && valueChanged){ // if already contains a table
    containerB.getChildren().remove(0); // remove it
}
 类似资料:
  • 我试图将乘法VBox添加到scrollpane中的gridpane(在下面的codesnippet中称为refPane)。 它在一行中添加不超过ITEMS_PER_ROW的Vbox,并在下一行中继续。也不应该有更多的行,然后ITEMS_PER_COLUM可见。问题是,如果我添加更多的ITEMS_PER_ROW*ITEMS_PER_COLUMN到网格中,而不是obingbeingscrollable

  • 我无法在SceneBuilder(eclipse)中使用GridPane,当我尝试在项目中插入GridPane时,SceneBuilder会在没有提示任何消息的情况下退出。 这就是我在日志文件中找到的:

  • 有人能举一个简单的例子来说明如何设置EventHandler以在窗格(JavaFX)上拖动图像视图。对于拖动,我的意思是在图像上按下鼠标,拖动和图像应该跟随,然后释放鼠标,图像视图将停止在该位置。

  • 我想在不收缩的情况下动态添加ui节点到gridapanes行..而不是收缩gridpane应该启用滚动(网格窗格在滚动窗格中)..但它们都不是... iam所尝试的只是创建一个事件calander,该事件calander能够将整个月的事件作为天在顶部行中查看(因此至少30个colomuns) ---->控制器类包示例;

  • 下面是主界面,我想动态添加包含名称、作者、描述和按钮的窗格。 在这里,它很好地扩展到可用的宽度。 这是我上面UI的FXML代码 任何帮助都会得到很大的支持...

  • 嘿,我有一个网格,对于其中一个节点,我希望它能够占据整行。 但我似乎不知道如何使用GridPane.setColumnSpan(node,column span); 这是我的代码 这就是现在的样子 这就是我想要的样子 我将非常感谢任何帮助。谢谢