2010-06-22 3 views
1

많은 양의 항목 (사전 항목)을 표시해야하는 Java 애플릿이 있습니다. 사용자는 목록에서 개별 항목을 선택할 수 있어야하므로 JList로 구현됩니다. 목록을 생성하는 것은 HTML을 사용하여 개별 항목의 형식을 지정하여 더보기 좋게 디스플레이를 만들기로 결정할 때까지 매우 빨랐습니다. 이제 목록이 꽤 보이지만 사용자가 사전에 액세스 할 때마다 (거의 즉시 서식을 지정하지 않고)이를 생성 할 때마다 10 ~ 15 초가 소요됩니다. 사용자가 처음 응용 프로그램을 시작하고 필요에 따라 목록을 숨기거나 숨기기 만하면 목록을 생성하여 성능이 저하 될 수 있다고 생각합니다. 그러나 더 좋은 방법이 있는지 궁금합니다. 아마도 목록을 생성하는보다 효율적인 방법입니다.큰 JLIST를 HTML로 표시

DefaultListModel dictCodeModel = new DefaultListModel(); 
System.out.println("C"); 
while (e.hasMoreElements()) { 
    String currentEntry = ""; 
    DEntry dentry = (DEntry) e.nextElement(); 
    if (!filter)     
     dictCodeModel.addElement(dentry.theToken); // tokens have embedded html tags 

} 
System.out.println("D"); 

당신이 아주 간단 볼 수 있듯이 : 여기

는 (C와 D의 표시 사이) 느린 아래가 발생할 수있는 코드의 섹션입니다. "theToken"이 HTML로 포맷 된 경우 실제 실적이 저하됩니다. 이 문제를 해결하기 위해 내가 할 수있는 일에 대한 아이디어가 있습니까?

감사합니다.

답변

1

어떤 종류의 HTML 형식을 사용하고 있습니까? 텍스트 스타일 (글꼴, 색상)이 조금이라면 JLabel을 사용하고 속성을 적절히 설정하고 JListset it as ListCellRenderer으로 설정하면됩니다.

+0

난 당신이 함께 어디로 가고 있는지 볼 수 있지만, 나는 나에게 여러 라인 항목을 표시 할 수 뭔가가 필요합니다. 다음은 일반적인 형식 항목입니다. E995.9 다른 종류의 재래식 전쟁에 의한 전쟁으로 인한 상해

재래식 전쟁의 불특정 형태 개조 \ n 또는 문자 반환 \ r은 ListCellRenderer가있는 경우에도 JList에서 작동하지 않습니다. 제안? – Elliott

+0

@Elliott : HTML 구문 분석을 피하면서 여러 줄 텍스트를 렌더링하려면 사용자 정의 구성 요소 (또는 사용자 정의 LabelUI : http://codeguru.earthweb.com/java/articles/198.shtml)를 사용할 수 있습니다. 그것이 실제로 병목인지 여부를 확인하기 위해). 또는 JList 대신 단일 열 JTable을 사용해보십시오. IIRC JTable은 JList보다 훨씬 많은 양의 데이터 용으로 설계되었으며 실제로 표시되는 요소 만 렌더링합니다. –

+0

JTextArea 구성 요소를 사용하여 텍스트를 표시했습니다. 그것은 트릭을했다. ListCellRenderer 제안은 나를 올바른 방향으로 가리켰다. 다음 샘플 코드를 사용하여이 문제를 해결할 수있었습니다. http://forums.sun.com/thread.jspa?threadID=552711 – Elliott

1

위 링크는 최신이 아니므로 여기에 최신 정보가 있습니다.

단순히 JTable을 사용하면 초기로드 속도가 크게 향상되지만 스크롤을 처음 시작할 때 약간 느려집니다. 그리고 행 높이가 조정해야하는 새로운 문제가 있습니다. getTableCellRendererComponent 메서드를 사용하면 행, 테이블 및 구성 요소에 액세스 할 수 있으므로 TableCellRenderer을 구현하여 사용자 정의 렌더러 내에서 쉽게 수행 할 수 있습니다. 그러나 동일한 코드를 호출하는 테이블의 업데이트가 실행됩니다. 적절하게 코딩하면 문제가되지 않습니다. 그래도 다른 곳에 넣는 것이 더 나은 습관입니다. JViewport에 리스너를 추가하고 현재 볼 수있는 행만 업데이트했습니다. The code I based this on is here

또는 ListCellRenderer을 사용하여 HTML과 비슷한 JPanel을 반환 할 수 있습니다. JTextArea 만 필요한 경우 너비를 설정하여 기본 높이가 올바르게 설정되어 있는지 확인해야합니다 (like in this answer). 다시 행의 너비를 업데이트해야하며 JViewport을 기반으로이를 수행하는 것이 좋습니다.

두 가지 방법의 성능에 대해 궁금한 점이 있다면 JPanel을 반환하는 사용자 정의 렌더러는 JLabels 렌더링 HTML보다 빠릅니다. 몇 천 개의 항목이있는 목록에서도 두 가지 모두 상당히 빠릅니다. 언급했듯이 처음 스크롤 할 때 약간 느려질 수 있습니다.

마지막으로, 여기에 짧은 비교 자신을 만들 수 있습니다 일부 코드입니다 :

import java.awt.*; 
import java.awt.event.*; 
import java.util.*; 
import java.util.Timer; 
import java.util.concurrent.ExecutionException; 

import javax.swing.*; 
import javax.swing.event.*; 
import javax.swing.table.*; 

public class JTableHtmlTest extends JFrame { 

    protected static final long serialVersionUID = 1L; 

    public static class Item { 
     public int id; 
     public String msg; 
    } 

    static class TableModel extends AbstractTableModel { 

     private static final long serialVersionUID = JListTest.serialVersionUID; 
     private Item[] items = new Item[] {}; 

     public int getRowCount() { 
      return items.length; 
     } 

     public int getColumnCount() { 
      return 1; 
     } 

     public Object getValueAt(int rowIndex, int columnIndex) { 
      return items[rowIndex]; 
     } 

     @Override 
     public String getColumnName(int column) { 
      return ""; 
     } 

     public void updateItems() { 
      SwingWorker<Item[], Void> worker = new SwingWorker<Item[], Void>() { 

       @Override 
       protected Item[] doInBackground() throws Exception { 
        final Item[] tempList = new Item[3000]; 
        for (int i = 0; i < tempList.length; i++) { 
         Item item = new Item(); 
         item.id = (int) (Math.random() * 10000); 
         item.msg = "This is the default message that has to be" 
           + " long enough to wrap around a few times so that" 
           + " we know things are working. It's rather tedious to write."; 
         tempList[i] = item; 
        } 
        return tempList; 
       } 

       @Override 
       protected void done() { 
        try { 
         items = get(); 
         fireTableDataChanged(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } catch (ExecutionException e) { 
         e.printStackTrace(); 
        } 

       } 
      }; 
      worker.execute(); 
     } 

    } 

    public static class TableRenderer implements TableCellRenderer { 

     private static final String strColor = "#EDF5F4"; 
     private static final Color strideColor = Color.decode(strColor); 

     JLabel htmlLabel = new JLabel(); 
     JPanel noHtmlPanel = new JPanel(); 
     JLabel noHtmlLabel = new JLabel(); 
     JTextArea noHTMLTextArea = new JTextArea(); 
     Item toRender = null; 
     boolean useHtml = false; 

     public TableRenderer() { 
      noHTMLTextArea.setWrapStyleWord(false); 
      noHTMLTextArea.setLineWrap(true); 
      noHTMLTextArea.setOpaque(false); 

      Font defaultFont = noHtmlLabel.getFont(); 
      Font boldFont = defaultFont.deriveFont(Font.BOLD); 
      noHtmlLabel.setFont(boldFont); 
      noHtmlLabel.setOpaque(false); 

      noHtmlPanel.setLayout(new BorderLayout()); 
      noHtmlPanel.add(noHtmlLabel, BorderLayout.NORTH); 
      noHtmlPanel.add(noHTMLTextArea, BorderLayout.SOUTH); 
     } 

     public void setUseHtml(boolean useHtml) { 
      this.useHtml = useHtml; 
     } 

     public Component getJlabelRenderer(JTable table, Item value, int row) { 

      String colorString = ""; 
      if (row % 2 == 0) { 
       colorString = "background-color:" + strColor + ";"; 
      } 
      if (toRender != value) { 
       toRender = value; 
       htmlLabel.setText("<html><div style='padding:2px;" + "width:" 
         + table.getWidth() + ";" + colorString 
         + "color:black;'>" 
         + "<div style='padding:2px;font-weight:500;'>" 
         + "Item " + value.id + "</div>" + value.msg 
         + "</div></html>"); 
      } 

      return htmlLabel; 
     } 

     public Component getNoHtmlRenderer(JTable table, Item value, int row) { 
      if (toRender != value) { 
       toRender = value; 
       noHtmlLabel.setText("Item " + value.id); 
       noHTMLTextArea.setText(value.msg); 

       if (row % 2 == 0) { 
        noHtmlPanel.setBackground(strideColor); 
        noHtmlPanel.setOpaque(true); 
       } else { 
        noHtmlPanel.setOpaque(false); 
       } 
      } 

      return noHtmlPanel; 
     } 

     public Component getTableCellRendererComponent(JTable table, 
       Object value, boolean isSelected, boolean hasFocus, int row, 
       int column) { 
      if (useHtml) { 
       return getJlabelRenderer(table, (Item) value, row); 
      } else { 
       return getNoHtmlRenderer(table, (Item) value, row); 
      } 
     } 

    } 

    public JTableHtmlTest() { 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JPanel controlPanel = new JPanel(); 
     JButton updaterControl = new JButton("Update 3000"); 
     final JCheckBox useHtmlControl = new JCheckBox("Use HTML"); 
     final TableModel model = new TableModel(); 
     final JTable table = new JTable(model); 
     final TableRenderer renderer = new TableRenderer(); 
     JScrollPane scrollPane = new JScrollPane(table); 
     final JLabel durationIndicator = new JLabel("0"); 

     controlPanel.add(useHtmlControl, BorderLayout.WEST); 
     controlPanel.add(updaterControl, BorderLayout.EAST); 

     getContentPane().add(controlPanel, BorderLayout.PAGE_START); 
     getContentPane().add(scrollPane, BorderLayout.CENTER); 
     getContentPane().add(durationIndicator, BorderLayout.PAGE_END); 

     table.setDefaultRenderer(Object.class, renderer); 

     // Only update the JTable row heights when they are in view 
     final JViewport viewport = scrollPane.getViewport(); 
     viewport.addChangeListener(new ChangeListener() { 
      public void stateChanged(ChangeEvent e) { 
       Rectangle viewRect = viewport.getViewRect(); 
       int first = table.rowAtPoint(new Point(0, viewRect.y)); 
       if (first == -1) { 
        return; 
       } 
       int last = table.rowAtPoint(new Point(0, viewRect.y 
         + viewRect.height - 1)); 
       if (last == -1) { 
        last = model.getRowCount() - 1; 
       } 

       int column = 0; 
       for (int row = first; row <= last; row++) { 
        Component comp = table.prepareRenderer(
           table.getCellRenderer(row, column), 
           row, column); 
        int rowHeight = comp.getPreferredSize().height; 
        table.setRowHeight(row, rowHeight); 
       } 
      } 
     }); 

     updaterControl.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       renderer.setUseHtml(useHtmlControl.isSelected()); 
       model.updateItems(); 
      } 
     }); 

     Timer counter = new Timer(); 
     counter.schedule(new TimerTask() { 
      @Override 
      public void run() { 
       String previousCounter = durationIndicator.getText(); 
       final String newCounter = Integer.toString(Integer 
         .parseInt(previousCounter) + 1); 
       SwingUtilities.invokeLater(new Runnable() { 
        public void run() { 
         durationIndicator.setText(newCounter); 
         setTitle(newCounter); 
        } 
       }); 
      } 
     }, 0, 100); 
    } 

    public static void main(String args[]) { 
     EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       try { 
        JTableHtmlTest jlt = new JTableHtmlTest(); 
        jlt.pack(); 
        jlt.setSize(300, 300); 
        jlt.setVisible(true); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 

    } 
} 
관련 문제