Domanda

I'm attempting to create a customized JProgressBar that utilizes the JLayer class so that it can be colored differently depending on the situation, a la this solution. The thing is that I want to wrap it up as a JComponent of some sort since it makes it more manageable. I would expose it as a customized JLayer, but that class is sealed, so nothing doing.

I've tried just making it a JComponent, but nothing is drawn on the screen (probably because I have no idea how to make a custom JComponent that contains other components inside of it?). I've tried a JFrame, which works, but the sizing is all wrong, likely because the progress bar is using the layout manager of the JFrame I made instead of the layout manager containing the JFrame. I've tried JProgressBar, which draws, but then I have no way of returning the JLayer and preserving the correct hierarchy without additional method calls after the constructor, which just doesn't seem elegant.

Here's my sample code, based heavily on the code from the question I linked to above:

public class Test {
    public JComponent makeUI() {
        final BoundedRangeModel model = new DefaultBoundedRangeModel();
        model.setValue(20);

        final JPanel p = new JPanel(new GridLayout(4, 1, 12, 12));
        p.setBorder(BorderFactory.createEmptyBorder(24,24,24,24));

        // This does not draw
        final ColorProgressBar pb4 = new ColorProgressBar(model);
        p.add(pb4);

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(p, BorderLayout.NORTH);
        return panel;
    }
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
                createAndShowGUI();
            }
        });
    }
    public static void createAndShowGUI() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch(Exception e) {
            e.printStackTrace();
        }
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(new Test().makeUI());
        f.setSize(320, 240);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class ColorProgressBar extends JComponent {
    private static final long serialVersionUID = -1265489165072929352L;

    private BlockedColorLayerUI colorUI = new BlockedColorLayerUI();
    private JLayer<JProgressBar> layer;
    private JProgressBar bar;
    private PropertyChangeSupport supporter = new PropertyChangeSupport(new WeakReference<ColorProgressBar>(this));

    public ColorProgressBar(BoundedRangeModel model) {
        bar = new JProgressBar(model);
        layer = new JLayer<JProgressBar>(bar, colorUI);
        this.add(layer);
    }

    public Color getColor() {
        if (colorUI == null)
            return null;

        return colorUI.color;
    }

    public void setColor(Color color) {
        Color oldColor = colorUI.color;
        colorUI.color = color;
        supporter.firePropertyChange("color", oldColor, color);
    }

    @Override
    public void paintComponents(Graphics g) {
        layer.paintComponents(g);
    }

    class BlockedColorLayerUI extends LayerUI<JProgressBar> {
        public Color color = null;
        private BufferedImage bi;
        private int prevw = -1;
        private int prevh = -1;
        @Override public void paint(Graphics g, JComponent c) {
            if(color != null) {
                JLayer<?> jlayer = (JLayer<?>)c;
                JProgressBar progress = (JProgressBar)jlayer.getView();
                int w = progress.getSize().width;
                int h = progress.getSize().height;

                if(bi==null || w!=prevw || h!=prevh) {
                    bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
                }
                prevw = w;
                prevh = h;

                Graphics2D g2 = bi.createGraphics();
                super.paint(g2, c);
                g2.dispose();

                Image image = c.createImage(
                        new FilteredImageSource(bi.getSource(),
                                new ColorFilter(color)));
                g.drawImage(image, 0, 0, c);
            } else {
                super.paint(g, c);
            }
        }
    }
    class ColorFilter extends RGBImageFilter {
        Color color;

        public ColorFilter(Color color) {
            this.color = color;
        }

        @Override public int filterRGB(int x, int y, int argb) {
            int r = (int)((argb >> 16) & 0xff);
            int g = (int)((argb >>  8) & 0xff);
            int b = (int)((argb      ) & 0xff);
            return (argb & color.getRGB()) | (g<<16) | (r<<8) | (b);
        }
    }
}

Anyone know where I'm going wrong? Thanks!

EDIT: I've trimmed down the example slightly and modified it to better express my issue. Sorry for the confusion.

È stato utile?

Soluzione

You may need to call super(model); and p.add(pb4.layer);

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.beans.*;
import java.lang.ref.WeakReference;
import javax.swing.*;
import javax.swing.plaf.LayerUI;

public class Test2 {
    public JComponent makeUI() {
        final BoundedRangeModel model = new DefaultBoundedRangeModel();
        final JPanel p = new JPanel(new GridLayout(4, 1, 12, 12));
        p.setBorder(BorderFactory.createEmptyBorder(24,24,24,24));

        final JProgressBar pb1 = new JProgressBar(model);
        pb1.setStringPainted(true);
        p.add(pb1);
        final JProgressBar pb2 = new JProgressBar(model);
        pb2.setStringPainted(true);
        p.add(pb2);

        p.add(new JProgressBar(model));
        final ColorProgressBar pb4 = new ColorProgressBar(model);
        p.add(pb4.layer);

        JPanel box = new JPanel();
        box.add(new JButton(new AbstractAction("+10") {
            private int i = 0;
            @Override public void actionPerformed(ActionEvent e) {
                model.setValue(i = (i>=100) ? 0 : i + 10);
            }
        }));
        //http://msdn.microsoft.com/en-us/library/windows/desktop/aa511486.aspx
        box.add(new JCheckBox(new AbstractAction(
                "<html>Turn the progress bar red<br />"+
                        " when there is a user recoverable condition<br />"+
                " that prevents making further progress.") {
            @Override public void actionPerformed(ActionEvent e) {
                boolean b = ((JCheckBox)e.getSource()).isSelected();
                pb2.setForeground(b? new Color(255,0,0,100) : new Color(255,255,0,100));
                if (b)
                    pb4.setColor(Color.RED);
                else
                    pb4.setColor(Color.YELLOW);
                p.repaint();
            }
        }));

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(p, BorderLayout.NORTH);
        panel.add(box, BorderLayout.SOUTH);
        return panel;
    }
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
                createAndShowGUI();
            }
        });
    }
    public static void createAndShowGUI() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch(Exception e) {
            e.printStackTrace();
        }
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(new Test2().makeUI());
        f.setSize(320, 240);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class ColorProgressBar extends JProgressBar {
    private static final long serialVersionUID = -1265489165072929352L;

    private BlockedColorLayerUI colorUI = new BlockedColorLayerUI();
    public JLayer<JProgressBar> layer;
    private PropertyChangeSupport supporter = new PropertyChangeSupport(new WeakReference<ColorProgressBar>(this));

    public ColorProgressBar(BoundedRangeModel model) {
        super(model);
        layer = new JLayer<JProgressBar>(this, colorUI);
    }

    public Color getColor() {
        if (colorUI == null)
            return null;

        return colorUI.color;
    }

    public void setColor(Color color) {
        Color oldColor = colorUI.color;
        colorUI.color = color;
        supporter.firePropertyChange("color", oldColor, color);
    }

//     @Override
//     public void paintComponents(Graphics g) {
//         layer.paintComponents(g);
//     }

    class BlockedColorLayerUI extends LayerUI<JProgressBar> {
        public Color color = null;
        private BufferedImage bi;
        private int prevw = -1;
        private int prevh = -1;
        @Override public void paint(Graphics g, JComponent c) {
            if(color != null) {
                JLayer<?> jlayer = (JLayer<?>)c;
                JProgressBar progress = (JProgressBar)jlayer.getView();
                int w = progress.getSize().width;
                int h = progress.getSize().height;

                if(bi==null || w!=prevw || h!=prevh) {
                    bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
                }
                prevw = w;
                prevh = h;

                Graphics2D g2 = bi.createGraphics();
                super.paint(g2, c);
                g2.dispose();

                Image image = c.createImage(
                        new FilteredImageSource(bi.getSource(),
                                new ColorFilter(color)));
                g.drawImage(image, 0, 0, c);
            } else {
                super.paint(g, c);
            }
        }
    }
    class ColorFilter extends RGBImageFilter {
        Color color;

        public ColorFilter(Color color) {
            this.color = color;
        }

        @Override public int filterRGB(int x, int y, int argb) {
            int r = (int)((argb >> 16) & 0xff);
            int g = (int)((argb >>  8) & 0xff);
            int b = (int)((argb      ) & 0xff);
            return (argb & color.getRGB()) | (g<<16) | (r<<8) | (b);
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top