I would like to use the JXBusyLabel
in a cell to notify the user that an event is currently taking place for the row where the JXBusyLabel
is.
For example, double clicking a row to open it would trigger the anymation of the JXBusyLabel
.
Does this make sense?
In case you are wondering what a JXBusyLabel
is, please look here.
Thanks!
[EDIT] Solution based on @kleopatra answer:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.table.DefaultTableModel;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.decorator.AbstractHighlighter;
import org.jdesktop.swingx.decorator.HighlightPredicate;
import org.jdesktop.swingx.decorator.PainterHighlighter;
import org.jdesktop.swingx.painter.BusyPainter;
public class TableBusyLabelTest {
private JFrame frame;
private JXTable table;
private JButton button;
private BusyPainter busyPainter;
private AbstractHighlighter highlighter;
private Timer timer;
private boolean on = false;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
TableBusyLabelTest window = new TableBusyLabelTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public TableBusyLabelTest() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
busyPainter = new BusyPainter(15);
timer = new Timer(100, getTimerActionListener());
highlighter = new PainterHighlighter(HighlightPredicate.NEVER,
busyPainter);
table = new JXTable();
table.setModel(getTableExampleModel());
// Tell which column will use the highlighter
table.getColumnExt(0).addHighlighter(highlighter);
button = new JButton("Start / Stop busy thing");
button.addActionListener(getButtonActionListener());
frame.getContentPane().add(table, BorderLayout.CENTER);
frame.getContentPane().add(button, BorderLayout.SOUTH);
}
private DefaultTableModel getTableExampleModel() {
return new DefaultTableModel(new Object[][] { { null, "Test1" },
{ null, "Test2" }, }, new String[] { "busy", "Name" });
}
private ActionListener getTimerActionListener() {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int frame = busyPainter.getFrame();
frame = (frame + 1) % busyPainter.getPoints();
busyPainter.setFrame(frame);
}
};
}
private ActionListener getButtonActionListener() {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (on) {
on = false;
} else {
on = true;
}
// on a change that should toggle the busy-ness on/off
if (on) {
highlighter
.setHighlightPredicate(HighlightPredicate.ALWAYS);
timer.start();
} else {
highlighter.setHighlightPredicate(HighlightPredicate.NEVER);
timer.stop();
}
}
};
}
}
Depending on your exact use case, you wouldn't want to use the JXBusyLabel as the rendering component (you wouldn't get the anitmation, as it's a renderer), all you need is a PainterHighlighter configured with a BusyPainter whose frame property is controlled by a timer. Whether or not the painter is visible should be bound to some property of your data which triggers the on/off of the highlighters HighlightPredicate.
For an example, please see PainterVisualCheck interactiveAnimatedBusyPainterHighlight in the swingx test hierarchy, package renderer. Something like:
BusyPainter painter = new BusyPainter();
ActionListener l = new ActionListener() {
public void actionPerformed(ActionEvent e) {
int frame = busyPainter.getFrame();
frame = (frame+1)%busyPainter.getPoints();
busyPainter.setFrame(frame);
}
};
Timer timer = new Timer(delay, l);
AbstractHighlighter hl = new PainterHighlighter(HighlightPredicate.NEVER, painter);
table.getColumnExt().addHighlighter(hl);
// on a change that should toggle the busy-ness on/off
if (on) {
hl.setHighlightPredicate(HighlightPredicate.ALWAYS);
timer.start();
} else {
hl.setHighlightPredicate(HighlightPredicate.NEVER);
timer.stop();
}
Edit (answering the extended question):
to activate the busy-highlighter only for a particular condition, implement a custom HighlightPredicate and set that instead of the ALWAYS. F.i. a specific row in the column:
HighlightPredicate predicate = new HighlightPredicate() {
@Override
public boolean isHighlighted(Component renderer,
ComponentAdapter adapter) {
return
adapter.convertRowIndexToModel(adapter.row) == mySpecialRow;
}
};