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); той променя цвета на фона на избора. И изглежда, че 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 - и искам да получа пари чрез щракване на пръсти :-) Или с други думи: ако приложим неправилния подход, няма да получим очаквания резултат . Повтаряне на trashgod - вижте QA, вече посочен от @DavidKroukamp   -  person kleopatra    schedule 17.01.2013
comment
@mbasol, тъй като Kleo каза, че няма да работи, въпреки че трябва да попитам какво не е наред в това да създадете свой собствен ProgressBarUI и да извикате метода на потребителския интерфейс на лентите на прогреса, за да промените цвета там?   -  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);                          
}

Test.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