Java Swing: JTable contains many models and custom renderers

I have a JTable. I recolor the rows according to the values of the model, as shown below:

resultTable = new javax.swing.JTable(){
    private Border outside = new MatteBorder(1,1,Color.BLACK);
    private Border inside = new EmptyBorder(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;
    }
};

I set different models (myfirsttablemodel, mysecondtablemodel) according to the VaR state in the swing worker thread, and display the modal dialog box of "please wait"

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);

Change the model in the refresh() method:

if (getMainFrameStatus().equals("status2")) {
     @Override
                public void run() {
                    //Update the model here

                    resultTable.setModel(new mySecondTableModel(data));
                }
            });

But I think I'll call preparererender when I wait for the dialog box to confuse my table However, different models have not been applied

Obviously I understand

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: myFirstTableModel cannot be cast to mySecondTableModel at mySecondTableModel model = (mySecondTableModel) resultTable.getModel();

Can I allow tables to call preparereader? How to make this mess work?

Solution

It is best not to smear the details of the data (business) field into the view In your context, you can f.i. achieve clean separation

>Define an interface with the concept of state (note, note...) > let your custom model implement this interface > in the view, access the state of the model through this interface

Image (not compiled, just a pseudo code fragment)

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;
       }
}

edit

Similar to swingx (cough... No tutorial, only API doc, Wiki, snippets, swinglabs demo):

>Implement custom highlightpredicate: This determines whether a given cell should be visually "decorated" It has only one implementation that allows read access to data through the componentadapter > configure a predefined highlighter with predicates (there are a lot) > add the highlighter to the table

Excerpt from 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);

Edit 2

It does not directly support accessing data that does not belong to the model Although it has been dormant for some time, it never seems enough to skip it:) it violates the basic idea that there is a common abstraction to access data without knowing the type and model of the underlying components (highlighter) / - predict and stringvalue are the same for tables, lists and trees)

With this in mind, you can get it indirectly through the target component of the adapter:

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
      }
  }
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>