【问题标题】:JTabbedPane: show task progress in a tabJTabbedPane:在选项卡中显示任务进度
【发布时间】:2012-04-20 18:30:21
【问题描述】:

我有一个执行搜索的简单 Swing Java 应用程序,结果显示在新选项卡中。在搜索运行时,我想在选项卡标题中显示进度图标或动画。我尝试添加一个 gif 图标,但它没有动画。这不起作用有什么原因吗?

【问题讨论】:

  • 对此的“最不意外的路径”可以是感兴趣的选项卡组件中的JProgressBar,或者是显示任何进度的通用进度条(在选项卡式窗格之外)选项卡被选中。 “有什么建议吗?tnx” 1) 不要那样做。 2)正确拼写“谢谢”之类的词,或者更好的是,将它们排除在外——它们是噪音。
  • 谢谢,但我想实现类似firefox的标签(带有显示加载进度的图标)。
  • 好吧,很糟糕,但是'我们有技术'所以看看我的回答。留给读者选择看起来不像是发狂的黑猩猩想出来的颜色(和图像风格等)作为练习。

标签: java swing jtabbedpane jprogressbar


【解决方案1】:

Swing tutorial about progress bars(并显示总体进展)是一个非常好的起点。它向您展示了如何使用SwingWorker 在工作线程上执行持久操作,并以特定间隔更新您的 UI 以向用户显示持久操作的进度。有关SwingWorker and concurrency in Swing

的更多信息,还有另一个教程可用

和往常一样,这个网站充满了例子。例如a previous answer of mine 使用SwingWorker 类向用户显示进度

编辑

因为我错过了您问题的 标签标题 部分。您可以创建一个“进度图标”并将其设置在选项卡上。然后可以使用SwingWorker 更新图标。

是此类图标的一个示例,它基本上是您每次取得一些进展时都会旋转的图像。 tabbed pane tutorial 向您展示了如何将图标添加到选项卡(甚至使用自定义组件)

编辑2

我的 Mac 与 JDK1.7 的结合似乎比在其他系统上更容易显示动画 gif,我也创建了一个小型 SSCCE,与 Andrew 的非常相似,但带有一个旋转图标看起来它是由“疯狂的黑猩猩”创造的,我引用了“疯狂的黑猩猩”。旋转图标代码来自this site(我使用了精简版并添加了计时器)。唯一让我不太高兴的是我需要将选项卡式窗格传递给旋转图标才能触发。可能的解决方案是将计时器拉到 RotatingIcon 类之外,但是嘿,它只是一个 SSCCE 。图片不包括在内,但通过 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();
    }
  } 
}

截图供参考。遗憾的是,屏幕截图中的图标没有旋转。

【讨论】:

  • 这一切都很好,但是 OP 希望在 标签本身 中显示进度。我没有看到您的回答解决了这部分问题。
  • 哦,我没有看到 标签的标题 部分,只是他使用的是标签窗格。那么这确实不是一个答案。看看我是否可以在这个回复中添加一些有用的东西,或者删除它
  • 感谢您的回答,但在我的情况下,我无法使用此方法:程序无法访问搜索进度(由服务器执行)。所以我必须显示一个进度图标并仅在收到来自服务器的响应时隐藏它
  • @Robin 如果 J2SE 在更多情况下支持“开箱即用”的动画 GIF,那就太好了。我尝试将动画 GIF(漂亮的图像,顺便说一句)作为选项卡图标,不,它仍然是静态的。
  • @AndrewThompson 在我的 Mac (JDK1.7) 上,图像可以很好地旋转,无需任何额外步骤。两者都在选项卡中作为 JLabel 中的内容。将尝试我对静态图标的处理
【解决方案2】:

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

【讨论】:

  • 太棒了!另请参阅此相关example
  • @trashgod Jeesh .. 我应该知道 a) 你已经有一个例子 b) 与那些可爱的 Mac 之一。屏幕截图。 c)我已经投了赞成票,d)这比我在几个“疯狂”的时刻可以破解的任何东西都要好! (除了我仍然喜欢我的方法不需要覆盖任何东西的事实。不确定在这种情况下这是否构成“好的设计”,或者仅仅是“鞭打一匹死马”。)
  • 我认为这两者在所有方面都是互补的;引用。
【解决方案3】:

@安德鲁汤普森

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. 

我不想读完整个......,而是把你和@trashgod 陛下的代码放在一起

1)使用Htlm(我不擅长纯Html)

2) 将GlassPaneJLabel#(setOpaque(true)) 一起使用

3) 使用JLayerJXLayer 更好,因为 Sn'Oracle 删除重要方法 == 我的观点)

4) 你必须force ..... for Swing JComponents by @aterai

5) Rob's Animated Icon 几次提到 Rob 对 JTabbedPane 的支持

代码

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, "<html><img src=" + ii + " width=20 height=20></img></html>");

        // change foreground Color for disabled tab        
        /*jtp.setTitleAt(2, "<html><font color=" + (jtp.isEnabledAt(2) ? "black" : "red") + ">"
                + jtp.getTitleAt(2) + "</font></html>");*/

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

【讨论】:

  • 感谢您重新设置此答案。 +1 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 1970-01-01
  • 2011-07-21
相关资源
最近更新 更多