2014-01-24 27 views
0

本質上我需要做的是在我的JTable上爲行和列模型設置ListSelectionListener,所以我知道哪個單元格已被點擊,我很好。在ListSelectionEvent導致StackOverFlow後fireTableDataChanged()

如果我單擊的單元格恰好具有JTree作爲渲染器組件,那麼我將展開/摺疊JTree,調整表格行的高度並重新繪製表格。所以我的ListSelectionListener看起來像這樣

static class TableCellSelectionListener implements ListSelectionListener { 

    private JTable _t; 

    @Override 
    public void valueChanged(ListSelectionEvent lse) { 
     if(!lse.getValueIsAdjusting()) { 
     int rowSelected = _t.getSelectedRow(); 
     int colSelected = _t.getSelectedColumn();  
     if(rowSelected > -1 && colSelected > -1) { 
      TableCellRenderer renderer = _t.getCellRenderer(rowSelected, colSelected); 
      Object obj = _t.getValueAt(rowSelected, colSelected); 
      Component c = renderer.getTableCellRendererComponent(_t, obj, true, false, rowSelected, colSelected);  
      if(c instanceof JTree) { 
      JTree tree = (JTree) c; 
      TreePath path = tree.getPathForRow(0); 

      if(tree.isExpanded(path)) { 
       tree.collapsePath(path); 
       tree.fireTreeCollapsed(path); 
      } else { 
       tree.expandPath(path); 
       tree.fireTreeExpanded(path); 
      }   

      Enumeration<TableColumn> columns = _t.getColumnModel().getColumns(); 
      while(columns.hasMoreElements()) { 
       TableColumn col = columns.nextElement(); 
       int colIndex = col.getModelIndex(); 
       if(_t.getColumnClass(colIndex) == JTree.class && colIndex != colSelected) { 
       JTree t = (JTree) _t.getValueAt(rowSelected, colIndex); 
       TreePath p = t.getPathForRow(0); 
       if(tree.isExpanded(path) && !t.isExpanded(p)) { 
        t.expandPath(p); 
        t.fireTreeExpanded(p); 
       } else if(!tree.isExpanded(path) && t.isExpanded(p)) { 
        t.collapsePath(p); 
        t.fireTreeCollapsed(p); 
       } 
       } 
      }   

      _t.setRowHeight(rowSelected, c.getPreferredSize().height); 
      //Line below causes StackOverFlow 
      ((SortableTableModel)_t.getModel()).fireTableDataChanged(); 
      _t.clearSelection(); 
      } 
     } 
     }  
    } 

    public void setTable(JTable t) { 
     _t = t; 
    } 

    } 

這樣做的「正確」方法是什麼?因爲我真的對正確的方法感興趣,所以這裏是完整的可編譯代碼,運行它你很快就會看到我的目標(正如已經提到的具有JTree組件的表單元展開/摺疊,錶行的高度也需要反映JTree的狀態)

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.beans.PropertyChangeSupport; 
import java.util.Arrays; 
import java.util.Enumeration; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Random; 
import java.util.concurrent.Callable; 

import javax.swing.BorderFactory; 
import javax.swing.Icon; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JProgressBar; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.JTree; 
import javax.swing.SwingWorker; 
import javax.swing.UIManager; 
import javax.swing.WindowConstants; 
import javax.swing.event.ListSelectionEvent; 
import javax.swing.event.ListSelectionListener; 
import javax.swing.plaf.IconUIResource; 
import javax.swing.table.DefaultTableCellRenderer; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableColumn; 
import javax.swing.tree.DefaultMutableTreeNode; 
import javax.swing.tree.DefaultTreeCellRenderer; 
import javax.swing.tree.DefaultTreeModel; 
import javax.swing.tree.TreeCellRenderer; 
import javax.swing.tree.TreePath; 

public class ProgressBarPCSTable { 

    private ProgressBarValueTracker pbValueTracker = new ProgressBarValueTracker(); 

    private String[] columnNames = {"JobID","Progress", "Status"}; 
    private DefaultTableModel tableModel = new DefaultTableModel(null, columnNames) { 
    private static final long serialVersionUID = 1L; 

    @Override 
    public Class<?> getColumnClass(int column) { 
     return getValueAt(0, column).getClass(); 
    } 

    @Override 
    public boolean isCellEditable(int row, int col) { 
     return false; 
    } 
    }; 

    private JTable table = new JTable(tableModel); 

    public JComponent makeUI() { 
    TableColumn progressColumn = table.getColumnModel().getColumn(1); 
    progressColumn.setCellRenderer(new JTreeRenderer(true, pbValueTracker)); 
    TableColumn statusColumn = table.getColumnModel().getColumn(2); 
    statusColumn.setCellRenderer(new JTreeRenderer(false, pbValueTracker)); 

    //Setup row/column selection listeners 
    table.setRowSelectionAllowed(true); 
    TableCellSelectionListener cellSelectionListener = new TableCellSelectionListener(table); 
    table.getSelectionModel().addListSelectionListener(cellSelectionListener); 
    table.getColumnModel().getSelectionModel().addListSelectionListener(cellSelectionListener); 

    EventQueue.invokeLater(new Runnable() { 

     @Override 
     public void run() { 
     startTask(new Object[][]{{"000001"}, {0}, {"complete"}}); 
     startTask(new Object[][]{{"000002"}, {0,0}, {"processing","rendering pdf"}}); 
     startTask(new Object[][]{{"000003"}, {0,0,0}, {"processing","rendering pdf","rendering afp"}}); 
     startTask(new Object[][]{{"000004"}, {0,0,0,0}, {"processing","rendering pdf","rendering afp","rendering postscript"}}); 
     startTask(new Object[][]{{"000005"}, {0,0,0,0,0}, {"processing","normalsing","enhancing","sorting","rendering"}}); 
     } 
    }); 
    JPanel p = new JPanel(new BorderLayout()); 
    p.add(new JScrollPane(table)); 
    return p; 
    } 

    private void startTask(final Object[][] job) { 
    final int key = tableModel.getRowCount(); 
    final String jobID = (String) job[0][0];  

    final DefaultMutableTreeNode progressRoot = new DefaultMutableTreeNode((Integer)job[1][0]); 
    final DefaultMutableTreeNode statusRoot = new DefaultMutableTreeNode((String)job[2][0]); 

    final DefaultTreeModel progressTreeModel = new DefaultTreeModel(progressRoot); 
    final DefaultTreeModel statusTreeModel = new DefaultTreeModel(statusRoot); 

    final JTree progressTree = new JTree(progressTreeModel); 
    final JTree statusTree = new JTree(statusTreeModel); 

    if(job[1].length > 1) { 
     initJTree(progressRoot, Arrays.copyOfRange(job[1], 1, job[1].length, Integer[].class)); 
     ((DefaultTreeModel)progressTree.getModel()).nodeChanged(progressRoot); 
    } 

    if(job[2].length > 1) { 
     initJTree(statusRoot, Arrays.copyOfRange(job[2], 1, job[2].length, String[].class)); 
    } 

    pbValueTracker.initPVMap(progressTree); 

    EventQueue.invokeLater(new Runnable() { 

     @Override 
     public void run() { 
     startProgressBarTask(progressTree, progressRoot, key, false); 
     int childCount = progressRoot.getChildCount();   
     for(int i=0; i < childCount; i++) { 
      startProgressBarTask(progressTree, (DefaultMutableTreeNode)progressRoot.getChildAt(i), key, i == 1 ? true : false);   
     } 
     } 
    }); 

    tableModel.addRow(new Object[]{jobID, progressTree, statusTree}); 


    } 

    private <T> void initJTree(DefaultMutableTreeNode root, T[] list) { 
    for(T t: list) { 
     root.add(new DefaultMutableTreeNode(t)); 
    } 
    } 

    private void startProgressBarTask(final JTree progressTree, final DefaultMutableTreeNode node, 
     final int rowCount, final boolean error) { 
    LoudCall<Void, JTree> progressShout = new LoudCall<Void, JTree>() { 

     @Override 
     public Void call() throws Exception { 

     SwingWorker<Integer, Integer> progressWorker = new SwingWorker<Integer, Integer>() { 

      private int sleepDummy = new Random().nextInt(100) + 1; 
      private int lengthOfTask = 120; 

      /** 
      * Overrides the SwingWorker doInBackground, this version, increments 
      * the value of the % complete and publishes it, the process method will 
      * pick up the published value so that the ProgressBarRenderer can 
      * deal with it. It also triggers a nodeChanged event on the DefaultTreeModel 
      * so that the JTree updates 
      */ 
      @Override 
      protected Integer doInBackground() throws Exception {    
      int current = 0; 
      DefaultMutableTreeNode root = (DefaultMutableTreeNode) progressTree.getModel().getRoot(); 
      String suffix = root == node ? "_root" : "_" +root.getIndex(node); 
      String key = String.valueOf(System.identityHashCode(progressTree)) +suffix; 
      while(current < lengthOfTask && !isCancelled()) { 
       if(error && current >= 60) { //Error test 
       cancel(true); 
       publish(-1); 
       pbValueTracker.putErrMap(key, -1); 
       System.out.println(pbValueTracker.getErrMap()); 
       return -1; 
       } 
       current++; 
       try { 
       Thread.sleep(sleepDummy); 
       } catch (InterruptedException ie) { 
       break; 
       } 
       int value = 100 * current/lengthOfTask; 
       publish(value); 
       if(!pbValueTracker.getErrMap().containsKey(key)) { 
       pbValueTracker.putPVMap(key, value); 
       }    
      } 
      return sleepDummy * lengthOfTask; 
      } 

      /** 
      * Attach a user object to the node, in this case 
      * it is an Integer with the latest value triggered by publish 
      * process will fire getTreeCellRendererComponent of the 
      * ProgressBarRenderer 
      * 
      * @param c - a list of Integer to process, only process the last value set 
      */ 
      @Override 
      protected void process(List<Integer> c) { 
      node.setUserObject(c.get(c.size() - 1)); 
      shoutOut(progressTree);    
      ((DefaultTreeModel)progressTree.getModel()).nodeChanged(node); 
      } 

      @Override 
      protected void done() { 
      int i = -1; 
      if(!isCancelled()) { 
       try { 
       i = get(); 
       } catch (Exception e) { 
       e.printStackTrace(); 
       }   
      } 
      System.out.println("Value: " +i); 
      shoutOut(progressTree); 
      ((DefaultTreeModel)progressTree.getModel()).nodeChanged(node); 
      System.out.println(pbValueTracker.getPVMap()); 
      } 

     }; 

     progressWorker.execute(); 

     return null; 
     } 

    }; 

    (new ListenerTask<Void, JTree>(progressShout) { 

     @Override 
     protected void process(List<JTree> chunks) { 
     tableModel.setValueAt(chunks.get(chunks.size() - 1), rowCount, 1); 
     tableModel.fireTableDataChanged(); 
     }  

    }).execute(); 
    } 

    public static void main(String... args) { 
    EventQueue.invokeLater(new Runnable() { 

     @Override 
     public void run() { 
     createAndShowGUI(); 
     } 
    }); 
    } 

    public static void createAndShowGUI() { 
    JFrame frame = new JFrame(); 
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
    frame.getContentPane().add(new ProgressBarPCSTable().makeUI()); 
    frame.setSize(669, 307); 
    frame.setLocationRelativeTo(null); 
    frame.setVisible(true); 
    } 

} 

/** 
* This class listens for selection of a table cell 
* if selected and the cells component is a JTree it 
* expands/collapses the JTree and adjusts the height 
* of the table row accordingly 
* 
* @author pstatham 
* 
*/ 
class TableCellSelectionListener implements ListSelectionListener { 

    private JTable _t; 

    public TableCellSelectionListener(JTable t) { 
    _t = t; 
    } 

    @Override 
    public void valueChanged(ListSelectionEvent lse) { 
    if(!lse.getValueIsAdjusting()) { 
     int rowSelected = _t.getSelectedRow(); 
     int colSelected = _t.getSelectedColumn();  
     if(rowSelected > -1 && colSelected > -1) { 
     TableCellRenderer renderer = _t.getCellRenderer(rowSelected, colSelected); 
     Object obj = _t.getValueAt(rowSelected, colSelected); 
     Component c = renderer.getTableCellRendererComponent(_t, obj, true, false, rowSelected, colSelected);  
     if(c instanceof JTree) { 
      JTree tree = (JTree) c; 
      TreePath path = tree.getPathForRow(0); 

      if(tree.isExpanded(path)) { 
      tree.collapsePath(path); 
      tree.fireTreeCollapsed(path); 
      } else { 
      tree.expandPath(path); 
      tree.fireTreeExpanded(path); 
      }   

      Enumeration<TableColumn> columns = _t.getColumnModel().getColumns(); 
      while(columns.hasMoreElements()) { 
      TableColumn col = columns.nextElement(); 
      int colIndex = col.getModelIndex(); 
      if(_t.getColumnClass(colIndex) == JTree.class && colIndex != colSelected) { 
       JTree t = (JTree) _t.getValueAt(rowSelected, colIndex); 
       TreePath p = t.getPathForRow(0); 
       if(tree.isExpanded(path) && !t.isExpanded(p)) { 
       t.expandPath(p); 
       t.fireTreeExpanded(p); 
       } else if(!tree.isExpanded(path) && t.isExpanded(p)) { 
       t.collapsePath(p); 
       t.fireTreeCollapsed(p); 
       } 
      } 
      }   

      _t.setRowHeight(rowSelected, c.getPreferredSize().height); 
      ((DefaultTableModel)_t.getModel()).fireTableDataChanged(); 
      _t.clearSelection(); 
     } 
     } 
    }  
    } 

} 

/** 
* This class keeps track of a particular JProgressBar's previous 
* value in case it has gone in to error 
* @author pstatham 
* 
*/ 
class ProgressBarValueTracker { 

    private HashMap<String, Integer> pvMap = new HashMap<String, Integer>(); 
    private HashMap<String, Integer> errMap = new HashMap<String, Integer>(); 

    public void initPVMap(JTree tree) { 
    String key = String.valueOf(System.identityHashCode(tree)) +"_root"; 
    DefaultMutableTreeNode root = (DefaultMutableTreeNode) ((DefaultTreeModel)tree.getModel()).getRoot(); 
    pvMap.put(key, (Integer) root.getUserObject()); 
    for(int i=0; i < root.getChildCount(); i++) { 
     key = String.valueOf(System.identityHashCode(tree)) +"_" + i; 
     DefaultMutableTreeNode child = (DefaultMutableTreeNode) root.getChildAt(i); 
     pvMap.put(key, (Integer) child.getUserObject()); 
    } 
    } 

    public void putPVMap(String key, Integer value) { 
    pvMap.put(key, value); 
    } 

    public void putErrMap(String key, Integer value) { 
    errMap.put(key, value); 
    } 

    public HashMap<String, Integer> getPVMap() { 
    return pvMap; 
    } 

    public HashMap<String, Integer> getErrMap() { 
    return errMap; 
    } 

} 


/** 
* This class extends the DefaultTreeCellRenderer and returns a JPanel with a 
* JProgressBar attached as its renderer component 
* @author pstatham 
* 
*/ 
@SuppressWarnings("serial") 
class ProgressBarRenderer extends DefaultTreeCellRenderer { 

    private final JProgressBar progressBar = new JProgressBar(0, 100); 

    private ProgressBarValueTracker pbValueTracker; 

    public ProgressBarRenderer(ProgressBarValueTracker tracker) { 
    super();  
    pbValueTracker = tracker; 
    setOpaque(true); 
    configureProgressBar(progressBar);  
    progressBar.setBackground(Color.YELLOW);  
    } 

    @Override 
    public Component getTreeCellRendererComponent(JTree tree, final Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { 
    if(((DefaultMutableTreeNode) value).getUserObject() instanceof String) { 
     super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); 
     return this; 
    } 

    DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot(); 
    String suffix = root == value ? "_root" : "_" +root.getIndex((DefaultMutableTreeNode)value); 
    String key = String.valueOf(System.identityHashCode(tree)) +suffix;  

    JPanel p = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0)); 
    p.setBackground(Color.WHITE);  

    JLabel l = (JLabel)super.getTreeCellRendererComponent(tree, null, selected, expanded, leaf, row, hasFocus); 

    if(((DefaultMutableTreeNode)value).isRoot() && ((DefaultMutableTreeNode)value).getChildCount() > 0) { 
     TreePath path = tree.getPathForRow(row); 
     if(tree.isExpanded(path)) { 
     l.setIcon(new IconUIResource(new NodeIcon('-'))); 
     } else { 
     l.setIcon(new IconUIResource(new NodeIcon('+'))); 
     } 
    } else { 
     l.setIcon(new IconUIResource(new NodeIcon(' '))); 
    } 

    p.add(l);  

    Integer i = (Integer) ((DefaultMutableTreeNode) value).getUserObject(); 

    // 
    // If Job is in error return a different 
    // JProgressBar with a red background 
    // 
    if(i<0) {    
     JProgressBar errorProgressBar = new JProgressBar(0, 100); 
     configureProgressBar(errorProgressBar); 
     errorProgressBar.setBackground(Color.RED);  
     errorProgressBar.setValue(pbValueTracker.getPVMap().get(key)); 
     p.add(errorProgressBar); 
    } else { 
     progressBar.setValue(i); 
     p.add(progressBar); 
    }  
    return p;  
    } 

    /** 
    * Configure a JProgressBar with common options 
    * 
    * @param pb JProgressBar to configure 
    */ 
    private void configureProgressBar(JProgressBar pb) { 
    pb.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); 
    pb.setForeground(Color.GREEN.darker()); 
    pb.setStringPainted(true); 
    pb.setPreferredSize(new Dimension(pb.getPreferredSize().width, 16)); 
    } 

} 

/** 
* This class extends the DefaultTableCellRenderer and returns a JTree 
* as its renderer component. The JTrees renderer 
* can either be an instance of a ProgressBarRenderer or a 
* DefaultTreeCellRenderer that returns a label with an open/close icon 
* as its renderer component. 
* @author pstatham 
* 
*/ 
@SuppressWarnings("serial") 
class JTreeRenderer extends DefaultTableCellRenderer { 

    private JTree tree; 
    private TreeCellRenderer renderer; 

    public JTreeRenderer(boolean progressTree, ProgressBarValueTracker tracker) {  
    if(progressTree) { 
     renderer = new ProgressBarRenderer(tracker);  
    } else { 
     renderer = new DefaultTreeCellRenderer() {   
     @Override 
     public Component getTreeCellRendererComponent(final JTree tree, Object value, 
      boolean sel,boolean expanded,boolean leaf,int row,boolean hasFocus){ 
      JLabel label = (JLabel)super.getTreeCellRendererComponent(tree,value, 
       sel,expanded,leaf,row,hasFocus); 
      if(((DefaultMutableTreeNode)value).isRoot() && ((DefaultMutableTreeNode)value).getChildCount() > 0) { 
      TreePath path = tree.getPathForRow(row); 
      if(tree.isExpanded(path)) { 
       label.setIcon(new IconUIResource(new NodeIcon('-'))); 
      } else { 
       label.setIcon(new IconUIResource(new NodeIcon('+'))); 
      } 
      } else { 
      label.setIcon(new IconUIResource(new NodeIcon(' '))); 
      } 
      return label; 
     }     
     }; 
    }  
    } 

    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 
    tree = (JTree) value; 
    tree.setCellRenderer(renderer); 
    table.setRowHeight(row, tree.getPreferredSize().height); 
    return tree; 
    } 

} 

/** 
* Pinched from http://stackoverflow.com/a/7984734/564045 
* @author pstatham 
* 
*/ 
class NodeIcon implements Icon { 

    private static final int SIZE = 9; 

    private char type; 

    public NodeIcon(char type) { 
    this.type = type; 
    } 

    public void paintIcon(Component c, Graphics g, int x, int y) { 
    if(type != ' ') { 
     g.setColor(UIManager.getColor("Tree.background")); 
     g.fillRect(x, y, SIZE - 1, SIZE - 1); 

     g.setColor(UIManager.getColor("Tree.hash").darker()); 
     g.drawRect(x, y, SIZE - 1, SIZE - 1); 

     g.setColor(UIManager.getColor("Tree.foreground")); 
     g.drawLine(x + 2, y + SIZE/2, x + SIZE - 3, y + SIZE/2); 
     if (type == '+') { 
     g.drawLine(x + SIZE/2, y + 2, x + SIZE/2, y + SIZE - 3); 
     }  
    } 
    } 

    public int getIconWidth() { 
    return SIZE; 
    } 

    public int getIconHeight() { 
    return SIZE; 
    } 
} 

/** 
* Wrapper for the background logic 
* http://stackoverflow.com/a/6834797/564045 
* @author pstatham 
* 
* @param <T> return type 
* @param <S> intermediary type (the "shout out") 
*/ 
abstract class LoudCall<T, S> implements Callable<T> { 

    private PropertyChangeSupport pcs; 
    private S shout; 

    public LoudCall() { 
    pcs = new PropertyChangeSupport(this); 
    } 

    public void shoutOut(S s) { 
    pcs.firePropertyChange("shoutOut", this.shout, this.shout = s); 
    } 

    public void addListener(PropertyChangeListener listener) { 
    pcs.addPropertyChangeListener(listener); 
    } 

    public void removeListener(PropertyChangeListener listener) { 
    pcs.removePropertyChangeListener(listener); 
    } 

    @Override 
    public abstract T call() throws Exception; 

} 

/** 
* Wrapper for the GUI listener. 
* http://stackoverflow.com/a/6834797/564045 
* @author pstatham 
* 
* @param <T> return type 
* @param <S> intermediary type (the "shout out" to listen for) 
*/ 
abstract class ListenerTask<T, S> extends SwingWorker<T, S> implements PropertyChangeListener { 

    private LoudCall<T, S> aMethod; 

    public ListenerTask(LoudCall<T, S> aMethod) { 
    this.aMethod = aMethod; 
    } 

    @Override 
    protected T doInBackground() throws Exception { 
    aMethod.addListener(this); 
    return aMethod.call(); 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public void propertyChange(PropertyChangeEvent evt) { 
    if("shoutOut".equals(evt.getPropertyName())) { 
     publish((S)evt.getNewValue()); 
    } 
    } 

    @Override 
    protected abstract void process(List<S> chunks); 
} 
+2

--->請什麼目標,理由或期望,因爲fireTableDataChanged()可用於XxxTableCellRenderer正在重置一切(永遠,不這樣做裏面的Listener,Renderer沒有被設置,使用,啓動,改變這種方式),確保爲更快的幫助發佈一個SSCCE/MCVE,短小的,可運行的,可編譯的JTable/JTree編碼值,來自局部變量 – mKorbel

+3

fireXxxXxx僅用於方法在模型API中實現,並且不能從外部調用 – mKorbel

+0

我有一個SSCCE,但它不會產生一個StackOverflow(我首先開發了這個概念,然後嘗試將它實現爲真正的代碼),從我的使用Google搜索我明白fireXXXX僅適用於Models API,但如果是這種情況,更新(a)JTree(b)JTable以便重新繪製它們的最佳方法是什麼(在上例中)? – PDStat

回答

-1

我真的不明白你的意見,但我設法得到它的工作通過設置一個布爾標誌

public void valueChanged(ListSelectionEvent lse) { 
    if(!lse.getValueIsAdjusting()) 
     if(!methodCalled) { 
     //Logic for expanding/collapsing JTree and adjusting 
     //JTable row height 
     methodCalled = true; 
     fireTableDataChanged(); 
     methodCalled = false; 
     } 
    } 
} 
+0

不會手動調用任何fireXX - 這取決於通知其聽衆的模型。或者相反:如果手動解僱似乎解決了一個問題,你在其他地方做錯了什麼 – kleopatra

+0

感嘆......我會在稍後發佈SSCCE,這樣我就可以看到「正確」的方式來做到這一點,這這首先是問題的關鍵,我在這裏學習 – PDStat

0

似乎每DefaultTableModel.fire .. 。()方法也會導致ListSelectionEven噸。想象一下你的模型在更新之後的情況,例如刪除一些先前選擇的模型。在這種情況下,列表選擇必須重新計算,因此新的ListSelectionEvent。我猜JDK總是在TableModel.fire ...()之後重新計算列表選擇。請參閱this JDK的錯誤報告。 我希望至少fireTableCellUpdated()它不會發生,但它是。

你可以做的是使用上面描述的標誌,或者根據第一個事件是選擇'clear'事件(選定行是空的)並且下一個事件具有與之前。 下面的單項選擇情況下,代碼:從另一個角度

int prevSel = -1; 
... 
public void valueChanged(ListSelectionEvent lse) { 

    if(lse.getValueIsAdjusting() || getSelectedRows().length==0 || getSelectedRows()[0]==prevSel) 
    return; 
    prevSel = getSelectedRows()[0]; 

    ... your code ... 
    fireTableDataChanged(); 
} 
相關問題