在重写的JTable中在构造函数之前调用的方法

时间:2012-10-13 17:21:30

标签: java

我有一个扩展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构造函数中也可以工作。为什么不把它分成一个单独的类?

2 个答案:

答案 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。

永远不要让事情逃脱构造函数 - 而且你是安全的。