Avatar billede OBS Juniormester
10. april 2025 - 16:21 Der er 10 kommentarer

AbstractTabelModel

Nu har jeg lavet en lille tabel, hvor samtlige celler er redigerbare - hvordan tilføjes nye kolonner og nye rækker, således at deres celler også skal være redigerbare ?

    import javax.swing.*;
    import javax.swing.table.DefaultTableModel;

    public class EditableTableExample {
        public static void main(String[] args) {
            // Opretter rammen
            JFrame frame = new JFrame("Editable Table Example");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            // Opretter data til tabellen
            String[] columnNames = {"Navn", "Alder", "By"};
            Object[][] data = {
                {"Hans", 30, "København"},
                {"Jens", 25, "Aarhus"},
                {"Kasper", 35, "Odense"}
            };

            // Opretter tabellen med DefaultTableModel
            DefaultTableModel model = new DefaultTableModel(data, columnNames) {
                @Override
                public boolean isCellEditable(int row, int column) {
                    return true; // Gør alle celler redigerbare
                }
            };

            JTable table = new JTable(model);

            // Tilføj tabellen til rammen
            frame.add(new JScrollPane(table));
            frame.setSize(400, 300);
            frame.setVisible(true);
        }
    }
Avatar billede arne_v Ekspert
10. april 2025 - 16:42 #1
Jeg har aldrig prøvet, men model.setDataVector efterfulgt af table.revalidate vil muligvis virke.
Avatar billede arne_v Ekspert
10. april 2025 - 17:13 #2
Ser ud til at virke:


import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class EditableTableExample {
    public static void main(String[] args) {
        // Opretter rammen
        JFrame frame = new JFrame("Editable Table Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());

        // Opretter data til tabellen
        String[] columnNames = {"Navn", "Alder", "By"};
        Object[][] data = {
            {"Hans", 30, "København"},
            {"Jens", 25, "Aarhus"},
            {"Kasper", 35, "Odense"}
        };

        // Opretter tabellen med DefaultTableModel
        DefaultTableModel model = new DefaultTableModel(data, columnNames) {
            @Override
            public boolean isCellEditable(int row, int column) {
                return true; // Gør alle celler redigerbare
            }
        };

        JTable table = new JTable(model);

        // Tilføj tabellen til rammen
        frame.add(new JScrollPane(table), BorderLayout.CENTER);
       
        // do stuff
        JButton addbtn = new JButton("Add");
        addbtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String[] columnNames2 = {"Navn", "Alder", "By", "Extra"};
                Object[][] data2 = {
                    {"Hans", 30, "København", "..."},
                    {"Jens", 25, "Aarhus", "..."},
                    {"Kasper", 35, "Odense", "..."}
                };
                model.setDataVector(data2, columnNames2);
                table.revalidate();
            }
        });
        frame.add(addbtn, BorderLayout.SOUTH);
       
        //
        frame.setSize(400, 300);
        frame.setVisible(true);
    }
}
Avatar billede arne_v Ekspert
10. april 2025 - 17:16 #3
Bemærk at Swing kald i main thread ikke er sikker.

Der er en grund til at man bruger:


    SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame f = new Whatever();
                f.setVisible(true);
            }
        });
Avatar billede OBS Juniormester
10. april 2025 - 18:44 #4
Ja, det fungerer, mange tak.

Kan en ny række tilføjes på lignende måde ?
Avatar billede arne_v Ekspert
10. april 2025 - 18:53 #5
Ja.

Og strengt taget er det vel meget mere naturligt at øge antal rækker end øge antal kolonner.
Avatar billede arne_v Ekspert
10. april 2025 - 21:58 #6
Men hvis du vil tilføje rækker er Vector versionen nok bedre end array versionen!


import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Vector;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class EditableTableExample2 {
    public static void main(String[] args) {
        // Opretter rammen
        JFrame frame = new JFrame("Editable Table Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());

        // Opretter data til tabellen
        Vector<String> columnNames = new Vector<String>(Arrays.asList("Navn", "Alder", "By"));
        Vector<Vector<Object>> data = new Vector<Vector<Object>>(Arrays.asList(
            new Vector<Object>(Arrays.asList("Hans", 30, "København")),
            new Vector<Object>(Arrays.asList("Jens", 25, "Aarhus")),
            new Vector<Object>(Arrays.asList("Kasper", 35, "Odense"))
        ));

        // Opretter tabellen med DefaultTableModel
        DefaultTableModel model = new DefaultTableModel(data, columnNames) {
            @Override
            public boolean isCellEditable(int row, int column) {
                return true; // Gør alle celler redigerbare
            }
        };

        JTable table = new JTable(model);

        // Tilføj tabellen til rammen
        frame.add(new JScrollPane(table), BorderLayout.CENTER);
       
        // do stuff
        JButton addbtn = new JButton("Add");
        addbtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                model.getDataVector().add(new Vector<Object>(Arrays.asList("XXXX", 100, "Ålborg")));
                table.revalidate();
            }
        });
        frame.add(addbtn, BorderLayout.SOUTH);
       
        //
        frame.setSize(400, 300);
        frame.setVisible(true);
    }
}
Avatar billede OBS Juniormester
Skrevet i går kl. 10:39 #7
Mange tak
Avatar billede arne_v Ekspert
Skrevet i går kl. 14:14 #8
Ovenstående kode er lidt klodset, men meget af det skyldes at:
- ArrayList erstattede Vector i Java 1.2 (1998)
- Swing blev en del af Java i Java 1.2 (1998) men var tilgængeligt for tidligere versioner allerede i 1997

Så DefaultTableModel bruger Vector som er en forældet klasse og mangler en masse sammenlignet med nyere collections framework typer.

Så det er enten lev med Vector i DefaultTableModel eller skift til AbstractTableModel som kan bruge hvad som helst inkl. ArrayList.
Avatar billede OBS Juniormester
Skrevet i går kl. 14:39 #9
Jeg har fundet en løsning:

import javax.swing.*;
    import javax.swing.table.DefaultTableModel;
    import java.awt.*;

    public class TableExample {
        public static void main(String[] args) {
            // Oprette en JFrame
            JFrame frame = new JFrame("Tabel Eksempel");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(600, 400);

            // Oprette en DefaultTableModel
            DefaultTableModel model = new DefaultTableModel();
           
            // Tilføje kolonner til model
            model.addColumn("Navn");
            model.addColumn("Alder");
            model.addColumn("By");
            model.addColumn("Land");
            model.addColumn("Europa");

            // Oprette en JTable med den model
            JTable table = new JTable(model);
           
            // Tilføje nogle rækker til tabellen
            model.addRow(new Object[]{"Caroline", 30, "København"});
            model.addRow(new Object[]{"Jens", 25, "Aarhus"});
            model.addRow(new Object[]{"CKasper", 35, "Odense"});

            // Oprette en JScrollPane og tilføje tabellen til den
            JScrollPane scrollPane = new JScrollPane(table);
            frame.add(scrollPane, BorderLayout.CENTER);

            // Oprette en knap til at tilføje en række
            JButton addButton = new JButton("Tilføj række");
            addButton.addActionListener(e -> {
                //
                model.addRow(new Object[]{"Ny person", 0, "By"});
            });
           
            frame.add(addButton, BorderLayout.SOUTH);

            // Gøre vinduet synligt
            frame.setVisible(true);
        }
    }
Avatar billede arne_v Ekspert
Skrevet i går kl. 17:16 #10
Det undgår Vector, men der er stadig Object[].

Jeg prøvede at lave en lidt mere moderne table model:


import java.awt.BorderLayout;
import java.awt.Color;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.table.AbstractTableModel;

public class ModernTableUsage extends JFrame {
    public static class BeanTableModel<T> extends AbstractTableModel {
        private static final long serialVersionUID = 1L;
        private List<T> data;
        private List<Method> getter = new ArrayList<Method>();
        private List<Method> setter = new ArrayList<Method>();
        public BeanTableModel(Class<T> clz, List<T> data, String... flds) {
            this.data = data;
            for(String fld : flds) {
                try {
                    getter.add(clz.getDeclaredMethod("get" + fld));
                    setter.add(clz.getDeclaredMethod("set" + fld, String.class));
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (SecurityException e) {
                    e.printStackTrace();
                }
            }
        }
        @Override
        public int getRowCount() {
            return data.size();
        }
        @Override
        public int getColumnCount() {
            return getter.size();
        }
        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            try {
                return getter.get(columnIndex).invoke(data.get(rowIndex));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                return null;
            } catch (InvocationTargetException e) {
                e.printStackTrace();
                return null;
            }
        }
        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            try {
                setter.get(columnIndex).invoke(data.get(rowIndex), aValue);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return true;
        }
    }
    public static class Data {
        private int f1;
        private String f2;
        public Data() {
            this(0, "");
        }
        public Data(int f1, String f2) {
            super();
            this.f1 = f1;
            this.f2 = f2;
        }
        public int getF1() {
            return f1;
        }
        public void setF1(int f1) {
            this.f1 = f1;
        }
        public void setF1(String f1) { // <---- needed for default cell editor !!!!
            this.f1 = Integer.parseInt(f1);
        }
        public String getF2() {
            return f2;
        }
        public void setF2(String f2) {
            this.f2 = f2;
        }
        @Override
        public String toString() {
            return String.format("(%s,%s)",  f1, f2);
        }
    }
    private static final long serialVersionUID = 1L;
    public ModernTableUsage() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Moden table usage");
        setLayout(new BorderLayout());
        List<Data> data = new ArrayList<Data>(List.of(new Data(1, "A"), new Data(2, "BB"), new Data(3, "CCC")));
        BeanTableModel<Data> model = new BeanTableModel<Data>(Data.class, data, "F1", "F2");
        JTable table = new JTable(model);
        table.setShowGrid(true);
        table.setGridColor(Color.BLACK);
        table.setBorder(new LineBorder(Color.BLACK, 2));
        JPanel wrapper = new JPanel();
        wrapper.setBorder(new EmptyBorder(10, 10, 10, 10));
        wrapper.add(table);
        add(wrapper, BorderLayout.CENTER);
        JPanel buttons = new JPanel();
        buttons.setBorder(new EmptyBorder(10, 10, 10, 10));
        JButton test = new JButton("Test");
        test.addActionListener(e -> JOptionPane.showMessageDialog(null, data.stream().map(Data::toString).collect(Collectors.joining("\r\n"))));
        buttons.add(test);
        JButton add = new JButton("Add row");
        add.addActionListener(e -> { data.add(new Data()); model.fireTableDataChanged(); });
        buttons.add(add);
        add(buttons, BorderLayout.SOUTH);
        pack();
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame f = new ModernTableUsage();
                f.setVisible(true);
            }
        });
    }
}
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester