-1

I have two controllers:

  1. Main which contains TableView Tab which displays SQLITE database tables (which contain different number of columns) in tabular format, and
  2. Rem which contains a button which dictates which database to display (there are many such controllers).

Now if I create a method in Main which is responsible for updating and displaying TableView contents, how do I use that method in other controller?

I created two static ObservableList variables columns and rows and bind them to Tab in Main's initialize.

APP.java

public class App extends Application {

    private static Scene scene;
    public static Connection conn;
    @Override
    public void start(Stage stage) throws IOException {
        try{
        conn=java.sql.DriverManager.getConnection("jdbc:sqlite:sample.db");
        if(conn!=null){
            conn.createStatement().execute("CREATE TABLE IF NOT EXISTS tab1(Field0 TEXT, Field1 TEXT, Field2 TEXT);");
            conn.createStatement().execute("CREATE TABLE IF NOT EXISTS tab2(Field3 TEXT, Field4 TEXT);");
        }
        }catch(Exception ex){
            System.out.println(ex);
        }
        scene = new Scene(loadFXML("main"), 640, 480);
        stage.setScene(scene);
        stage.show();
    }
    private static Parent loadFXML(String fxml) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
        return fxmlLoader.load();
    }

    public static void main(String[] args) {
        launch();
    }
    public static ResultSet getRS(String table){
        String sql="SELECT * FROM "+table;
        ResultSet rs=null;
        try{
            rs=conn.createStatement().executeQuery(sql);
        }catch(Exception ex){
            System.out.println(ex);
        }
        return rs;
    }
}

MAIN.FXML

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

<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.VBox?>

<VBox xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nic.testfx.Main">
   <children>
      <MenuBar>
        <menus>
          <Menu mnemonicParsing="false" text="File">
            <items>
              <MenuItem mnemonicParsing="false" onAction="#loadRem" text="Load Remaining" />
            </items>
          </Menu>
        </menus>
      </MenuBar>
      <TableView fx:id="Tab" prefHeight="200.0" prefWidth="200.0" />
      <VBox fx:id="remPane" prefHeight="200.0" prefWidth="100.0" />
   </children>
</VBox>

MAIN.JAVA

public class Main implements Initializable {
    @FXML
    public TableView<ObservableList<String>> Tab;
    @FXML
    private VBox remPane;
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        Tab.itemsProperty().bind(getTabRow());
    }
public void makeTable(ResultSet rs){
    try{
        var rsm=rs.getMetaData();
        ObservableList<TableColumn<ObservableList<String>,String>>cols=FXCollections.observableArrayList();
        for(int i=0;i<rsm.getColumnCount();i++){
            final int j=i;
            TableColumn<ObservableList<String>,String> col=new TableColumn(rsm.getColumnName(i+1));
            col.setCellValueFactory(param->new SimpleStringProperty(param.getValue().get(j)));
            cols.add(col);
        }
        ObservableList<ObservableList<String>> arows=FXCollections.observableArrayList();
        while(rs.next()){
            ObservableList<String> row=FXCollections.observableArrayList();
            for(int i=1;i<=rsm.getColumnCount();i++){
                row.add(rs.getString(i));
            }
            arows.add(row);
        }
        setTable(cols,arows);
    }catch(Exception ex){
        System.out.println(ex);
    }
}
    private static final ObservableList<TableColumn<ObservableList<String>,String>> columns=FXCollections.observableArrayList();
    private static final javafx.beans.property.ListProperty<ObservableList<String>> rows=new javafx.beans.property.SimpleListProperty();
    private javafx.beans.property.ListProperty getTabRow(){
        Tab.getColumns().clear();
        Tab.getColumns().addAll(columns);
        return rows;
    }
    private static void setTable(ObservableList<TableColumn<ObservableList<String>,String>>c,ObservableList<ObservableList<String>> r){
        columns.setAll(c);
        rows.set(r);
    }

    @FXML
    private void loadRem(ActionEvent event) {
        try{
            for(int i=remPane.getChildren().size()-1;i>=0;i--){
                    remPane.getChildren().remove(i);
                }
                javafx.fxml.FXMLLoader fxmlLoader=new javafx.fxml.FXMLLoader();
                fxmlLoader.setLocation(getClass().getResource("rem.fxml"));
                javafx.scene.layout.Pane panel=fxmlLoader.load();
                remPane.getChildren().add(panel);
                makeTable(App.getRS("tab1"));
        }catch(Exception ex){
            System.out.println(ex);
        }
    }
}

REM.FXML

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>

<VBox alignment="CENTER" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nic.testfx.Rem">
   <children>
      <Button fx:id="btn" mnemonicParsing="false" onAction="#loadTab" text="Button" />
   </children>
</VBox>

REM.JAVA

public class Rem implements Initializable {

    @FXML
    private Button btn;
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    
    @FXML
    private void loadTab(ActionEvent event) {
        try{
            var fxml=new javafx.fxml.FXMLLoader(App.class.getResource("main.fxml"));
            fxml.load();
            Main controller=fxml.getController();
            var rs=App.getRS("tab2");
            controller.makeTable(rs);
        }catch(Exception ex){
            System.out.println(ex);
        }
    }
}
JavaUser
  • 19
  • 3
  • 1
    same comment as to your previous question: [mcve] please .. (don't delete and repost!) – kleopatra Dec 17 '22 at 09:41
  • Sorry but I don't understand how "minimal" does my code needs to be compared to what I've posted here. What else do I have to remove/add in this? If I add fxml files, database creation code, then it won't be minimal anymore. – JavaUser Dec 17 '22 at 09:48
  • read the referenced help page and act accordingly – kleopatra Dec 17 '22 at 09:49
  • 1
    You need to post code that can be copied, compiled and executed. Your question does not contain the FXML file nor does it contain the class that extends `javafx.application.Application`. Or maybe this will help: [SSCCE: How to provide examples for programming questions](https://meta.stackexchange.com/questions/22754/sscce-how-to-provide-examples-for-programming-questions) – Abra Dec 17 '22 at 10:01
  • That's what I did in my last question but then I was asked to make it minimal. I'll add the FXML and `App` here now. – JavaUser Dec 17 '22 at 10:25
  • Alternatively, consider [pagination](https://stackoverflow.com/a/74480486/230513). – trashgod Dec 17 '22 at 13:56
  • 2
    the example has to be stand-alone, runnable as-is _for potential helpers_ - yours isn't due to the database access (which we don't have). To fix, hard-code some data. Also: stick to java naming conventions when showing java code publicly. And don't use static scope for anything: instead learn how to pass parameters across controllers/Application (the java tag wiki - "learn more" on the list of questions page - has several entries in its FAQ section) – kleopatra Dec 17 '22 at 13:57
  • 1
    I haven’t gone through all you code, which looks convoluted with way too much interdependency between the classes. But it’s generally bad practice to have controllers directly communicating with each other. Instead, consider using a MVC approach. There’s an example [here](https://stackoverflow.com/questions/32342864/applying-mvc-with-javafx) – James_D Dec 17 '22 at 14:57

1 Answers1

-1

OK I got it. Created a java class which encapsulate method makeTable:

MODEL.JAVA

public class Model{
    private final TableView table;
    public Model(TableView t){
        this.table=t;
    }
    public void makeTable(ResultSet rs){
        ObservableList<TableColumn<ObservableList<String>,String>>tabcols=FXCollections.observableArrayList();
        ObservableList<ObservableList<String>>tabrows=FXCollections.observableArrayList();
        //Create TableColumns and add to tabcols;
        while(rs.next()){
            //Create ObservableList<String>, get data from rs, and add to tabrows
        }
        this.table.getColumns().setAll(tabcols);
        this.table.getItems().setAll(tabrows);
    }
}

Next, in Controller file Main.java created a static instance of Model:

MAIN.JAVA

public class Main implements Initializable{
    @FXML
    private TableView<ObservableList<String>> Tab;
    static Model model;
    @Override
    public void initialize (URL url, ResourceBundle rb){
        model=new Model(Tab);
    }
}

Now I can use model from Rem controller:

REM.JAVA

public class Rem implements Initializable{
    @FXML
    private Button btn;
    @Override
    public void initialize (URL url, ResourceBundle rb){
       //TODO
    }
    @FXML
    private void loadTab(ActionEvent event){
        var rs=App.getRS("tab2");
        Main.model.makeTable(rs);
}
JavaUser
  • 19
  • 3