Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CellRenderer Item repaint

I created my own CellRenderer which include some several strings and a JProgressBar in a JList Item ... But the JProgressBar and so the whole JList Item will painted one time and I'm looking for a way to repaint the Items ... I tried to start a thread, that will permanently repaint ... But I don't know what I have to repaint to get the result ...

JList repaint ... no result CellRenderer repaint ... no result JFrame repaint ... no result

Does anyone understand my Problem and know a way out?

Thank you very much!

UPDATE: [Update deleted]

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



}

}
like image 618
Tobias Raphael Dieckmann Avatar asked Apr 17 '13 06:04

Tobias Raphael Dieckmann


3 Answers

As already mentioned, renderers are not live components, that is not part of component hierarchy. Consequently, "natural" animation effects (like f.i. the movement of the indeterminate progressbar) are lost. A trick that might work - but beware: that's highly LAF dependent! - is to lie to the system and report the bar as being dispayable always. That combined with a timer faking a new value every x ms might show the animation again:

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();
like image 62
kleopatra Avatar answered Sep 29 '22 02:09

kleopatra


Cell renderers are static/rubber stamps of components, they are not "real", active components. They are simply "painted" onto the surface of the view that uses them.

This means that it's not (really) possible to repaint them as such. You can encourage the list to update by changing the value of the row you want to change. This will cause the model to trigger an update that will cause the list to repaint.

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

This is a simple example and I tried using setIndeterminate, but I couldn't get it to update (very annoying), but this might trigger some ideas

like image 33
MadProgrammer Avatar answered Sep 29 '22 02:09

MadProgrammer


  • +1 for interesting issue,

  • but Renderer in Swing isn't designated to showing animations, this is only static painting, illusion, snapshot,

  • you have to animate this Object in your code, but not easy job for JProgressBar.setIndeterminate(true); if is possible without dirty hacks,

    1. required own JProgressBar

    2. required own animation for ListCellRenderer, and the result could be so far in compare with JProgressBar placed in JPanel e.g.


  • I think JList couldn't be proper JComponents, use JTable with one Column and /or without JTableHeader

  • simple workaround to use JPanel (layed by GridLayout) with JProgressBars for JProgressBar.setIndeterminate(true);, then output to the Swing GUI will be very similair to the JTable (without JTableHeader or JList)

    1. put this JPanel to JScrollPane

    2. override getPreferredSize for JScrollPane, then you'll simulating JList.setVisibleRowCount properly

    3. change JScrollBar.setUnitIncrement for natural scrolling for JPanel with JComponents and with JList, JTable, JTextArea placed in JScrollPane

like image 21
mKorbel Avatar answered Sep 29 '22 03:09

mKorbel