I have one class extending JScrollPane, that’s creating an object of another class that extends JTable. Basically it looks like this:
class CustomScrollPane{
private CustomTable table
public CustomScrollPane(..){
table = new CustomTable(this);
..
}
public void scrollToBottom(){
...
}
}
In the CustomTable class I override tableChanged:
public class CustomTable extends JTable{
private CustomScrollPane scrollPane;
public CustomTable(CustomScrollPane scrollPane){
super();
this.scrollPane = scrollPane;
}
@Override
public void tableChanged(TableModelEvent e) {
super.tableChanged(e);
scrollPane.scrollToBottom();
}
When I run this I get a NullPointerException on scrollPane in tableChanged(), how is that possible? How can scrollPane be null when it was set in the constructor? Running it in the debugger shows that tableChanged() is called before the constructor. Adding the condition
if (scrollPane != null)
actually fixes the problem, because later on the constructor is called. Also, defining the JTable as its constructed, like:
table = new JTable(){
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
final Component c = super.prepareRenderer(new CustomTableCellRenderer(), row, column);
if (c instanceof JComponent){
((JComponent) c).setOpaque(true);
}
return c;
}
@Override
public void paint(Graphics g) {
int scrolling = scrollPane.getViewport().getViewPosition().y;
super.paint(g);
g.drawImage(image.getImage(), -30, -50 + scrolling, null, null);
}
@Override
public void tableChanged(TableModelEvent e) {
super.tableChanged(e);
scrollPane.scrollToBottom();
}
};
directly in the CustomScrollPane constructor also works. Why can’t a break it out into a seperate class?
It looks like the
JTableconstructor invokes methodtableChanged(...)– which means it is invoked before you’re able to initialize thescrollPaneinstance variable.First, I suggest you take a look at some puzzlers in the book Java Puzzlers – specifically puzzle 51: What’s the Point and maybe puzzle 53: Do Your Thing. They should help you understand what’s going on. Basically, the first line of your
CustomTableconstructor invokes theJTableconstructor (viasuper()). TheJTableconstructor is trying to invoketableChanged– which has been overriden. The overridentableChangedtries to manipulatescrollPane… but all this is happening on line 1 of your constructor (super()) – before the linethis.scrollPane = scrollPanehas executed, soscrollPaneis still null.Next, I suggest using the observer pattern. Here you have two objects – your scroll pane and the custom table – and one needs to be notified when the other is changed. That is textbook observer pattern. Here’s the rough idea:
File
CustomTable.javaFile
CustomScrollPane.java