2012-10-13 46 views
1

我有一个扩展JScrollPane的类,即创建另一个可扩展JTable的类的对象。基本上,它看起来是这样的:覆盖JTable的构造函数之前调用的方法

class CustomScrollPane{ 
    private CustomTable table 

    public CustomScrollPane(..){ 
    table = new CustomTable(this); 
    .. 
    } 
    public void scrollToBottom(){ 
     ... 
    } 
} 

在CustomTable I类重写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()得到一个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

你确定你没有另一个构造无论是在CustomScrollPane或CustomTable,实际上是越来越叫什么名字?再次运行调试器,查看CustomTable中的哪个构造函数是从CustomScrollPane中的哪个构造函数调用的。 –

+0

是的,我想你是对的。它似乎从JPanel中调用了一些其他的构造函数,我觉得这个构造函数不管它是什么,都不可能有与我的(我自己的类的对象)相同的参数。 –

回答

1

它看起来像JTable构造函数调用方法tableChanged(...) - 这意味着它是在您能够初始化实例变量scrollPane之前调用的。

首先,我建议你看看Java Puzzlers这本书中的一些益智游戏 - 特别是拼图51:什么是关键,也许是拼图53:做你的事情。他们应该帮助你理解发生了什么。基本上,CustomTable构造函数的第一行调用JTable构造函数(通过super())。 JTable构造函数试图调用tableChanged - 已被覆盖。覆盖tableChanged试图操纵scrollPane ...但所有这些发生在您的构造函数(super()) - 的第1行之前this.scrollPane = scrollPane已执行,因此scrollPane仍然为空。我建议你使用observer pattern。这里有两个对象 - 滚动窗格和自定义表格 - 另一个需要在另一个对象发生变化时通知。这是教科书观察者模式。下面是粗略的想法:

文件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

class CustomScrollPane implements ChangeListener{ 
    private CustomTable table 

    public CustomScrollPane(/*...*/){ 
     table = new CustomTable(); 
     table.addChangeListener(this); 
     //... 
    } 

    public void scrollToBottom(){ 
     //... 
    } 

    /* new methods */ 

    @Override 
    public void onChange() { 
     scrollToBottom(); 
    } 
} 
+0

感谢您的构造信息,链接和模式建议! –

0

这是部分初始化的实例转义构造函数的范围的经典非常糟糕的模式。我想,当您调用新的CustomTable(this)时,CustomScrollPane会将一些事件触发到CustomTable表中。

由于scrollPane还没有初始化 - 那么你会得到NPE。

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

+1

我不确定我明白你的建议。你认为我应该删除 table = new CustomTable(this); 从构造函数,而是添加一个setTable()方法? –

+0

请看这里的下一个答案,它非常详细地描述我的观点 – jdevelop