JProgressBar Динамическое изменение цвета панели

Я использую компонент JProgressBar вместе с настройками пользовательского интерфейса Nimbus по умолчанию. Проблема в том, что когда я хочу вручную изменить цвет каждого индикатора прогресса, я использую BasicProgressBarUI, установив функцию JProgressBar.setUI(). Это создает больше проблем, потому что я хотел бы просто изменить цвет панели, и кажется, что я теряю внешний вид jprogressbar по умолчанию (граница, фоновый цвет исчезает).

Так что я могу установить UIDefaults в Nimbus ProgressBar при инициализации кода. Оно работает.

Но я хочу динамически менять цвет каждого индикатора прогресса.

Есть ли другой способ изменить цвет панели JProgressBar?

public class ProgressGenerator extends JFrame {

    protected int minValue = 0;
    protected int maxValue = 100;
    protected int counter = 0;
    protected JProgressBar progressBar;

    public ProgressGenerator() {
        super("JProgressBar Demo");
        setSize(300, 100);

        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (ClassNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (InstantiationException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IllegalAccessException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (UnsupportedLookAndFeelException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        progressBar = new JProgressBar();
        progressBar.setMinimum(minValue);
        progressBar.setMaximum(maxValue);
        progressBar.setStringPainted(true);

        progressBar.setForeground(Color.GREEN);

        JButton start = new JButton("Start");
        start.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Thread runner = new Thread() {
                    public void run() {
                        counter = minValue;
                        while (counter <= maxValue) {
                            Runnable runme = new Runnable() {
                                public void run() {
                                    progressBar.setValue(counter);
                                }
                            };
                            SwingUtilities.invokeLater(runme);
                            counter++;
                            try {
                                Thread.sleep(100);
                            } catch (Exception ex) {
                            }
                        }
                    }
                };
                runner.start();
            }
        });
        getContentPane().add(progressBar, BorderLayout.CENTER);
        getContentPane().add(start, BorderLayout.WEST);
        WindowListener wndCloser = new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        };
        addWindowListener(wndCloser);
        setVisible(true);
    }

    public static void main(String[] args) {
        new ProgressGenerator();
    }
}

person mbasol    schedule 17.01.2013    source источник
comment
для получения дополнительной помощи скорее опубликуйте SSCCE, короткий, исполняемый, компилируемый, иначе придется искать, Google может вернуть это   -  person mKorbel    schedule 17.01.2013
comment
См. этот аналогичный вопрос/ответ, в котором показано, как использовать UIDefaults и putClientProperty для изменить один JProgressBar цвет   -  person David Kroukamp    schedule 17.01.2013
comment
Текущая проблема: когда я меняю цвет панели с помощью setForeground(Color.GREEN); он изменяет цвет SelectionBackground. И кажется, что setBackgroundColor(Color.RED); команда ничего не делает.   -  person mbasol    schedule 17.01.2013
comment
Как показывает ответ, связанный с @DavidKroukamp, ​​ваш sscce должен включать ваши собственные Painter.   -  person trashgod    schedule 17.01.2013
comment
Я установил пользовательский интерфейс как Nimbus и хотел изменить цвет полосы с помощью progressBar.setForeground(Color.GREEN), но это не работает.   -  person mbasol    schedule 17.01.2013
comment
Я хотел изменить цвет бара с помощью progressBar.setForeground - и я хочу получить деньги, обрезая пальцы :-) Или другими словами: если мы применим неправильный подход, мы не получим ожидаемого результата . Повторяя трэшбог — см. QA, на который уже ссылался @DavidKroukamp.   -  person kleopatra    schedule 17.01.2013
comment
@mbasol, как сказал Клео, это не сработает, хотя я должен спросить, что не так с созданием собственного ProgressBarUI и вызовом метода в экземпляре пользовательского интерфейса progressbars, чтобы изменить там цвет?   -  person David Kroukamp    schedule 17.01.2013
comment
@DavidKroukamp, ​​пользовательский интерфейс - это в основном неправильный подход (и гораздо больше работы, чем вы ожидаете, чтобы сделать это правильно) - рекомендуется только в том случае, если вам нужны функции, которые не предоставляются основным пользовательским интерфейсом. Насколько я понимаю вопрос, здесь решается только проблема с конфигурацией, как указано в другой ветке.   -  person kleopatra    schedule 17.01.2013
comment
@kleopatra +1 Спасибо за эту проверку (до того, как я отправил неверный код в качестве ответа). Я не был уверен, что пользовательский подход UI лучше, но если вы завернете его в свой собственный JProgressBar класс и перенаправление setBackground и setForeground вызова JProgressBar на UI, который меняет цвет... Я думаю, все же UIDefaults лучше?   -  person David Kroukamp    schedule 17.01.2013
comment
@DavidKroukamp не уверен, что полностью понимаю, что вы имели в виду, поэтому не говорите ни о том, ни о другом :-) Nimbus поддерживает скиннинг для каждого класса и экземпляра, так что так и есть - хотя обычно это сложнее, чем ожидалось, Nimbus ... не совсем взрослый.   -  person kleopatra    schedule 17.01.2013


Ответы (2)


+1 к Келопатре за первое место.

Вот пример, который я сделал:

Цвет JProgressBar изначально устанавливается с помощью:

UIDefaults defaults = new UIDefaults();
defaults.put("ProgressBar[Enabled].foregroundPainter", new MyPainter(Color.GREEN));
defaults.put("ProgressBar[Enabled+Finished].foregroundPainter", new MyPainter(Color.GREEN));

progressBar.putClientProperty("Nimbus.Overrides.InheritDefaults", Boolean.TRUE);
progressBar.putClientProperty("Nimbus.Overrides", defaults);

На 50% прогресса цвет изменится на КРАСНЫЙ:

if (progressBar.getValue() == 50) {//change color on 50%
   UIDefaults defaults = new UIDefaults();
   defaults.put("ProgressBar[Enabled].foregroundPainter", new MyPainter(Color.RED));
   defaults.put("ProgressBar[Enabled+Finished].foregroundPainter", new MyPainter(Color.RED));
   progressBar.putClientProperty("Nimbus.Overrides.InheritDefaults", Boolean.TRUE);
   progressBar.putClientProperty("Nimbus.Overrides", defaults);                          
}

Тест.java:

введите здесь описание изображения

введите здесь описание изображения

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;

public class Test {

    public static void createAndShowGUI() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        final JProgressBar progressBar = new JProgressBar();
        progressBar.setStringPainted(true);
        progressBar.setValue(0);
        progressBar.setBorderPainted(false);

        JButton startButton = new JButton("Start");

        startButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                UIDefaults defaults = new UIDefaults();
                defaults.put("ProgressBar[Enabled].foregroundPainter", new MyPainter(Color.GREEN));
                defaults.put("ProgressBar[Enabled+Finished].foregroundPainter", new MyPainter(Color.GREEN));

                progressBar.putClientProperty("Nimbus.Overrides.InheritDefaults", Boolean.TRUE);
                progressBar.putClientProperty("Nimbus.Overrides", defaults);

                SwingWorker worker = new SwingWorker() {
                    int current = 0, lengthOfTask = 100;

                    @Override
                    public Void doInBackground() {
                        while (current <= lengthOfTask && !isCancelled()) {

                            try { // dummy task
                                Thread.sleep(50);
                            } catch (InterruptedException ie) {
                            }

                            setProgress(100 * current / lengthOfTask);
                            current++;
                        }
                        return null;
                    }
                };
                worker.addPropertyChangeListener(new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent pce) {

                        String strPropertyName = pce.getPropertyName();
                        if ("progress".equals(strPropertyName)) {
                            int progress = (Integer) pce.getNewValue();
                            progressBar.setValue(progress);

                            if (progressBar.getValue() == 50) {//change color on 50%
                                UIDefaults defaults = new UIDefaults();
                                defaults.put("ProgressBar[Enabled].foregroundPainter", new MyPainter(Color.RED));
                                defaults.put("ProgressBar[Enabled+Finished].foregroundPainter", new MyPainter(Color.RED));

                                progressBar.putClientProperty("Nimbus.Overrides.InheritDefaults", Boolean.TRUE);
                                progressBar.putClientProperty("Nimbus.Overrides", defaults);
                            }

                        }
                    }
                });
                worker.execute();
            }
        });

        JPanel holder = new JPanel();
        holder.add(progressBar);
        holder.add(startButton);

        frame.add(holder);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }
                createAndShowGUI();
            }
        });
    }
}

class MyPainter implements Painter<JProgressBar> {

    private final Color color;

    public MyPainter(Color c1) {
        this.color = c1;
    }
    @Override
    public void paint(Graphics2D gd, JProgressBar t, int width, int height) {
        gd.setColor(color);
        gd.fillRect(0, 0, width, height);
    }
}
person David Kroukamp    schedule 17.01.2013
comment
+1 за динамическое изменение цвета в зависимости от значения, приятный штрих :-) - person kleopatra; 17.01.2013
comment
@David Kroukamp Означает ли это, что я могу переопределить методы setBackground и setForeground JProgressBar и правильно применить значения по умолчанию для пользовательского интерфейса? - person mbasol; 17.01.2013
comment
@DavidKroukamp У меня есть вопрос, связанный с классом Painter. Полоса в прогрессбаре Я хочу, чтобы она не выходила за границы области. Я попытался изменить g.fillRect(0,0, width, height -4); он меняет низ, однако верх по-прежнему выходит за границу. Любое решение? - person mbasol; 18.01.2013

Nimbus поддерживает скиннинг для каждого компонента, как уже было сказано в другом QA. Применяется к «панели» JProgressBar, что означает настройку экземпляра с помощью пользовательского foregroundPainter, например:

progressBar = new JProgressBar();

UIDefaults defaults = new UIDefaults();
Painter painter = new MyPainter(Color.GREEN);
defaults.put("ProgressBar[Enabled].foregroundPainter", painter);
defaults.put("ProgressBar[Enabled+Finished].foregroundPainter", painter);

progressBar.putClientProperty("Nimbus.Overrides.InheritDefaults", Boolean.TRUE);
progressBar.putClientProperty("Nimbus.Overrides", defaults);

Мимимальный (уродливый) художник будет выглядеть примерно так:

public static class MyPainter extends AbstractRegionPainter {

    private Color fillColor;
    public MyPainter(Color color) {
        // as a slight visual improvement, make the color transparent
        // to at least see the background gradient
        // the default progressBarPainter does it as well (plus a bit more)
        fillColor = new Color(
                color.getRed(), color.getGreen(), color.getBlue(), 156);
    }

    @Override
    protected void doPaint(Graphics2D g, JComponent c, int width,
            int height, Object[] extendedCacheKeys) {
        g.setColor(Color.GREEN);
        g.fillRect(0, 0, width, height);
    }

    @Override
    protected PaintContext getPaintContext() {
        return null;
    }

}

Чтобы сделать его визуально приятным, загляните в ProgressBarPainter: это частный пакет, поэтому вы не можете ничего сделать, кроме как понять, как он достигает своих градиентов/отрисовки пути, и сделать то же самое в пользовательской реализации.

person kleopatra    schedule 17.01.2013
comment
+1 не забудьте ProgressBar[Enabled+Finished].foregroundPainter, иначе он вернется к исходному состоянию при 100% завершении - person David Kroukamp; 17.01.2013