2014-06-10 53 views
0

使用Java中的自定義單元格渲染器重新渲染JTable時,我遇到了一些凍結SWING GUI的問題。所以我問了這個問題「Why does a JTable view update block the entire GUI?」。答案指出了一個事實,即一個沒有修改JTable並覆蓋的JList可能是一個更好的選擇。所以我用JList實現了這個例子,並遇到了同樣的問題:在生成數據時,一切正常,進度條移動。但是當視圖更新時,程序凍結並且進度條停止移動。爲什麼JList的fireContentsChanged調用會凍結整個GUI?

請注意,睡眠聲明僅僅是爲了讓世代花費更長,更實際的時間(通過JDBC讀取數千個數據集並在其中創建對象需要很長時間)。人們可以刪除它並增加生成項目的數量。但是你可以清楚地看到,HTML渲染速度很慢。但我需要這種顏色和兩條線(如果不一定是那麼多不同的顏色)。

那麼你能告訴我,我的錯誤在哪裏?我認爲,美國東部時間和其他工作是通過單獨的線程分開的,我看不出任何錯誤。

更新:我環顧了SO,發現這個問題「https://stackoverflow.com/a/20813122/2429611」。有說:

更有趣的問題是如何避免該UI阻塞,但我不認爲這是可能的只是擺動,你將不得不實施一些延遲加載,或批量渲染。

這意味着,我無法解決我的問題。它是否正確?


package example; 

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Component; 
import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.security.SecureRandom; 
import java.util.ArrayList; 
import java.util.List; 
import javax.swing.AbstractAction; 
import javax.swing.AbstractListModel; 
import javax.swing.Box; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JList; 
import javax.swing.JPanel; 
import javax.swing.JProgressBar; 
import javax.swing.JScrollPane; 
import javax.swing.ListCellRenderer; 
import javax.swing.SwingUtilities; 

public class ListExample extends AbstractListModel { 

    static List<DemoObject> internalList = new ArrayList<>(); 

     @Override 
     public int getSize() { 
      return internalList.size(); 
     } 

     @Override 
     public DemoObject getElementAt(int index) { 
      return internalList.get(index); 
     } 

     public void fireContentsChanged() { 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        fireContentsChanged(this, 0, -1); 
       } 
      }); 
     } 

    static class MyCellRenderer extends JLabel implements ListCellRenderer<ListExample.DemoObject> { 
     public MyCellRenderer() { 
      setOpaque(true); 
     } 

     @Override 
     public Component getListCellRendererComponent(JList<? extends ListExample.DemoObject> list, 
                 ListExample.DemoObject value, 
                 int index, 
                 boolean isSelected, 
                 boolean cellHasFocus) { 

      setText("<html>" + value.toString() 
        + "<br/>" 
        + "<span bgcolor=\"#ff0000\">Line 2; Color = " + value.c + "</span>"); 

      Color background; 
      Color foreground; 

      // check if this cell represents the current DnD drop location 
      JList.DropLocation dropLocation = list.getDropLocation(); 
      if (dropLocation != null 
        && !dropLocation.isInsert() 
        && dropLocation.getIndex() == index) { 

       background = Color.BLUE; 
       foreground = Color.WHITE; 

      // check if this cell is selected 
      } else if (isSelected) { 
       background = Color.RED; 
       foreground = Color.WHITE; 

      // unselected, and not the DnD drop location 
      } else { 
       background = value.c; //Color.WHITE; 
       foreground = Color.BLACK; 
      }; 

      setBackground(background); 
      setForeground(foreground); 

      return this; 
     } 
    } 

    static class DemoObject { 

     String str; 
     Color c; 

     public DemoObject(String str, int color) { 
      this.str = str; 
      this.c = new Color(color); 
     } 

     @Override 
     public String toString() { 
      return str; 
     } 

    } 

    static JPanel overlay; 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       JFrame frame = new JFrame("Example"); 
       frame.setLayout(new BorderLayout(4, 4)); 

       // Add JTable 
       final ListExample model = new ListExample(); 
       JList list = new JList(model); 
       list.setCellRenderer(new MyCellRenderer()); 
       frame.add(new JScrollPane(list), BorderLayout.CENTER); 

       // Add button 
       Box hBox = Box.createHorizontalBox(); 
       hBox.add(new JButton(new AbstractAction("Load data") { 

        @Override 
        public void actionPerformed(ActionEvent e) { 
         new Thread(new Runnable() { 

          @Override 
          public void run() { 
           overlay.setVisible(true); 
           internalList.clear(); 

           System.out.println("Generating data ..."); 

           SecureRandom sr = new SecureRandom(); 
           for (int i = 0; i < 10000; i++) { 
            internalList.add(
              new DemoObject(
                "String: " + i + " (" + sr.nextFloat() + ")", 
                sr.nextInt(0xffffff) 
              ) 
            ); 

            // To create the illusion, that data are 
            // fetched via JDBC (which takes a little 
            // while), this sleep statement is embedded 
            // here. In a real world scenario, this wait 
            // time is caused by talking to the database 
            // via network 
            if (i%10 == 0) { 
             try { 
              Thread.sleep(1); 
             } catch (Exception e) { 
             } 
            } 
           } 

           System.out.println("Updating view ..."); 

           model.fireContentsChanged(); 
           overlay.setVisible(false); 

           System.out.println("Finished."); 
          } 
         }).start(); 
        } 
       })); 
       hBox.add(Box.createHorizontalGlue()); 
       frame.add(hBox, BorderLayout.NORTH); 

       // Create loading overlay 
       overlay = new JPanel(new FlowLayout(FlowLayout.CENTER)) { 

        @Override 
        protected void paintComponent(Graphics g) { 
         g.setColor(new Color(0, 0, 0, 125)); 
         g.fillRect(0, 0, getWidth(), getHeight()); 
         super.paintComponent(g); 
        } 
       }; 
       overlay.setOpaque(false); 
       overlay.setBackground(new Color(0, 0, 0, 125)); 
       JProgressBar bar = new JProgressBar(); 
       bar.setIndeterminate(true); 
       overlay.add(bar); 

       frame.setGlassPane(overlay); 
       frame.getGlassPane().setVisible(false); 

       // Create frame 
       frame.setSize(600, 400); 
       frame.setVisible(true); 
      } 
     }); 
    } 

} 

回答

1

存在三個問題(重建,正在重置模式,以及自定義渲染採空到作品)

  1. JList (JComboBox hasn't) has an issue by removing more than 999 items,你有一個新的模式設置爲JList的

  2. 對於ComboBoxModel來說很重要extends AbstractListModel爲setElementAt實現MutableComboBoxModel(用於保存當前選擇)

  3. public void fireContentsChanged() {用法是錯誤的,看不出理由使用這種方式,又是即將取代目前,重置模型

。例如與成功atr運行時間和通過recrusive測試/如果事件(發射)

setModel(new DefaultListModel(list.toArray()) { 

     protected void fireContentsChanged(Object obj, int i, int j) { 
     if (!isFired) 
      super.fireContentsChanged(obj, i, j); 
     } 

    }); 
+0

我忘了這個模型是不完整的 – mKorbel