[英]Java swing: Jtable with many models and custom renderer
我有一個jtable,我根據模型的值重新着色行,如下所示:
resultTable = new javax.swing.JTable(){
private Border outside = new MatteBorder(1, 0, 1, 0, Color.BLACK);
private Border inside = new EmptyBorder(0, 1, 0, 1);
private Border highlight = new CompoundBorder(outside, inside);
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
JComponent jc = (JComponent) c;
// Color row based on a cell value
if (!isRowSelected(row)) {
c.setBackground(getBackground());
int modelRow = convertRowIndexToModel(row);
if (getStatus().equals("status1")) {
myFirstTableModel model = (myFirstTableModel ) resultTable.getModel();
if ((model.getObjectAtRow(modelRow).getMsg().getRegNumIn() == 3)) {
c.setBackground(new Color(255, 244, 148));//YELLOW - needs attension
}
} else if (getStatus().equals("status2")) {
mySecondTableModel model = (mySecondTableModel) resultTable.getModel();
if (model.getObjectAtRow(modelRow).getMsg().getTask() == 2) {
c.setBackground(new Color(210, 245, 176));//GREEN - got attension
}
}
} else if (isRowSelected(row)) {
jc.setBorder(highlight);
c.setBackground(new Color(201, 204, 196));
}
return c;
}
};
我根據SwingWorker線程中的var 狀態設置了不同的模型(myFirstTableModel,mySecondTableModel),並顯示“請等待”的模態對話框。
final WaitDialog dialog = new WaitDialog(new javax.swing.JFrame(), true);
dialog.addWindowListener(new java.awt.event.WindowAdapter() {
});
SwingWorker worker = new SwingWorker() {
@Override
protected Object doInBackground() throws Exception {
setStatus("status2");
Refresh();
return 0;
}
@Override
public void done() {
dialog.dispose();
}
};
worker.execute();
dialog.setVisible(true);
在Refresh()方法中更改模型:
if (getMainFrameStatus().equals("status2")) {
@Override
public void run() {
//Update the model here
resultTable.setModel(new mySecondTableModel(data));
}
});
但是我認為在等待dialog
混淆我的表時會調用prepareRendere
。 但是還沒有應用不同的模型。
顯然我明白了
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: myFirstTableModel cannot be cast to mySecondTableModel at mySecondTableModel model = (mySecondTableModel) resultTable.getModel();
我可以允許表調用prepareRenderer
嗎? 如何使這個混亂正常工作?
最好不要將數據(業務)域的詳細信息塗抹到視圖中。 在您的背景下,您可以實現清潔分離
像(未編譯,只是一個偽代碼片段)
public interface StatusAware {
enum Status {
NORMAL,
GOT_ATTENTION,
NEEDS_ATTENTION,
...
}
public Status getStatus(int modelIndex);
}
public class MyFirstTableModel extends AbstractTableModel implements StatusAware {
public Statuc getStatus(int modelRow) {
boolean needsAttention = getObjectAtRow(modelRow).getMsg().getRegNumIn() == 3;
return needsAttention ? NEEDS_ATTENTION : NORMAL;
}
....
}
public class MySecondTableModel extends AbstractTableModel implements StatusAware {
public Statuc getStatus(int modelRow) {
return // the status of the given row
}
....
}
public class MyTable extends JTable { // if you insist on not using JXTable
public Component prepareRenderer(...) {
Component comp = super(...)
if (getModel() instanceof StatusAware {
Status status = ((StatusAware) getModel()).getStatus(convertRowIndexToModel(row));
if (NEEDS_ATTENTION == status) {
...
} else if (...) {
...
}
}
return comp;
}
}
編輯
類似於SwingX(咳嗽......沒有教程,只有api doc,wiki,snippets,swinglabs-demo):
摘錄自ComponentAdapter api doc
HighlightPredicate feverWarning = new HighlightPredicate() {
int temperatureColumn = 10;
public boolean isHighlighted(Component component, ComponentAdapter adapter) {
return hasFever(adapter.getValue(temperatureColumn));
}
private boolean hasFever(Object value) {
if (!value instanceof Number)
return false;
return ((Number) value).intValue() > 37;
}
};
Highlighter hl = new ColorHighlighter(feverWarning, Color.RED, null);
table.addHighlighter(hl);
編輯2
不直接支持訪問不屬於模型的數據。 雖然它潛伏了一段時間,它似乎永遠不足以跳過它:)它有點違反了基本思想:有一個共同的抽象來訪問數據而不知道底層組件的類型和模型(熒光筆) / -Predicate和StringValue對於表,列表,樹完全相同)。
考慮到這一點,您可以通過適配器的目標組件間接獲取它:
if (adapter.getComponent() instanceof JTable) {
JTable table = (JTable) adapter.getComponent();
TableModel model = table.getModel();
if (model instanceof MyModel) {
int modelRow = adapter.convertRowIndexToModel(adapter.row);
MyObject object = ((MyModel).getRowObjectAt(modelRow));
... // check the object
}
}
首先,您可能希望強制事件等到模型重新加載后再調用
SwingUtilities.invokeLater(...)
在他們旁邊。 或者可能強制模型加載優先。 不太確定,但是
SwingUtilities.invokeAndWait(...)
可能是你想要的。
其次,您可能想要從SwingX中查看JXTable。 具體來說,熒光筆可以讓你的生活更輕松一些。 在我當前的項目中,為我節省了大量代碼 - 我現在不需要維護(是的!)
我根據我的表(myFirstTableModel,mySecondTableModel)設置了不同的模型
然后,您需要在prepareRenderer(...)代碼中使用不同的邏輯來支持這兩個模型。
在這種情況下,您可能需要2個不同的表。 然后,您將更改滾動窗格的視口中的表,而不是更改表中的模型。
對於行着色是SwingX項目的JXTable確實是一個很好的建議。
除此之外,為什么要覆蓋此prepareRenderer
方法,以便首先更改由渲染器創建的組件的設置。
對於那個特定的問題,當我切換模型時,我會更改表格上的渲染器,並將所有邏輯放在我的渲染器中。
如果您還沒有自己的渲染器,那么就像裝飾默認渲染器一樣簡單,並將您現在在prepareRenderer
擁有的代碼應用於默認渲染器返回的組件。
您的方法有問題:
JTable
依賴於TableModel
兩種不同實現。 JTable
實現,並將它們與您的specific
TableModel
耦合。 我的建議是在JTable上實現兩種不同的實現。 當您注意到status
的值更改時,請更改JTable。
除此之外, status
和model
是兩個不同的屬性,需要在您的情況下進行同步。
所以,您需要注意,在后台線程中需要更改的內容以及在EDT上的內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.