Best Practice JTable in MVC Pattern

cyb0rg

Aktives Mitglied
Hallo Zusammen,
ich arbeite gerade an folgenden Code:
Code:
public class mainGUIController {
    private ch.becit.m2o.views.mainGUIView mainGUIView;
    private ch.becit.m2o.models.mainGUIModel mainGUIModel;

    private JTable table;

    public mainGUIController(mainGUIView mainGUIView, mainGUIModel mainGUIModel) {
        this.mainGUIView = mainGUIView;
        this.mainGUIModel = mainGUIModel;
        this.mainGUIModel.setTitle("m2o");

        this.mainGUIView.setTitle(this.mainGUIModel.getTitle());

        setTable();

        // Add Action Listener
        this.mainGUIView.addActionListenerjMenuItemSettings(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                settingsView settingsView = new settingsView();
                settingsModel settingsModel = new settingsModel();
                settingsController settingsController = new settingsController(settingsView, settingsModel);
            }
        });

        this.mainGUIView.addActionListenerjMenuItemQuit(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });

    }

    public void loadSettings() {
        try {

            Properties properties = new Properties();
            FileInputStream fileInputStream = new FileInputStream(("m2o.config"));

            properties.load(fileInputStream);
            fileInputStream.close();

            this.mainGUIModel.setRootPath(properties.getProperty("rootPath", "Not Set"));

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void listFiles(String path){
        try(Stream<Path> paths = Files.walk(Paths.get(path))) {
            paths.forEach((Path filePath) -> {
                if (Files.isRegularFile(filePath)) {
                    //this.mainGUIModel.addData(filePath.toString(),true);
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setTable(){
            this.table = new JTable(this.mainGUIModel.getData(),this.mainGUIModel.getColumnNames());
            JScrollPane scrollPane = new JScrollPane(this.table);
            table.setFillsViewportHeight(true);
            this.mainGUIView.addComponents(scrollPane);
    }
}
Code:
public class mainGUIModel {
    // Frame Settings Variables
    private String title;

    // Table Settings Variables
    private String rootPath;
    private String[] columnNames = {"FileName"};
    private String[] data = {
            "Snowboarding",
            "John",
            "Sue",
            "Jane",
            "Joe"
    };

    private ArrayList<String> dataTemp;

    public mainGUIModel() {
        this.title = "";
    }

    // Getter
    public String getTitle() {
        return this.title;
    }

    public String getRootPath() {
        return rootPath;
    }

    public String[] getData(){
        return this.data;
    }

    public String[] getColumnNames(){
        return this.columnNames;
    }

    // Setter
    public void setTitle(String title) {
        this.title = title;
    }

    public void setRootPath(String rootPath) {
        this.rootPath = rootPath;
    }

    public void addData(String fileName, Boolean value){
        this.dataTemp.add(fileName);
    }
}
Code:
public class mainGUIView extends JFrame {

    private JFrame frame;

    // Menu Object definitions
    private JMenuBar jMenuBar;

    // Table Objects definitions
    /*private String[] columnNames = {"FileName",
            "Choosen"};
    private Object[][] data = {
            {"Snowboarding", true},
            {"John", true},
            {"Sue", false},
            {"Jane" ,true},
            {"Joe",false}
    };*/

    private JTable table;

    // Menu File
    private JMenu jMenuFile;
    private JMenuItem jMenuItemSettings;
    private JMenuItem jMenuItemQuit;


    public mainGUIView() {
        this.frame = new JFrame();
        this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        buildComponents(this.frame.getContentPane());
    }

    private void buildComponents(Container pane) {

        try {
            settings();

            this.frame.setJMenuBar(this.jMenuBar);


            // Settings for the Frame
            this.frame.setPreferredSize(new Dimension(200, 200));
            this.frame.setVisible(true);
            this.frame.pack();

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }


    }

    private void settings() {
        // Build objects
        this.jMenuFile = new JMenu("File");
        this.jMenuBar = new JMenuBar();
        this.jMenuItemSettings = new JMenuItem("Settings");
        this.jMenuItemQuit = new JMenuItem("Quit");


        // add objects
        this.jMenuFile.add(jMenuItemSettings);
        this.jMenuFile.add(jMenuItemQuit);
        this.jMenuBar.add(this.jMenuFile);
    }

    private void table(String[] columnNames, String[][]data){
        // Building Table
        this.table = new JTable(data, columnNames);

    }
    // Add Components
    public void addComponents(Object comp){
        this.frame.getContentPane().add((Component) comp, BorderLayout.CENTER);
        this.frame.pack();
    }

    // Add ActionListeners
    public void addActionListenerjMenuItemSettings(ActionListener actionListener){
        this.jMenuItemSettings.addActionListener(actionListener);
    }
    public void addActionListenerjMenuItemQuit(ActionListener actionListener){
        this.jMenuItemQuit.addActionListener(actionListener);
    }

    // Setter
    // TODO: Unit Tests
    public void setTitle(String title){
        this.frame.setTitle(title);
    }
}

mein Problem bzw Frage lautet:

ich würde jetzt gerne die JTable so implementieren, dass ich die Table über den Controller und Model kontrollieren kann, doch im moment verliere ich mich da. Klar ich könnte jetzt die JTable direkt im View implementieren (wie es zu testzwecken war) doch dann wären ja die Daten nicht im Model und der Controller würde dann wohl nur noch die Listener implementieren, doch ich möchte es richtig machen und habe im moment keine idee mehr wie ich es machen soll / muss. Als ich das Refactoring anfing um es zum Controller bzw Model auszulagern, merkte ich relativ schnell dass da leider nochein paar abhängigkeiten nicht berücksichtigt habe, wie unter anderem... ich muss es ja im Scrollpane hinzufügen, welches ich ja dem frame adden muss, etc.. darauf habe ich aber lediglich über den View zugriff und nicht den controller, wie macht man das? konnte leider auf dem netzt kein praktikables bsp dazu finden.
 

vielen dank! das hat mir weitergeholfen! den neuen funktionierende Code poste ich unten, bin gespannt auf feedback 🙂
Das da ist falsch bzw. unsauber. dein mainGUIView ist ja schon ein JFrame ! Jetzt hast du zwei
vielen dank für den hinweis! habe ich entsprechend entfernt 🙂

diesmal habe ich lediglich den relevanteren code herausgefiltert.. wird sonst etwas to much..
Code:
public class Table {
    private String filePath;

    // TODO: UnitTests
    public String getFilePath() {
        return filePath;
    }

    // TODO: UnitTests
    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

}
Code:
public class TableModel extends AbstractTableModel{
    private List<Table> table = new ArrayList();
    private String[] columnNames = {"Filepath"};


    @Override
    public String getColumnName(int columnName){
        return this.columnNames[columnName];
    }
    @Override
    public int getRowCount() {
        return this.table.size();
    }

    @Override
    public int getColumnCount() {
        return this.columnNames.length;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        switch (columnIndex){
            case 0:
                return this.table.get(rowIndex).getFilePath();
        }
        return null;
    }

    public void addRow(Table table){
        this.table.add(table);
//        fireTableRowsInserted(this.table.size() - 1, this.table.size() -1);
        fireTableDataChanged();
    }

    public void removeValue(Table table){
        this.table.remove(table);
//        fireTableRowsInserted(this.table.size() - 1, this.table.size() -1);
    }
}

Code:
public class mainGUIController {
        setTable();
    }
    public void listFiles(String path) {
        try (Stream<Path> paths = Files.walk(Paths.get(path))) {
            paths.forEach((Path filePath) -> {
                if (Files.isRegularFile(filePath)) {
                    Table f = new Table();
                    f.setFilePath(filePath.toString());
                    this.tableModel.addRow(f);
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void setTable() {
        this.tableModel = new TableModel();
        this.mainGUIView.setTableModel(tableModel);
    }
}
hier merke ich grad beim posten... eigentlich könnte ich die zwei funktionen private setzen, die brauch ich nähmlich nicht public...
Code:
public class mainGUIView extends JFrame {
    public mainGUIView() {
        super("m2o");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        buildComponents(getContentPane());
    }

    private void buildComponents(Container pane) {

        try {
            settings();
            setJMenuBar(this.jMenuBar);
            this.table = new JTable();
            this.scrollPane = new JScrollPane(this.table);

            this.table.setFillsViewportHeight(true);

//            TableModel tableModel = new TableModel();
//            this.table.setModel(tableModel);
            addComponents(this.scrollPane);

            // Settings for the Frame
            setPreferredSize(new Dimension(200, 200));
            setVisible(true);
            pack();

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
    private void settings() {
        // Build objects
        this.jMenuFile = new JMenu("File");
        this.jMenuBar = new JMenuBar();
        this.jMenuItemSettings = new JMenuItem("Settings");
        this.jMenuItemQuit = new JMenuItem("Quit");


        // add objects
        this.jMenuFile.add(jMenuItemSettings);
        this.jMenuFile.add(jMenuItemQuit);
        this.jMenuBar.add(this.jMenuFile);
    }
    // Add Components
    public void addComponents(Object comp){
        getContentPane().add((Component) comp, BorderLayout.CENTER);
        pack();
    }
    // Setter
    // TODO: Unit Tests
    public void setTitle(String title){
        setTitle(title);
    }

    public void addScrollpaneComponent(Component component){
        this.scrollPane.add(component);
    }

    public void setTableModel(TableModel tableModel){
        this.table.setModel(tableModel);
    }
}

so ich denke das relevanteste ist drinn... da ist sicherlich noch vebesserungspotential, was meint ihr dazu?
 
Ich habe den Code jetzt nur überflogen aber ich frage mich warum du eine eigene Klasse TableModel gemacht hast? Welche zusätzliche Funktionalität bietet diese die z.B. DefaultTableModel nicht hat ? Oder liegt das daran dass man nicht den ganzen Code sieht ?
 
Ich habe den Code jetzt nur überflogen aber ich frage mich warum du eine eigene Klasse TableModel gemacht hast? Welche zusätzliche Funktionalität bietet diese die z.B. DefaultTableModel nicht hat ? Oder liegt das daran dass man nicht den ganzen Code sieht ?
da is keine zusätzlich funktionalität nein. Das liegt wohl daran dass ich dies "überlesen" habe.. werds auch mal mit DefaultTableModel testen, danke!
 
Musst du ja nicht. Wenn es so funktioniert ist es ja gut und gehört zur Übung. Ich wollte nur verstehen warum du es so gemacht hast. Alles gut.
 
Musst du ja nicht. Wenn es so funktioniert ist es ja gut und gehört zur Übung. Ich wollte nur verstehen warum du es so gemacht hast. Alles gut.
🙂 werde es so oder so noch anschauen, lerne halt auch gern dazu... aber heute musste / durfte ich mich ein paaar stunden mit JavaFX beschäftigen.. und ich denke in Zukunft werde ich nur noch in die Richtung entwickeln 🙂
 

Zurück
Oben