0

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.

jww
  • 97,681
  • 90
  • 411
  • 885
Jeremy
  • 105
  • 1
  • 4
  • 11
  • Read about [TableCellRenderer](http://docs.oracle.com/javase/6/docs/api/javax/swing/table/TableCellRenderer.html). `getTableCellRendererComponent` can return any Component, even a Container. – PeterMmm Jun 15 '14 at 09:26
  • Agree with @PeterMmm you will need to have a look at how to customise your rendering for each cell. – isaias-b Jun 15 '14 at 09:29
  • [Here](http://stackoverflow.com/questions/7036036/adding-multiple-jprogressbar-to-tablecolumn-of-jtable) is a post which adds `ProgressBar`s to table cells – isaias-b Jun 15 '14 at 09:32
  • @PeterMmm Include JPanel? – Jeremy Jun 15 '14 at 09:33
  • JPanel extends JComponent, JComponent extends Container, Container extends Component, yes. – PeterMmm Jun 15 '14 at 09:35
  • @PeterMmm I tried some code from Google. The result is like `Lnsdf@19839` – Jeremy Jun 15 '14 at 09:37
  • Show us the code you have tried. – PeterMmm Jun 15 '14 at 09:38
  • Sorry I deleted it. It was about a month ago. I was making another similar application – Jeremy Jun 15 '14 at 09:39
  • @Jeremy You are rigth the `JPanel` will be the solution. [Here is a stackoverflow post adding a JPanel to a JTable cell](http://stackoverflow.com/questions/3795695/jpanel-in-a-cell-of-a-jtable) – isaias-b Jun 15 '14 at 09:40
  • @isi I read about that before. But it is `JLabel` not `JPanel` :( – Jeremy Jun 15 '14 at 09:45
  • @Jeremy I have transfered the code using the `JLabel` into now using a `JPanel` – isaias-b Jun 15 '14 at 11:01

2 Answers2

1

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

isaias-b
  • 2,255
  • 2
  • 25
  • 38
  • Wow thanks. I just need to replace `MyPanel` with my own right? The friends name is stored in client's computer. Is it possible to set the text of `JLabel` after client got the data from server? – Jeremy Jun 15 '14 at 12:03
  • @Jeremy #1 Yes in theory you just need to replace the panel type `MyPanel` to your panel type. But as i said the solution still has some flaws. #2 You can modify the panel class to take appropriate setters for setting the values afterwards. – isaias-b Jun 15 '14 at 12:33
  • @Jeremy after all i ask myself, do you really need a table?? isnt it the fact that you just have a list of items with individual panels associated? Or do you need the columns of the table for some reason? If not think about using a JList instead ;) – isaias-b Jun 15 '14 at 12:38
  • I want the result look exactly like http://i.stack.imgur.com/mm1VN.png . I think the only solution is, `JTable`. :3 – Jeremy Jun 15 '14 at 12:55
  • @Jeremy But you are not using any Columns in that picture. E.g. in my implementation there are two columns one for the "Id" of the row and another one for the panel called "MyPanel". So if you dont need the columns then it is also managable by a list or am i wrong with that?? – isaias-b Jun 15 '14 at 12:58
  • Yes you are right. I only need one coloumn. Is it possible with `JList`? – Jeremy Jun 15 '14 at 13:11
0

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.

Community
  • 1
  • 1
isaias-b
  • 2,255
  • 2
  • 25
  • 38
  • @Jeremy Yes, the scrollpane will justify the scrollbars. But if you want the inner panels to fill the whole space in terms of width some extra effort will be necessary. I added a picture of the actual behaviour when resizing the whole window to be smaller than the inner panels – isaias-b Jun 15 '14 at 14:09
  • Thanks :D (character limit) – Jeremy Jun 15 '14 at 14:20