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;
}
}
}
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();
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
+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,
required own JProgressBar
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
)
put this JPanel
to JScrollPane
override getPreferredSize
for JScrollPane
, then you'll simulating JList.setVisibleRowCount properly
change JScrollBar.setUnitIncrement for natural scrolling for JPanel
with JComponents and with JList
, JTable
, JTextArea
placed in JScrollPane
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With