Reputation: 33
First off, this is for a school project so I can't upload my full code. We've been given a blank project and asked to add functionality to it.
I want to be able to display data from a sever in various tables, each one in a separate tab, with each 'page' having the option to add, edit or delete records to the table.
As I have quite a few different tables, I wrote a parent class, Page, that will contain a table and some JPanels that I can add buttons to if needed.
However whenever I try adding a JTable to Page, it causes unpredictable behaviour between the tabs - note this happens regardless of whether or not I use a TableModel.
I tried using labels to display where the components should be, which works fine, but using actual tables causes the placeholder labels and the tabs at the top to be hidden.
Tab with labels to illustrate where the components SHOULD be
I haven't done anything with threading, so am at a loss as to what's happening to the application when I try to add my JTable.
This is the code for Page.java:
import java.awt.*;
import javax.swing.*;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
public class Page extends JPanel {
private static final long serialVersionUID = -4661566573959270000L;
protected JTable table;
protected JPanel addPanel;
protected JPanel fieldPanel;
protected JPanel buttonPanel;
protected TableModel model;
public Page(String[] names) {
this.setLayout(new GridLayout(2,1));
final class MyTableModel implements TableModel{
private static final long serialVersionUID = -4661566573959270000L;
private String[] columnNames;
private Object[][] data;
public MyTableModel(String[] names) {
columnNames=names;
data=new Object[names.length][0];
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if(isCellEditable(rowIndex, columnIndex)) {
data[rowIndex][columnIndex] = aValue;
}
}
@Override
public void removeTableModelListener(TableModelListener l) {
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return data[rowIndex][columnIndex];
}
@Override
public int getRowCount() {
return data.length;
}
@Override
public String getColumnName(int columnIndex) {
return columnNames[columnIndex];
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
try {
return getValueAt(0, columnIndex).getClass();
}
catch (Exception e) {
return null;
}
}
@Override
public void addTableModelListener(TableModelListener l) {
}
};
/**
* creating and adding a table
* this is the problematic bit
*/
table = new JTable(new MyTableModel(names));
this.add(table);
//this.add(new Label("Table"));
//panels for layout
addPanel = new JPanel();
fieldPanel = new JPanel();
buttonPanel = new JPanel();
//assigning positions
this.add(addPanel);
addPanel.setLayout(new BorderLayout());
addPanel.add(fieldPanel, BorderLayout.CENTER);
addPanel.add(buttonPanel, BorderLayout.SOUTH);
//placeholder labels
fieldPanel.add(new JLabel("Insert fields here"));
buttonPanel.add(new Button("Buttons"));
}
}
I add new pages to my tab system with the following code:
JTabbedPane tabs = new JTabbedPane();
tabs.add("A", new Page(new String[]{"A"}));
tabs.add("B", new Page(new String[]{"B"}));
tabs.add("C", new Page(new String[]{"C"}));
tabs.add("D", new Page(new String[]{"D"}));
With the String[] being the names of the columns that I want to display - note these will be replaced with actual helpful names once I've got the tables working properly.
Any ideas what I'm doing wrong? I've tried repainting my frame with a ChangeListener event, but that doesn't seem to do anything.
Thank you!
EDIT Included is a complete version of the code. Use the above code for Page, and use this in a Main class:
import java.awt.*;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
JFrame window = new JFrame("Components and Containers");
window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE) ;
window.setSize(800,600);
Container pane = window.getContentPane();
JTabbedPane tabs = new JTabbedPane();
tabs.add("A", new Page(new String[]{"A"}));
tabs.add("B", new Page(new String[]{"B"}));
tabs.add("C", new Page(new String[]{"C"}));
tabs.add("D", new Page(new String[]{"D"}));
pane.add(tabs);
window.setVisible(true);
}
}
I tried adding the table to a ScrollPanel instead, and the table only becomes visible when you hover over it. The tabs are still not showing correctly.
The result of adding the table to a separate ScrollPanel instead of directly to the component.
Upvotes: 0
Views: 41
Reputation: 21510
Your table model class is inconsistent with respect to the row/column ordering.
In the constructor, you write
data=new Object[names.length][0];
which implies that the first index is the column number and the second index is the row number.
However, when accessing the data (in getValueAt
, setValueAt
), you use the indizes in the other way round:
data[rowIndex][columnIndex]
And also, this:
public int getRowCount() {
return data.length;
}
returns the column count as row count, which means you get an ArrayIndexOutOfBoundsException
as soon as the JTable tries to call getValueAt(0, 0)
.
To fix the problem, you should initialize the data array in the constructor with:
data=new Object[0][names.length];
Upvotes: 2