2012-10-13 52 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