我有一个扩展JScrollPane的类,它正在创建另一个扩展JTable的类的对象。基本上它看起来像这样:
class CustomScrollPane{
private CustomTable table
public CustomScrollPane(..){
table = new CustomTable(this);
..
}
public void scrollToBottom(){
...
}
}
在CustomTable类中,我重写了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();
}
当我运行这个时,我在tableChanged()中的scrollPane上得到一个NullPointerException,这怎么可能?当scrollPane在构造函数中设置时,它如何为null?在调试器中运行它表明在构造函数之前调用tableChanged()。添加条件
if (scrollPane != null)
实际上解决了这个问题,因为稍后会调用构造函数。此外,将JTable定义为其构造,如:
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();
}
};
直接在CustomScrollPane构造函数中也可以工作。为什么不把它分成一个单独的类?
答案 0 :(得分:1)
看起来JTable
构造函数调用方法tableChanged(...)
- 这意味着在您能够初始化scrollPane
实例变量之前调用它。
首先,我建议你看看书中Java Puzzlers中的一些益智游戏 - 具体的谜题51:什么是重点,也许是谜题53:做你的事。他们应该帮助您了解正在发生的事情。基本上,CustomTable
构造函数的第一行调用JTable
构造函数(通过super()
)。 JTable
构造函数正在尝试调用tableChanged
- 已被覆盖。覆盖tableChanged
尝试操纵scrollPane
...但所有这一切都发生在构造函数的第1行(super()
) - 之前行{{1已执行,因此this.scrollPane = scrollPane
仍然为空。
接下来,我建议使用observer pattern。这里有两个对象 - 滚动窗格和自定义表 - 另一个需要在另一个更改时得到通知。那是教科书观察者模式。这是一个粗略的想法:
scrollPane
CustomTable.java
public class CustomTable extends JTable {
// No more scroll pane; only observers
private List<ChangeListener> listeners = [];
// no more scroll pagne
public CustomTable(){
super();
}
@Override
public void tableChanged(TableModelEvent e) {
super.tableChanged(e);
this.fireChangeEvent();
}
/* new methods */
public void addChangeListener(ChangeListener listener) {
listeners.add(listener);
}
public void removeChangeListener(ChangeListener listener) {
// ...
}
private void fireChangeEvent() {
for(String l : listeners ){
l.onChange();
}
}
}
CustomScrollPane.java
答案 1 :(得分:0)
这是一种经典的非常糟糕的模式,即部分初始化的实例会逃避构造函数的范围。
我想当你调用new CustomTable(this)时,CustomScrollPane会向表CustomTable触发一些事件;
并且由于scrollPane尚未初始化 - 那么您将获得NPE。
永远不要让事情逃脱构造函数 - 而且你是安全的。