JTabbedPane: muestra el progreso de la tarea en una pestaña

Tengo una aplicación Swing Java simple que realiza búsquedas y los resultados se muestran en una nueva pestaña. Mientras se ejecuta la búsqueda, quiero mostrar un ícono de progreso o animación en el título de la pestaña. Intenté agregar un ícono gif, pero no se anima. ¿Hay alguna razón por la cual esto no funciona?

El tutorial de Swing sobre barras de progreso (y mostrando el progreso en general) es un muy buen lugar para comenzar. Le muestra cómo realizar operaciones de larga duración en un hilo de trabajo mediante el uso de un SwingWorker , y la actualización de su interfaz de usuario en ciertos intervalos para mostrar el progreso de la operación de larga duración para el usuario. Hay otro tutorial disponible para obtener más información sobre el SwingWorker y concurrencia en Swing.

Y como siempre, este sitio está lleno de ejemplos. Por ejemplo, una respuesta mía anterior usa la clase SwingWorker para mostrar el progreso a un usuario

Editar

Como me perdí el título de la pestaña de su pregunta. Puede crear un ‘icono de progreso’ y configurarlo en la pestaña. El SwingWorker se puede usar para actualizar el ícono.

Un ejemplo de tal icono es ejemplo, icono de progreso , que es básicamente una imagen que rota cada vez que se realiza algún progreso. El tutorial de tabs le muestra cómo agregar icons a sus tabs (o incluso usar componentes personalizados)

Edit2

Como parece que mi Mac en combinación con JDK1.7 hace que sea mucho más fácil mostrar un gif animado y luego en otros sistemas, también creé un pequeño SSCCE, bastante similar al de Andrew pero con un icono giratorio que no se parece a él ha sido creado por, y cito, ‘chimpancé demente’. El código del icono giratorio proviene de este sitio (utilicé una versión reducida y agregué el temporizador). Lo único que no me agrada es el hecho de que necesito pasar el panel con tabs al icono giratorio para que se dispare. La posible solución es sacar el temporizador fuera de la clase RotatingIcon , pero bueno, es solo un SSCCE. Las imágenes no están incluidas, pero se encontraron con Google.

 import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTabbedPane; import javax.swing.Timer; import java.awt.Component; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; public class ProgressTabbedPane { public static void main( String[] args ) { EventQueue.invokeLater( new Runnable() { @Override public void run() { JFrame frame = new JFrame( "RotatingIcon" ); JTabbedPane tabbedPane = new JTabbedPane( ); tabbedPane.addTab( "Searching", new RotatingIcon( new ImageIcon( "resources/images/progress-indeterminate.png" ), tabbedPane ), new JLabel( new ImageIcon( "resources/images/rotatingIcon.gif" ) ) ); frame.getContentPane().add( tabbedPane ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.pack(); frame.setVisible( true ); } } ); } private static class RotatingIcon implements Icon{ private final Icon delegateIcon; private double angleInDegrees = 90; private final Timer rotatingTimer; private RotatingIcon( Icon icon, final JComponent component ) { delegateIcon = icon; rotatingTimer = new Timer( 100, new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { angleInDegrees = angleInDegrees + 10; if ( angleInDegrees == 360 ){ angleInDegrees = 0; } component.repaint(); } } ); rotatingTimer.setRepeats( false ); rotatingTimer.start(); } @Override public void paintIcon( Component c, Graphics g, int x, int y ) { rotatingTimer.stop(); Graphics2D g2 = (Graphics2D )g.create(); int cWidth = delegateIcon.getIconWidth() / 2; int cHeight = delegateIcon.getIconHeight() / 2; Rectangle r = new Rectangle(x, y, delegateIcon.getIconWidth(), delegateIcon.getIconHeight()); g2.setClip(r); AffineTransform original = g2.getTransform(); AffineTransform at = new AffineTransform(); at.concatenate(original); at.rotate(Math.toRadians( angleInDegrees ), x + cWidth, y + cHeight); g2.setTransform(at); delegateIcon.paintIcon(c, g2, x, y); g2.setTransform(original); rotatingTimer.start(); } @Override public int getIconWidth() { return delegateIcon.getIconWidth(); } @Override public int getIconHeight() { return delegateIcon.getIconHeight(); } } } 

Una captura de pantalla para referencia. Una pena que los icons no roten en la captura de pantalla. Captura de pantalla de SSCCE

Imagen animada como icono de pestaña

 import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; public class ImageOnTab { ImageOnTab() { final BufferedImage image = new BufferedImage( 32,32,BufferedImage.TYPE_INT_RGB); final JTabbedPane pane = new JTabbedPane(); ImageIcon icon = new ImageIcon(image); pane.addTab( "Progress", icon, new JTree() ); ActionListener listener = new ActionListener() { int x = 0; int step = 1; public void actionPerformed(ActionEvent ae) { Graphics g = image.createGraphics(); x+=step; if (step>0) { if (x>32) { step=-step; } } else if (x<0) { step=-step; } g.setColor(Color.ORANGE); g.fillRect(0,0,32,32); g.setColor(Color.RED); g.fillRect(0,0,x,32); g.dispose(); pane.repaint(); } }; Timer timer = new Timer(100,listener); timer.start(); JOptionPane.showMessageDialog(null, pane); } public static void main(String[] args) throws Exception { //Create the GUI on the event dispatching thread SwingUtilities.invokeLater(new Runnable(){ @Override public void run() { new ImageOnTab(); } }); } } 

@Andrew Thompson

 It would be great if the J2SE supported animated GIFs 'out of the box' in more situations. I tried that animated GIF (nice image, BTW) as a tab icon, and no, it remains static. 

No quiero leer todo …, sino juntar el código por suyas y la majestad de @ranshgod

1) use Htlm (no soy bueno en HTML simple)

2) use GlassPane con JLabel#(setOpaque(true))

3) use JLayer ( JXLayer es mejor, porque Sn’Oracle elimina métodos importantes == mi vista)

4) tienes que forzar ….. para Swing JComponents por @aterai

5) Rob’s Animated Icon algunas veces menciona soporte por Rob para JTabbedPane

código

 import java.awt.*; import java.awt.event.*; import java.net.MalformedURLException; import java.net.URL; import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.*; //https://stackoverflow.com/questions/3483485/java-jprogressbar-or-equivalent-in-a-jtabbedpane-tab-title/3484251#3484251 public class JTabbedTest { private JFrame f = new JFrame(); private JTabbedPane jtp = new JTabbedPane(); private URL url = null; public JTabbedTest() { try { url = new URL("http://pscode.org/media/starzoom-thumb.gif"); } catch (MalformedURLException ex) { Logger.getLogger(JTabbedTest.class.getName()).log(Level.SEVERE, null, ex); } ImageIcon ii = new ImageIcon(url); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jtp.setPreferredSize(new Dimension(400, 200)); createTab("Reds", Color.RED); createTab("Greens", Color.GREEN); createTab("Blues", Color.BLUE); f.add(jtp, BorderLayout.CENTER); jtp.setTitleAt(2, ""); // change foreground Color for disabled tab /*jtp.setTitleAt(2, "" + jtp.getTitleAt(2) + "");*/ Rectangle tabBounds = jtp.getBoundsAt(0); Container glassPane = (Container) f.getRootPane().getGlassPane(); glassPane.setVisible(true); glassPane.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.weightx = 1.0; gbc.weighty = 1.0; gbc.fill = GridBagConstraints.NONE; gbc.insets = new Insets(tabBounds.y + 23, 0, 0, 5); gbc.anchor = GridBagConstraints.NORTHEAST; JButton button = new JButton("My Button Position", ii); button.setPreferredSize(new Dimension(button.getPreferredSize().width, (int) tabBounds.getHeight() - 2)); glassPane.add(button, gbc); f.pack(); f.setVisible(true); } private void createTab(String name, Color color) { ProgressIcon icon = new ProgressIcon(color); jtp.addTab(name, icon, new ColorPanel(jtp, icon)); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { JTabbedTest jTabbedTest = new JTabbedTest(); } }); } private static class ColorPanel extends JPanel implements ActionListener { private static final Random rnd = new Random(); private static final long serialVersionUID = 1L; private final Timer timer = new Timer(1000, this); private final JLabel label = new JLabel("Stackoverflow!"); private final JTabbedPane parent; private final ProgressIcon icon; private final int mask; private int count; public ColorPanel(JTabbedPane parent, ProgressIcon icon) { super(true); this.parent = parent; this.icon = icon; this.mask = icon.color.getRGB(); this.setBackground(icon.color); label.setForeground(icon.color); this.add(label); timer.start(); } @Override public void actionPerformed(ActionEvent e) { this.setBackground(new Color(rnd.nextInt() & mask)); this.icon.update(count += rnd.nextInt(8)); this.parent.repaint(); } } private static class ProgressIcon implements Icon { private static final int H = 16; private static final int W = 3 * H; private Color color; private int w; public ProgressIcon(Color color) { this.color = color; } public void update(int i) { w = i % W; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { g.setColor(color); g.fillRect(x, y, w, H); } @Override public int getIconWidth() { return W; } @Override public int getIconHeight() { return H; } } }