Reputation: 103
I am making a chat application in Java. They can add friends and chat with them.
Here is my add friend JFrame
idea:
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 JLabel
s 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
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.
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();
}
}
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
Reputation: 2289
Here is a proposal. But it contains some flaws yet
Component
But here is how it can be done. The code is separated into parts.
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;
}
}
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);
}
}
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
}
}
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];
}
}
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);
}
}
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 panel MyPanel
is created using eclipse and google's window builder
Upvotes: 1