Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JTabbedPane: show task progress in a tab

I have a simple Swing Java application that performs searches, and the results are shown in a new tab. While the search is running, I want to show a progress icon or animation in the title of the tab. I tried adding a gif icon, but it doesn't animate. Is there a reason why this isn't working?

like image 969
Paco Avatar asked Nov 29 '22 17:11

Paco


2 Answers

The Swing tutorial about progress bars (and showing progress in general) is a very good place to start. It shows you how to perform long-lasting operations on a worker thread by using a SwingWorker, and updating your UI at certain intervals to show progress of the long-lasting operation to the user. There is another tutorial available for more information on the SwingWorker and concurrency in Swing

And as always, this site is filled with examples. For example a previous answer of mine uses the SwingWorker class to show progress to a user

Edit

As I missed the title of tab part of your question. You could create a 'progress icon' and set that on the tab. The SwingWorker can then be used to update the icon.

An example of such an icon is example progress icon, which is basically an image you rotate each time some progress is made. The tabbed pane tutorial shows you how to add icons to your tabs (or even use custom components)

Edit2

As it seems my Mac in combination with JDK1.7 makes it much easier to show an animated gif then on other systems, I created a small SSCCE as well, quite similar to that of Andrew but with a rotating icon which does not look like it has been created by, and I quote, 'demented Chimpanzee'. The rotating icon code comes from this site (I used a stripped down version and added the timer). Only thing I am not too happy about is the fact I need to pass my tabbed pane to the rotating icon to trigger. Possible solution is to pull the timer outside the RotatingIcon class, but hey, it's only an SSCCE . Images are not included but were found with 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();
    }
  } 
}

A screenshot for reference. A shame the icons do not rotate in the screenshot. SSCCE screenshot

like image 79
Robin Avatar answered Dec 24 '22 07:12

Robin


Animated image as tab icon

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();
            }
        });
    }
}
like image 30
Andrew Thompson Avatar answered Dec 24 '22 08:12

Andrew Thompson