JTabbedPane: показва напредъка на задачата в раздел

Имам просто приложение Swing Java, което извършва търсения и резултатите се показват в нов раздел. Докато се изпълнява търсенето, искам да покажа икона за прогрес или анимация в заглавието на раздела. Опитах се да добавя gif икона, но не се анимира. Има ли причина това да не работи?


person Paco    schedule 07.04.2012    source източник
comment
„Пътят на най-малката изненада“ за това би бил или JProgressBar сред компонентите на раздела, който представлява интерес, или обща лента за напредък (извън панела с раздели), която показва напредъка на който и да е избран раздел. Някакви предложения? tnx 1) Не правете това. 2) Изписвайте правилно думи като „благодаря“ или още по-добре ги изпуснете - те са шум.   -  person Andrew Thompson    schedule 07.04.2012
comment
Благодаря, но искам да реализирам нещо като разделите на firefox (с икона, показваща напредъка на зареждането).   -  person Paco    schedule 07.04.2012
comment
Е, да, но „имаме технологията“, така че вижте отговора ми. Остава като упражнение за читателя да избере цветове (и стил на изображение и т.н.), които не изглеждат като измислени от луд шимпанзе.   -  person Andrew Thompson    schedule 07.04.2012


Отговори (3)


Урокът на Swing за лентите за напредък (и показване на напредъка като цяло ) е много добро място за начало. Той ви показва как да извършвате дълготрайни операции върху работна нишка, като използвате SwingWorker и актуализирате потребителския си интерфейс на определени интервали, за да покажете напредъка на дълготрайната операция на потребителя. Има друг наличен урок за повече информация относно SwingWorker и паралелността в Swing

И както винаги, този сайт е пълен с примери. Например предишен мой отговор използва класа SwingWorker, за да покаже напредъка на потребител

Редактиране

Тъй като пропуснах частта от заглавието на раздел на вашия въпрос. Можете да създадете „икона за напредък“ и да я зададете в раздела. След това SwingWorker може да се използва за актуализиране на иконата.

Пример за такава икона е примерна икона за напредък, което е основно изображение, което завъртате всеки път, когато се постигне някакъв напредък . урокът за панел с раздели ви показва как да добавяте икони към вашия раздели (или дори използвайте персонализирани компоненти)

Редактиране2

Тъй като изглежда, че моят Mac в комбинация с JDK1.7 прави много по-лесно показването на анимиран gif отколкото на други системи, създадох и малък SSCCE, доста подобен на този на Andrew, но с въртяща се икона, която не изглежда така е създадена от, цитирам, „безумно шимпанзе“. Кодът на въртящата се икона идва от този сайт (използвах оголен надолу версия и добави таймера). Единственото нещо, от което не съм много доволен, е фактът, че трябва да предам панела с раздели към въртящата се икона, за да се задейства. Възможно решение е да изтеглите таймера извън класа 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();
    }
  } 
}

Екранна снимка за справка. Жалко, че иконите не се въртят на екранната снимка. SSCCE екранна снимка

person Robin    schedule 07.04.2012
comment
Всичко това е добре, но OP иска да показва напредъка в самия раздел. Не виждам отговора ви да засяга тази част. - person Hovercraft Full Of Eels; 07.04.2012
comment
О, не видях заглавието на раздела частта, само че той използва панел с раздели. Тогава това наистина не е отговор. Ще видя дали мога да добавя нещо полезно към този отговор или да го изтрия в противен случай - person Robin; 07.04.2012
comment
Благодаря за отговора, но в моя случай не мога да използвам този метод: програмата не може да получи достъп до напредъка на търсенето (извършвано от сървъра). Така че трябва да покажа икона за напредък и да я скрия само когато получа отговор от сървъра - person Paco; 07.04.2012
comment
@Robin Би било чудесно, ако J2SE поддържаше анимирани GIF файлове „извън кутията“ в повече ситуации. Опитах този анимиран GIF (хубаво изображение, между другото) като икона на раздел и не, той остава статичен. - person Andrew Thompson; 07.04.2012
comment
@AndrewThompson Съгласен. Но повторното създаване на анимацията с тази икона е толкова просто, колкото използването на Swing таймер и завъртането на иконата във всяка стъпка (вижте тази връзка за завъртане на икона) - person Robin; 07.04.2012
comment
@Robin Вижте отговора ми за анимационната му страна. ;) - person Andrew Thompson; 07.04.2012
comment
@AndrewThompson на моя Mac (JDK1.7) изображението се завърта добре без никакви допълнителни стъпки. И в раздела, и в JLabel като съдържание. Ще опитам какво трябва да направя със статична икона - person Robin; 07.04.2012
comment
@Робин, ще добавя това към моя списък със „странни малки проблеми с x-plat“. Друг, който ме забеляза, беше за звука на Java Clip. Разработвах на Ubuntu по това време и използваната JRE реализация позволяваше клипове с произволен размер (поне до OutOfMemoryError). Но при JRE на Sun под Windows, 1 секунда аудио с качество на CD беше всичко, което можеше да зареди. :( Между другото - тествах тази анимация на изображение току-що на Win 7 с помощта на Java 1.6.0_29. - person Andrew Thompson; 07.04.2012
comment
@AndrewThompson Добавих малко код. JLabel използва иконата, която публикувах тук и която просто се върти сама. PNG е статичен и използва таймер за завъртане. +1 за вашия коментар за шимпанзето между другото - person Robin; 07.04.2012
comment
Ами глупости. Иска ми се да не бях гласувал за преди. Тогава бих могъл да направя това сега. ;) Добър пример и както обикновено с вашия Mac. потребители - отлична екранна снимка. Вероятно е автоматично, но ми харесва начина, по който се улавя сянката на прозореца. :) - person Andrew Thompson; 07.04.2012
comment
@AndrewThompson Наистина се случва автоматично, не мога да си припиша заслугата за това. И може би е добър момент да спра да коментирам, получавам предложение да преместя всичко това в чат - person Robin; 07.04.2012

Анимирано изображение като икона на раздел

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();
            }
        });
    }
}
person Andrew Thompson    schedule 07.04.2012
comment
Отлично! Вижте също този свързан пример. - person trashgod; 07.04.2012
comment
@trashgod Jeesh.. Трябваше да знам а) вече имаш пример за това б) с един от онези прекрасни Mac. екранни снимки. в) че вече бях гласувал за, и г) това беше по-добро от всичко, което можех да хакна за няколко „безумни“ момента! (Освен че все още харесвам факта, че подходът ми не трябва да отменя нищо. Не съм сигурен дали това представлява „добър дизайн“ в този случай или просто „бичуване на мъртъв кон“.) - person Andrew Thompson; 07.04.2012
comment
Виждам двете като допълващи се във всички точки; цитиран. - person trashgod; 07.04.2012

@Андрю Томпсън

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's величество

1) използвайте Htlm (не съм добър в обикновения Html)

2) използвайте GlassPane с JLabel#(setOpaque(true))

3) използвайте JLayer (JXLayer е по-добре, тъй като Sn'Oracle премахва важни методи == моето мнение)

4) трябва да форсирате ..... за Swing JComponents от @aterai

5) Анимираната икона на Роб няколко пъти спомена подкрепа от Роб за 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;
        }
    }
}
person mKorbel    schedule 07.04.2012
comment
Благодаря, че инсталирахте отново този отговор. +1 :) - person Andrew Thompson; 09.04.2012