簡體   English   中英

Java swing:Jtable包含許多模型和自定義渲染器

[英]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):

  • 實現自定義HighlightPredicate:這決定了給定單元格是否應該在視覺上“裝飾”。 它只有一種實現方法,允許通過ComponentAdapter對數據進行讀訪問
  • 使用謂詞配置一個預定義的熒光筆(有一大堆)
  • 將熒光筆添加到表格中

摘錄自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。


除此之外, statusmodel是兩個不同的屬性,需要在您的情況下進行同步。

所以,您需要注意,在后台線程中需要更改的內容以及在EDT上的內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM