2011-01-19 49 views
1

我正在創建我的第一個JTable,它需要我創建自定義AbstractTableModel,TableCellEditorDefaultTableCellRenderer。鑑於我之前不需要創建這些工具,我已經取得了一些重大進展,使我的表能夠按照預期行事。更新JTable單元格的ImageIcon

但是,我不知所措地使用了所有不同的方法,而且我正在旋轉我的輪子,試圖弄清楚如何修改特定單元格的ImageIcon。 單元格必須包含JLabel,因爲它需要ImageIcon以及文本字符串。我已經可以設置初始ImageIcon(雖然我可能做得不正確),但我無法設置更新的ImageIcon。沒有任何失敗,但沒有改變。

從一般意義上說,假設所有這些模型,編輯器和渲染器都已經實例化,獲取和設置圖標到JTableJLabel單元格的最佳方法是什麼?

我的模型已被定義爲返回JLabel.class這些單元格,如果您想知道,並且我也會在做出更改後執行fireTableCellUpdated(row, col)。如果我在更新前後執行System.out.println(getIcon()),我甚至可以看到源已更改。

下面是一些代碼(與地方URL/ImageIcon的修復更新)的

class MonitorTable extends JTable { 
    MonitorTableModel model = new MonitorTableModel(rows, columnNames); 
    setModel(model); 
    ... 
    public void setIconAt(ImageIcon icon, int row, int col) { 
     model.setIconAt(icon, row, col); 
    } // End setIconAt(ImageIcon, int, int) 
    ... 

    class MonitorTableModel extends AbstractTableModel { 
     ... 
     public void setIconAt(ImageIcon icon, int row, int col) { 
     StatusTableCellRenderer cell = 
      (StatusTableCellRenderer)getColumnModel().getColumn(col).getCellRenderer(). 
      getTableCellRendererComponent(myTableObject, null, false, false, row, col); 

     System.out.println(cell.getIcon()); // Shows initial icon source 
     cell.setIcon(icon); 
     fireTableCellUpdated(row, col);  // Should update the table 
     System.out.println(cell.getIcon()); // Shows new icon source 
     System.out.println("Cell updated"); 
     } // End setIconAt(ImageIcon, int, int) 
    } // End class MonitorTableModel 

    public class StatusTableCellRenderer extends DefaultTableCellRenderer { 
     public Component getTableCellRendererComponent(JTable table, Object value, 
     boolean isSelected, boolean hasFocus, int row, int col) { 

     setIcon(imgGray); 
     setText((String)value); 
     return this; 
     } // End getTableCellRendererComponent(JTable, Object, boolean, boolean, int, int) 
    } // End class StatusTableCellRenderer 
} // End class MonitorTable 

回答

0

我改變setIcon(imgGray)固定這if (getIcon() == null) setIcon(imgGray);

問題是我的getTableCellRendererComponent方法是每次將圖標設置爲imgGray。很明顯,我的setIconAt方法(即調用getTableCellRendererComponent)被覆蓋,即使「新」圖標值是在「舊」值被重新設置後處理的。

我最終刪除了所有我的setIcon方法,並將相關邏輯轉移到我的StatusTableCellRenderer類中。這樣我傳遞單元格的值,並讓渲染器根據該值執行圖標設置。這樣做更有意義,而且工作得很漂亮。我已確認初始設置和所有後續更新均按預期執行。

設置圖標的邏輯非常簡單 - 根據某些預定義的閾值設置預定義的圖標。

double val; 
if (getIcon() == null) setIcon(imgGray);  // Initialize 
if ((value == null) || (value == "")) { 
    val = 0; 
} else { 
    val = Double.parseDouble(value.toString()); 
} // End if 

if (val <= THRESHOLD1) { 
    setIcon(icon1); 
} else if (val <= THRESHOLD2) { 
    setIcon(icon2); 
... 
} // End if 
setText(value.toString()); 

我很擔心建議,讓品牌新的對象來使用,當默認JLabel正是我所需要的東西。這對JTable來說既沒有必要也沒有潛在的性能影響。謝謝大家的意見和協助。這讓我bat!不安!

0

調用fireTableDataChanged從你的模型。

嘗試從JLabel調用repaint方法。

更好的方法是實現一個CellRenderer,並返回一個JPanel並在paintComponent中繪製draw方法。您可以加載BufferedImage而不是ImageIcon,並使用它來繪製JPanel。

嘗試改變你渲染器:

public class StatusTableCellRenderer extends DefaultTableCellRenderer { 
    public Component getTableCellRendererComponent(JTable table, Object value, 
     boolean isSelected, boolean hasFocus, int row, int col) { 
     JLabel comp = new JLabel(new ImageIcon(imgGray)); 
     comp.setText((String)value); 
     return comp; 
    } // End getTableCellRendererComponent(JTable, Object, boolean, boolean, int, int) 
    } 

你正在做一些亂七八糟的,這是不是與TableModel來工作的正確途徑,應返回的URL在getValueAt圖像(INT行, int col),在它之後,註冊CellRenderer以對應於帶有URL.class的單​​元格。渲染器是從JTable自動調用的,您無需擴展JTable,只需實現渲染器和模型。 setIconAt應只調用setValueAt並將您的URL放在列中,渲染器負責其餘部分。

+0

我已經觸發`fireTableCellUpdated(row,col)`。我會更多地更新我的問題。 – 2011-01-19 20:17:44

+0

嘗試重繪JLabel – 2011-01-19 20:20:35

+0

我試過了,沒有改變。無論如何``fireTableCellUpdated(row,col)`應該照顧。難怪我以前從來沒有搞錯過JTables!哎呀! – 2011-01-19 20:23:10

3

我的模型已經被定義爲返回JLabel.class這些細胞,

但是根據你的渲染,你在這些細胞中期待一個字符串值代碼:

setText((String)value); 

我不喜歡你的setIcon()方法。我不會傳入網址。我會通過圖標。也許你有一個問題,即在渲染單元格時圖標還沒有被讀入內存。

什麼是獲得和圖標設置爲一個JTable的一個JLabel細胞的最佳途徑,

你不應該存儲在TableModel一個JLable。將Swing組件存儲在模型中很昂貴,這就是Swing組件使用渲染器的原因。而是存儲一個自定義對象,如「LabelInfo」,其中包含兩個屬性,即文本和圖標。然後,您的自定義渲染器將擴展默認渲染器並調用super.getTableCellRendererComponent()。然後,您可以訪問您的對象並放置渲染器的文本/圖標屬性。你不應該在渲染器中創建對象。

現在,當你想改變模型的東西,你可以這樣做:

LabelInfo info = (LabelInfo)table.getValueAt(row, column); 
info.setIcon(...); 
table.setValueAt(info, row, column); 

這就是你所需要的。沒有自定義代碼來重新繪製單元格或任何東西,因爲它已經構建到setValueAt(...)方法中。你的表模型。

編輯:在TableModel中使用自定義對象的簡單示例。

1)對象添加到模型中你這樣做:

LabelInfo info = new LabelInfo("some Text", yourIcon); 
table.setValueAt(info, row, column); 

2)爲您的自定義渲染器的代碼如下:

class LabelInfoRenderer extends DefaultTableCellRenderer 
{ 
    @Override 
    public Component getTableCellRendererComponent(
     JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 
    { 
     super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 

     LableInfo info = (LabelInfo)value; 
     setIcon(info.getIcon()); 

     return this; 
    } 
}