Multiple object in a single JTable cell

3.6k views Asked by At

Is it possible to have multiple objects inside one JTable cell looking like this where I have two JLabels in each cell on the first row?

enter image description here

The problem I am having in this example is that I can't add any listeners to any JLabels(Icons). My guess is that I need to change something else then the CellRenderer?

public class JTableIcons extends JPanel {

    private DefaultTableModel model;
    private JTable table;

    public JTableIcons() {
        initModel();
        initTable();
        this.setLayout(new BorderLayout());
        this.add(table, BorderLayout.CENTER);
    }

    class MyRenderer implements TableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {

            JPanel panel = new JPanel();
            if (row == 0) {
                JLabel lblCol = new JLabel("Column:" + column);
                Icon icon = UIManager.getIcon("OptionPane.errorIcon");
                JLabel lblIcon = new JLabel();
                lblIcon.setIcon(icon);
                panel.add(lblIcon);
                panel.add(lblCol);
            } else {
                JLabel lbl = new JLabel("(" + row + "," + column + ")");
                panel.add(lbl);
            }
            panel.setOpaque(false);
            return panel;
        }
    }

    private void initTable() {
        table = new JTable(model);
        table.setDefaultRenderer(Object.class, new MyRenderer());
        table.setShowGrid(true);
        table.setGridColor(Color.gray);
        table.setRowHeight(80);
    }

    private void initModel() {
        String[] cols = { "", "", "" };
        Object[][] rows = { { "", "", "" }, { "", "", "" }, { "", "", "" }, { "", "", "" } };
        model = new DefaultTableModel(rows, cols);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.add(new JTableIcons());
                f.setVisible(true);
                f.setSize(new Dimension(500, 350));
                f.setLocationRelativeTo(null);
            }
        });
    }
}
2

There are 2 answers

2
trashgod On

I would like to add two or more objects,

Don't use two components, when one will do. The renderer in this example implements the Icon interface to leverage the flexible relative positioning of the text and icon. When necessary, add multiple components to a suitable lightweight Container, e.g. JPanel.

and then also have different listeners to the added objects.

For interactivity, use a custom TableCellEditor. This example manages radio buttons in a panel.

0
Grains On

Thanks MadProgrammer for the example. Managed to come up with this:

enter image description here

Where both icons have listeners connected to it.

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

public class IconsInTableCell extends JPanel {

    private static final String[] COLUMN_NAMES = { "Icons" };
    private MyTableModel tableModel;
    private JTable table;
    private JFrame frame = new JFrame();

    public IconsInTableCell() {
        super(new BorderLayout(0, 5));
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        tableModel = new MyTableModel();
        table = new JTable(tableModel);
        table.setDefaultEditor(Icon.class, new IconEditor());
        table.setDefaultRenderer(Icon.class, new IconRenderer());
        table.setRowHeight(60);
        add(new JScrollPane(table), BorderLayout.CENTER);
        tableModel.add(new TableEntry());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new JScrollPane(table), BorderLayout.CENTER);
        frame.pack();
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                frame.setVisible(true);
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new IconsInTableCell();
            }
        });
    }

    private enum Icon {
        Delete, Sort;
    }

    private class IconPanel extends JPanel implements MouseListener {

        private JLabel icon1;
        private JLabel icon2;

        IconPanel() {
            super(new GridLayout(0, 1));
            setOpaque(true);

            try {
                icon1 = new JLabel(new ImageIcon(ImageIO.read(new File("Photo01.jpg"))));
                icon2 = new JLabel(new ImageIcon(ImageIO.read(new File("tst.jpg"))));

                icon1 = new JLabel(UIManager.getIcon("OptionPane.errorIcon"));
                icon2 = new JLabel(UIManager.getIcon("OptionPane.warningIcon"));
            } catch (IOException e) {
                e.printStackTrace();
            }

            icon1.addMouseListener(this);
            icon2.addMouseListener(this);

            this.setLayout(new GridBagLayout());
            GridBagConstraints c = new GridBagConstraints();
            add(icon1, c);
            add(new JLabel("TEXT"), c);
            add(icon2, c);
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            if (e.getSource() == icon1)
                System.out.println("icon1");
            else if (e.getSource() == icon2)
                System.out.println("icon2");
        }

        @Override
        public void mousePressed(MouseEvent e) {
        }

        @Override
        public void mouseReleased(MouseEvent e) {
        }

        @Override
        public void mouseEntered(MouseEvent e) {
        }

        @Override
        public void mouseExited(MouseEvent e) {
        }
    }

    private class TableEntry {

        private Icon theIcons;

        TableEntry() {
        }

        TableEntry(Icon aIcons) {
            theIcons = aIcons;
        }

        public Icon getIcons() {
            return theIcons;
        }

        public void setIcons(Icon aIcon) {
            theIcons = aIcon;
        }
    }

    private class MyTableModel extends AbstractTableModel {

        private Vector<Object> theEntries;

        MyTableModel() {
            theEntries = new Vector<Object>();
        }

        @SuppressWarnings("unchecked")
        public void add(TableEntry anEntry) {
            int index = theEntries.size();
            theEntries.add(anEntry);
            fireTableRowsInserted(index, index);
        }

        public void remove(int aRowIndex) {
            if (aRowIndex < 0 || aRowIndex >= theEntries.size()) {
                return;
            }
            theEntries.removeElementAt(aRowIndex);
            fireTableRowsDeleted(aRowIndex, aRowIndex);
        }

        public int getRowCount() {
            return theEntries.size();
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return Icon.class;
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            TableEntry entry = (TableEntry) theEntries.elementAt(rowIndex);
            entry.setIcons((Icon) aValue);
            fireTableCellUpdated(rowIndex, columnIndex);
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return true;
        }

        @Override
        public int getColumnCount() {
            return 1;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            TableEntry entry = (TableEntry) theEntries.elementAt(rowIndex);
            switch (columnIndex) {
            case 0:
                return entry.getIcons();
            }
            return null;
        }
    }

    private class IconEditor extends AbstractCellEditor implements TableCellEditor {

        private IconPanel theIconPanel;

        IconEditor() {
            theIconPanel = new IconPanel();
        }

        @Override
        public Object getCellEditorValue() {
            return null;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            if (isSelected) {
                theIconPanel.setBackground(table.getSelectionBackground());
            } else {
                theIconPanel.setBackground(table.getBackground());
            }
            return theIconPanel;
        }
    }

    private class IconRenderer extends IconPanel implements TableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            if (isSelected) {
                setBackground(table.getSelectionBackground());
            } else {
                setBackground(table.getBackground());
            }
            return this;
        }
    }
}