日期:2014-05-20  浏览次数:20811 次

JScrollPane中JTable更新内容问题
我在一个大的panel中用BorderLayout布局,把scrollpane加在east,如下所示

scrollpane初始状态里面是没有表格的,后面有个函数在每次更新表格数据时调用,将表格加进scrollpane

然后界面一生成布局就混乱。。。得把鼠标移来移去才能看到组建出现,还是不完整的出现,后面更新数据也一样。求教。。。

Java code


           private JScrollPane playerScrollPane;
           public FieldPanel(){     //panel的构造函数
                playerScrollPane=new JScrollPane();
        playerScrollPane.setPreferredSize(new Dimension(200, 400));   //大的panel的大小是(800,600)
        add(playerScrollPane,BorderLayout.EAST);
           }

           //.........

           public void setPlayersTable(Map<LoginMessage, Integer> playersMap){
        Set<LoginMessage> playersSet=playersMap.keySet();
        Iterator<LoginMessage> iterator=playersSet.iterator();
        
        final Object [][] data =new Object[playersMap.size()][4];
        for(int i=0;i<playersMap.size()&&iterator.hasNext();i++){
            LoginMessage loginMessage=iterator.next();
            data[i][0]="";//头像
            data[i][1]=loginMessage.name;
            data[i][2]=loginMessage.rank;
            data[i][3]=loginMessage.mark;
        }
        TableModel tableModel=new AbstractTableModel() {
            
            @Override
            public Object getValueAt(int rowIndex, int columnIndex) {
                // TODO Auto-generated method stub
                return data[rowIndex][columnIndex];
            }
            
            @Override
            public int getRowCount() {
                // TODO Auto-generated method stub
                return data.length;
            }
            
            @Override
            public int getColumnCount() {
                // TODO Auto-generated method stub
                return 4;
            }
            public String getColumnName(int column) {return names[column];}
                        public Class getColumnClass(int c) {return getValueAt(0, c).getClass();}
                        public boolean isCellEditable(int row, int col) {return false;}
                        public void setValueAt(Object aValue, int row, int column) { data[row][column] = aValue; }
        };
    
        playersTable=new JTable(tableModel);
        TableRowSorter<TableModel> rowSorter=new TableRowSorter<TableModel>(tableModel);
        playersTable.setRowSorter(rowSorter);
        playersTable.setRowHeight(50);
        
        SwingUtilities.invokeLater(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub        关键就在这里面了,数据是更新了,但布局一片混乱
                playerScrollPane.setViewportView(playersTable);
//                playerScrollPane.validate();
//                playerScrollPane.repaint();
                repaint();
            }
        });

    }




------解决方案--------------------
其次,不要每次更新数据就建一个新的JTable。
更新你的数据model,然后通知JTable重绘。示例代码如下:

Java code


import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;

public class FieldPanel extends JPanel {

  private JScrollPane playerScrollPane;
  private LoginMessageTableModel tableModel;

  public FieldPanel() {
    
    setLayout(new BorderLayout());
    
    tableModel = new LoginMessageTableModel();
    
    playerScrollPane = new JScrollPane(new JTable(tableModel));
    playerScrollPane.setPreferredSize(new Dimension(200, 400));
    add(playerScrollPane, BorderLayout.EAST);
  }

  public void setPlayersTable(Map<LoginMessage, Integer> playersMap) {
    
    tableModel.setData(playersMap.keySet());
  }
}

class LoginMessage {
  
  Object name, mark, rank;
}

class LoginMessageTableModel extends AbstractTableModel {
  
  private static enum Col {
    
    Unknown ("Unknown", Object.class) {
      
      @Override
      Object getData(LoginMessage message) {
        
        assert message != null;
        return "";
      }
    },
    Name ("Name", Object.class) {
      
      @Override
      Object getData(LoginMessage message) {
        
        assert message != null;
        return message.name;
      }
    },
    Rank ("Rank", Object.class) {
      
      @Override
      Object getData(LoginMessage message) {
        
        assert message != null;
        return message.rank;
      }
    },
    Mark ("Mark", Object.class) {
      
      @Override
      Object getData(LoginMessage message) {
        
        assert message != null;
        return message.mark;
      }
    },
    ;
    
    private final String display;
    private final Class<?> type;
    private Col(String display, Class<?> type) {
      
      this.display = display;
      this.type = type;
    }
    
    abstract Object getData(LoginMessage message);
  }
  
  private static final String[] COL_NAMES = new String[] {
    
    "Unknown", "Name", "Rank", "Mark"
  };
  
  private volatile List<LoginMessage> data;
  LoginMessageTableModel() {
    
    data = Collections.emptyList();
  }
  
  void setData(Iterable<LoginMessage> messages) {
    
    List<LoginMessage> list = new ArrayList<LoginMessage>();
    for(LoginMessage message : messages)
      list.add(message);
    
    data = list;
    fireTableDataChanged();
  }

  @Override
  public int getRowCount() {
    
    return data.size();
  }

  @Override
  public int getColumnCount() {
    
    return Col.values().length;
  }

  @Override
  public String getColumnName(int columnIndex) {
    
    return Col.values()[columnIndex].display;
  }

  @Override
  public Class<?> getColumnClass(int columnIndex) {
    
    return Col.values()[columnIndex].type;
  }

  @Override
  public boolean isCellEditable(int rowIndex, int columnIndex) {
    
    return false;
  }

  @Override
  public Object getValueAt(int rowIndex, int columnIndex) {
    
    LoginMessage message = data.get(rowIndex);
    return Col.values()[columnIndex].getData(message);
  }

  @Override
  public void setValueAt(Object aValue, int rowIndex, int columnIndex) {}
}