2013-04-17 27 views
5

Tôi tạo CellRenderer của riêng mình bao gồm một số chuỗi và JProgressBar trong một Mục JList ... Nhưng JProgressBar và vì vậy toàn bộ JList Item sẽ được vẽ một lần và tôi đang tìm cách để vẽ lại Vật phẩm ... Tôi đã cố gắng để bắt đầu một sợi, mà sẽ vĩnh viễn repaint ... Nhưng tôi không biết những gì tôi phải repaint để có được kết quả ...CellRenderer Item repaint

JList repaint ... no result CellRenderer repaint ... không có kết quả JFrame repaint ... không có kết quả

Có ai hiểu vấn đề của tôi và biết cách thoát không?

Cảm ơn bạn rất nhiều!

UPDATE: [Update đã xóa]

TIẾP UPDATE:

import java.awt.Component; 
import java.awt.Dimension; 
import javax.swing.DefaultListModel; 
import javax.swing.JFrame; 
import javax.swing.JList; 
import javax.swing.JPanel; 
import javax.swing.JProgressBar; 
import javax.swing.ListCellRenderer; 


public class Main extends JFrame{ 

public DefaultListModel contentListModel = new DefaultListModel(); 
public MyCellRenderer MCR = new MyCellRenderer(); 
public JList contentList = new JList(contentListModel); 

public Main(){ 
    super("Example"); 
    setMinimumSize(new Dimension(300,300)); 
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    contentList.setCellRenderer(MCR); 
    contentListModel.addElement(""); 
    contentListModel.addElement(""); 
    add(contentList); 
} 

public static void main(String[] args){ 
    new Main().setVisible(true); 
} 

class MyCellRenderer extends JPanel implements ListCellRenderer{ 

    public MyCellRenderer(){ 
     JProgressBar jpb = new JProgressBar(); 
     jpb.setIndeterminate(true); 
     add(jpb); 
    } 

    @Override 
    public Component getListCellRendererComponent(JList arg0, Object arg1, 
      int arg2, boolean arg3, boolean arg4) { 
     // TODO Auto-generated method stub 
     return this; 
    } 



} 

} 
+0

[SSCCE] (http://sscce.org/) đầu tiên, trả lời thứ hai;) – MadProgrammer

+0

để được giúp đỡ tốt hơn sớm gửi một [SSCCE] (http://sscce.org/), ngắn, runnable, compilable, chỉ về vấn đề sáng – mKorbel

+0

Để chuyển 2 tệp nguồn thành SSCCE, chỉ có một tệp được khai báo là 'công khai'. Thêm nguồn cho lớp thứ 2, vào cuối nguồn cho lần đầu tiên. –

Trả lời

0

Thật dễ dàng.

public void updateListData(final JList myList) { 
    SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
     ListModel lm = myList.getModel(); 
     DefaultListModel dlm = new DefaultListModel(); 
     for (int i = 0; i < lm.getSize(); i++) { 
     dlm.addElement(lm.getElementAt(i)); 
     } 
     myList.setModel(dlm); 
    } 
    }); 
} 

Đoạn mã trên có thể được gọi từ EDT và từ một chuỗi khác. Nhưng bạn cũng nên đọc cách xử lý các thành phần Swing và hiểu các mô hình (ListModel, TableModel, vv). Để yêu cầu một phần tử trong JList vẽ lại bạn nên sửa đổi đối tượng của nó trong mô hình.

+0

Điều này sẽ không thay đổi bất cứ điều gì. Bên cạnh đó, đó là một overkill để tạo lại toàn bộ ListModel với cùng một giá trị chính xác. Bạn có thể chỉ cần gọi 'myList.repaint()' để có cùng một hiệu ứng (mà vẫn không giải quyết được vấn đề). –

+0

@Sergiy Medvynskyy không và trả lời cho ListCellRenderer, xin vui lòng để xóa câu trả lời này – mKorbel

2

Trình kết xuất ô là tem tĩnh/cao su của các thành phần, chúng không phải là thành phần hoạt động "thực". Chúng chỉ đơn giản là "sơn" lên bề mặt của chế độ xem sử dụng chúng.

Điều này có nghĩa là không thực sự có thể vẽ lại chúng như vậy. Bạn có thể khuyến khích danh sách cập nhật bằng cách thay đổi giá trị của hàng bạn muốn thay đổi. Điều này sẽ làm cho mô hình kích hoạt bản cập nhật sẽ làm cho danh sách phải được sơn lại.

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.DefaultListModel; 
import javax.swing.JFrame; 
import javax.swing.JList; 
import javax.swing.JProgressBar; 
import javax.swing.JScrollPane; 
import javax.swing.ListCellRenderer; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class TestProgressListCellRenderer { 

    public static void main(String[] args) { 
     new TestProgressListCellRenderer(); 
    } 

    public TestProgressListCellRenderer() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       final DefaultListModel<Float> model = new DefaultListModel<>(); 
       model.addElement(0f); 

       JList<Float> list = new JList<>(model); 
       list.setCellRenderer(new ProgressListCellRenderer()); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new JScrollPane(list)); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 

       Timer timer = new Timer(125, new ActionListener() { 
        @Override 
        public void actionPerformed(ActionEvent e) { 
         float value = model.getElementAt(0); 
         value += 0.01; 
         if (value >= 1f) { 
          value = 1f; 
          ((Timer)e.getSource()).stop(); 
         } 
         model.setElementAt(value, 0); 
        } 
       }); 
       timer.setRepeats(true); 
       timer.setCoalesce(true); 
       timer.start(); 

      } 
     }); 
    } 

    public class ProgressListCellRenderer extends JProgressBar implements ListCellRenderer<Float> { 

     @Override 
     public Component getListCellRendererComponent(JList<? extends Float> list, Float value, int index, boolean isSelected, boolean cellHasFocus) { 
      setValue(Math.round(value * 100)); 
      return this; 
     }    
    }   
} 

Đây là một ví dụ đơn giản và tôi đã cố gắng sử dụng setIndeterminate, nhưng tôi không thể làm cho nó cập nhật (rất khó chịu), nhưng điều này có thể gây ra một số ý tưởng

+0

Vì vậy, có lẽ nó tốt hơn để làm việc với một JPanel không có JList, ListModel và CellRenderer và phát triển chỉ có hành vi ... –

+1

Vấn đề với setIndeterminate là ProgressBarUI thực sự sử dụng một bộ đếm thời gian để tăng tốc độ hoạt ảnh. Tuy nhiên, điều này chỉ được thực hiện nếu JProgressBar là "Có thể hiển thị" mà không bao giờ là trường hợp vì toàn bộ cơ chế hiển thị JList. Tôi không chắc chắn rằng nó có thể dễ dàng thực hiện với JList. Tôi tin rằng sẽ dễ sử dụng các thành phần "Sống" hơn (nhưng tôi đang chờ để được chứng minh là sai) –

+0

@TobiasRaphaelDieckmann Tôi muốn "đề xuất" thêm 'JProgressBar' trực tiếp vào' JList', nhưng Kleo sẽ săn tôi xuống và làm những điều khó chịu với tôi ... – MadProgrammer

2
  • +1 cho vấn đề thú vị ,

  • nhưng Renderer trong Swing không được chỉ định để hình ảnh động cho thấy, đây chỉ là tĩnh sơn, ảo ảnh, ảnh chụp,

  • bạn phải động Object này trong mã của bạn, nhưng không dễ dàng công việc cho JProgressBar.setIndeterminate(true); nếu là có thể mà không hacks bẩn,

    1. cần riêng JProgressBar

    2. cần hoạt hình riêng cho ListCellRenderer, và kết quả có thể là cho đến nay so với JProgressBar được đặt trong JPanel ví dụ


  • Tôi nghĩ JList không thể thích hợp JComponents, sử dụng JTable với một cột và/hoặc không có JTableHeader

  • workaround đơn giản để sử dụng JPanel (xếp chồng bởi GridLayout) với JProgressBars cho JProgressBar.setIndeterminate(true);, sau đó đầu ra cho giao diện Swing sẽ rất similair đến JTable (không JTableHeader hoặc JList)

    1. đặt này JPanel để JScrollPane

    2. override getPreferredSize cho JScrollPane, sau đó bạn sẽ mô phỏng JList.setVisibleRowCount đúng

    3. thay đổi JScrollBar.setUnitIncrement cho di chuyển tự nhiên cho JPanel với JComponents và với JList, JTable, JTextArea đặt i n JScrollPane

+0

+1 để cung cấp giải pháp với các thành phần Trực tiếp. –

3

Bạn có thể lái xe hoạt hình với riêng bạn javax.swing.Timer trong một tùy chỉnh ProgressBarUI, thấy here; incrementAnimationIndex() có vẻ đầy hứa hẹn, nhưng tôi chưa thử.

image

Vắng mặt một giải pháp tốt hơn, bạn có thể sử dụng một ProgressIcon trong một DefaultListCellRenderer; cách tiếp cận được minh họa here trong một số JTabbedPane.

image

3

Như đã đề cập, kết xuất đồ họa được không sống thành phần, đó không phải là một phần của hệ thống cấp bậc thành phần. Do đó, hiệu ứng hoạt hình "tự nhiên" (như f.i. chuyển động của thanh tiến trình không xác định) bị mất. Một thủ thuật có thể có tác dụng - nhưng hãy cẩn thận: điều đó phụ thuộc rất nhiều vào LAF! - là để nói dối với hệ thống và báo cáo thanh như là dispayable luôn. Đó là kết hợp với một bộ đếm thời gian giả mạo một giá trị mới mỗi x ms có thể hiển thị các hình ảnh động một lần nữa:

public static class ProgressBarRenderer implements TableCellRenderer { 

    /** The bar. */ 
    private JProgressBar indeterminate = new JProgressBar() { 
     // fake displayable to trigger ui animation 
     @Override 
     public boolean isDisplayable() { 
      return true; 
     }; 
    }; 

    /** The bar. */ 
    private JProgressBar determinate = new JProgressBar() ; 

    public ProgressBarRenderer() { 
     indeterminate.setStringPainted(true); 
     indeterminate.setIndeterminate(true); 
     indeterminate.setString(null); 
    }  

    @Override 
    public Component getTableCellRendererComponent(JTable table, 
      Object value, boolean isSelected, boolean hasFocus, int row, 
      int column) { 
     int pbi = (Integer) value; 
     if (pbi < 0) { 
      return indeterminate; 
     } 
     determinate.setValue(pbi); 
     return determinate; 
    } 
} 

// a timer driving the animation 
Action update = new AbstractAction() { 

    int count; 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     table.setValueAt(-1, 0, AncientSwingTeam.INTEGER_COLUMN); 
    } 

}; 
new Timer(100, update).start();