Jeremy
Jeremy

Reputation: 103

How to create a custom JTable?

I am making a chat application in Java. They can add friends and chat with them.

Here is my add friend JFrame idea:

enter image description here

I tried to google search Multi jpanel in one jscrollpane but I found nothing. I ended up with custom JTable. I want to create a custom JTable which have JLabels in different position in each slot. Users can just select a slot in JTable, then they can use the JButton below to chat with them.

Is it possible to do this in Java. Is yes, please share your idea. Thanks.

Upvotes: 0

Views: 2964

Answers (2)

isaias-b
isaias-b

Reputation: 2289

This is a completely different approach using neither a table nor a list. It uses panels as items arranged as a list inside of another panel. This solution doesn't requires any further modification to delegate any events to the underlying controls. The events are processed natively. The idea comes from this post. I have separated the logic into two parts for now.

List of <code>JPanels</code> arranged inside on a `JPanel smaller resized version

JPanelList class

This class is a JPanel and maintains a list of such. ATM they can be added using the methods addPanel and addPanels.

public class JPanelList extends JPanel {
    private static final long serialVersionUID = 1L;
    private JPanel mainList;
    private List<JPanel> panels = new ArrayList<JPanel>();
    public JPanelList() { this(new ArrayList<JPanel>()); }
    public JPanelList(List<JPanel> panels) {
        setLayout(new BorderLayout());
        mainList = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbc.weightx = 1;
        gbc.weighty = 1;
        mainList.add(new JPanel(), gbc);
        add(new JScrollPane(mainList));
        addPanels(panels);
    }
    public void addPanels(List<JPanel> panels) {
        for (JPanel panel : panels)
            addPanel(panel);
    }
    public void addPanel(JPanel panel) {
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbc.weightx = 1;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        mainList.add(panel, gbc, 0);
        panels.add(panel);
        validate();
        repaint();
    }
}

JListFrame test class with main function

public class JPanelListFrame {
    private JFrame frame;
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    JPanelListFrame window = new JPanelListFrame();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    public JPanelListFrame() {
        frame = new JFrame();
        frame.setBounds(100, 100, 210, 192);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final JPanelList panelList = new JPanelList();
        frame.getContentPane().add(panelList, BorderLayout.CENTER);
        JButton btnAddMypanel = new JButton("Add MyPanel");
        btnAddMypanel.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                // just add a MyPanel with a Value containing a
                // "asdf" and a random boolean
                panelList.addPanel(new MyPanel(new Value("asdf",
                        (int) (2 * Math.random()) % 2 == 0)));
            }
        });
        panelList.add(btnAddMypanel, BorderLayout.SOUTH);
    }
}

One drawback with this solution is that the selection mechanics are lost. When selecting elements is a key requirement maybe a JList might be more appropriate. Another thing is that the items are not rendered as they would be rendered inside a JList or JTable e.g. using fancy borders. This can be solved by somehow adding a border decorator before adding the panels into the mainList of the JPanelList.

Upvotes: 0

isaias-b
isaias-b

Reputation: 2289

Here is a proposal. But it contains some flaws yet

  • Size propagation is fiexed (may be better client or server based sizing)
  • No event delegation to underlying Component
  • Performance, because heavyweight panel instances are created frequently inside paint loop

But here is how it can be done. The code is separated into parts.

A value class

Just a simple class to represent the date inside your panels for each cell.

class Value {
    public final String text;
    public final boolean flag;
    public Value(String text, boolean flag) {
        this.text = text;
        this.flag = flag;
    }
}

My individual panel class

The representation can be modelled within a gui editor like google's window builder. This panel makes use of the value and displays it accordingly.

public class MyPanel extends JPanel {
    public MyPanel(Value v) {
        JLabel lblNewLabel = new JLabel(v.text);
        add(lblNewLabel);
        JCheckBox chckbxSomeValue = new JCheckBox("some value");
        chckbxSomeValue.setSelected(v.flag);
        add(chckbxSomeValue);
    }
}

A table cell renderer class

Just returns some panel instance showing up the desired values.

import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

class MyPanelCellRenderer implements TableCellRenderer {
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        return new MyPanel((Value)value); // maybe performance problem
    }   
}

A custom table model

import javax.swing.table.DefaultTableModel;

class MyTableModel extends DefaultTableModel {
    public MyTableModel() {
        super(new Object[][] {
                        new Object[] { 1, new Value("asdf", true) },
                        new Object[] { 2, new Value("qwer", false) } },
                        new String[] {"Id", "MyPanel" });
    }

    Class[] columnTypes = new Class[] { Integer.class, Value.class };

    MyTableModel(Object[][] data, Object[] columnNames) {
        super(data, columnNames);
    }

    public Class getColumnClass(int columnIndex) {
        return columnTypes[columnIndex];
    }
}

A frame class

import java.awt.BorderLayout;

public class MyFrame {
    JFrame frame;
    private JTable table;

    public MyFrame() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        table = new JTable();
        table.setModel(new MyTableModel());
        table.setFillsViewportHeight(true);
        table.getColumnModel()
            .getColumn(1)
            .setCellRenderer(new MyPanelCellRenderer());
        table.setRowHeight(40); // static sizing

        JScrollPane scrollPane = new JScrollPane();
        frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
        scrollPane.setViewportView(table);
    }
}

Main Function

import java.awt.EventQueue;

public class MyApp {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    MyFrame window = new MyFrame();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

The final result

The result

The panel MyPanel is created using eclipse and google's window builder

<code>MyPanel</code> creation

Upvotes: 1

Related Questions