2013-04-17 15 views
5

Ho creato il mio CellRenderer che include alcune stringhe e un JProgressBar in un elemento JList ... Ma JProgressBar e così l'intero elemento JList verrà dipinto una volta e sto cercando un modo per ridisegnare il Elementi ... Ho provato ad avviare un thread, che verrà ridisegnato in modo permanente ... Ma non so cosa devo ridipingere per ottenere il risultato ...CellRenderer Repaint

JList riverniciare ... nessun risultato CellRenderer riverniciare ... nessun risultato JFrame rivernicia ... nessun risultato

Qualcuno capisce il mio problema e conosce una via d'uscita?

Grazie mille!

UPDATE: [Aggiornamento soppresso]

Prossimo aggiornamento:

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/) prima, rispondere secondo;) – MadProgrammer

+0

per una migliore aiuto prima Inserisci un [SSCCE] (http://sscce.org/), breve, eseguibile, compilabile, solo sul numero – mKorbel

+0

Per trasformare 2 file sorgente in un SSCCE, è sufficiente dichiararne uno come "pubblico". Aggiungi il sorgente per la 2a classe, alla fine del sorgente per il primo. –

risposta

0

E 'facile.

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); 
    } 
    }); 
} 

Il codice sopra può essere chiamato da EDT e da un altro thread. Ma dovresti anche leggere come gestire i componenti di Swing e capire i modelli (ListModel, TableModel, ecc.). Per chiedere a un elemento di JList di ridisegnare, è necessario modificarne l'oggetto nel modello.

+0

Questo non cambierà nulla. Inoltre, è un overkill per ricreare l'intero ListModel con lo stesso identico valore. Potresti semplicemente chiamare 'myList.repaint()' per avere lo stesso effetto (che comunque non risolverebbe il problema). –

+0

@Sergiy Medvynskyy no e rispondi a ListCellRenderer, per favore cancella questa risposta – mKorbel

2

I renderer di celle sono timbri statici/di gomma di componenti, non sono componenti "reali" attivi. Sono semplicemente "dipinti" sulla superficie della vista che li usa.

Ciò significa che non è (davvero) possibile ridisegnarli come tali. Puoi incoraggiare la lista ad aggiornare cambiando il valore della riga che vuoi modificare. Ciò farà sì che il modello inneschi un aggiornamento che causerà la ridisposizione dell'elenco.

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; 
     }    
    }   
} 

Questo è un semplice esempio e ho provato ad utilizzare setIndeterminate, ma non ho potuto ottenere per aggiornare (molto fastidioso), ma questo potrebbe innescare alcune idee

+0

Quindi forse è meglio lavorare con JPanel senza JList, ListModel e CellRenderer e sviluppare solo il comportamento ... –

+1

Il problema con setIndeterminate è che ProgressBarUI effettivamente usa un timer per stimolare l'animazione. Tuttavia questo viene fatto solo se JProgressBar è "visualizzabile", il che non è mai il caso a causa dell'intero meccanismo di rendering di JList. Non sono sicuro che possa essere facilmente eseguito con JList. Credo che sarebbe più semplice usare componenti "Live" invece (ma aspetto di essere smentito) –

+0

@TobiasRaphaelDieckmann "suggerisco" di aggiungere "JProgressBar" direttamente a "JList", ma Kleo mi darebbe la caccia giu 'e fai cose cattive per me ... – MadProgrammer

2
  • +1 per questione interessante ,

  • ma Renderer in swing non è designato a mostrare le animazioni, questo è solo statica pittura, illusione, snapshot,

  • si deve animare questo oggetto nel codice, ma non facile lavoro per JProgressBar.setIndeterminate(true); se è possibile senza hack sporco,

    1. richiesto proprio JProgressBar

    2. richiede possesso animazione per ListCellRenderer, e il risultato potrebbe essere finora in confronto con JProgressBar posto in JPanel ad es.


  • Penso JList non poteva essere corretta JComponents, utilizzare JTable con una colonna e/o senza JTableHeader

  • semplice soluzione da usare JPanel (spiegate da GridLayout) con JProgressBars per JProgressBar.setIndeterminate(true);, quindi l'output sulla GUI Swing sarà molto similare al JTable (senza JTableHeader o JList)

    1. PUT JPanel a JScrollPane

    2. esclusione getPreferredSize per JScrollPane Allora ti simulando JList.setVisibleRowCount correttamente

    3. cambiamento JScrollBar.setUnitIncrement per lo scorrimento naturale per JPanel con JComponents e con JList, JTable, JTextArea inserito i n JScrollPane

+0

+1 per fornire la soluzione con componenti Live. –

3

Si può essere in grado di guidare l'animazione con il proprio javax.swing.Timer in un costume ProgressBarUI, visto here; incrementAnimationIndex() sembra promettente, ma non l'ho provato.

image

Assente una soluzione migliore, è possibile utilizzare un ProgressIcon in un DefaultListCellRenderer; l'approccio è illustrato here in un JTabbedPane.

image

3

Come già accennato, renderer non sono in diretta i componenti, che non fa parte della gerarchia dei componenti. Di conseguenza, gli effetti di animazione "naturali" (come ad esempio il movimento della barra di avanzamento indeterminata) vengono persi. Un trucco che potrebbe funzionare - ma attenzione: questo è altamente dipendente dalla LAF! - è mentire al sistema e riferire sempre che la barra è sempre disponibile. Che combinati con un timer fingendo un nuovo valore ogni x ms potrebbe mostrare l'animazione di nuovo:

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();