How to know what r,g,b values to use for get other

2019-09-22 07:30发布

问题:

I want to know how to manage the rgb values to change the background colour of a JFrame dynamically, by now i can only change from green to blue and versa vice; this are the colours that i need:

The rgb of these colours can be found here

Here's my sample code of how to change from green to blue dynamically:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class ChangeColor {

    public ChangeColor() {
        JFrame frame = new JFrame();
        frame.add(new ColorPanel());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public class ColorPanel extends JPanel {

        private static final int DELAY = 30;
        private static final int INCREMENT = 15;
        private Color currentColor = Color.BLUE;
        boolean isBlue = true;
        boolean isGreen = false;
        private int r,g,b;

        private Timer timer = null;
        private JButton greenButton = null;
        private JButton blueButton = null;

        public ColorPanel() {
            r = 0; g = 0; b = 255;

            greenButton = createGreenButton();
            blueButton = createBlueButton();

            timer = new Timer(DELAY, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {

                    if (isBlue) {
                        if (b == 0) {
                            stopTimer();
                            enableButtons();
                        } else {
                            blueToGreen();
                            setColor(new Color(r, b, g));
                        }
                    } 

                    if (isGreen) {
                        if (g == 0) {
                            stopTimer();
                            enableButtons();
                        } else {
                            greenToBlue();
                            setColor(new Color(r, b, g));
                        }
                    }

                    repaint();
                }
            });

            add(blueButton);
            add(greenButton);
        }

        public JButton createBlueButton() {
            JButton button = new JButton("BLUE");
            button.addActionListener(new ActionListener(){
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (currentColor != new Color(0, 255, 0)) {
                        System.out.println("turn blue");
                        isBlue = true;
                        isGreen = false;
                        diableButtons();
                        startTimer();   
                    }
                }
            });
            return button;
        }

        public void diableButtons() {
            blueButton.setEnabled(false);
            greenButton.setEnabled(false);
        }

        public void enableButtons() {
            blueButton.setEnabled(true);
            greenButton.setEnabled(true);
        }

        public JButton createGreenButton() {
            JButton button = new JButton("GREEN");
            button.addActionListener(new ActionListener(){
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (currentColor != new Color(0, 0, 255)) {
                        System.out.println("turn green");
                        isGreen = true;
                        isBlue = false;
                        diableButtons();
                        startTimer();

                    }
                }
            });
            return button;
        }

        private void blueToGreen() {
            b -= INCREMENT;
            g += INCREMENT;
        }

        private void greenToBlue() {
            g -= INCREMENT;
            b += INCREMENT;
        }



        public void setColor(Color color) {
            this.currentColor = color;
        }

        public void startTimer() {
            timer.start();
        }

        public void stopTimer() {
            timer.stop();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(currentColor);
            g.fillRect(0, 0, getWidth(), getHeight());
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                new ChangeColor();
            }
        });

    }
}

The code has some bugs, and it's not the most robust code, so that if you can improve it, i'll be thanked

Here's the output of the sample code:

回答1:

Your current approach is indeed not easily generalizable. The hard-coded parts of the buttons for "blue" and "green", and especially the special methods like blueToGreen make it impossible to extend the number of colors with reasonable effort. (You don't want to create methods blueToYellow, blueToRed, blueToTheThirdColorFromThisListForWhichIDontKnowAName ...).

There are many possible ways of generalizing this. You did not say much about the intended structure and responsibilities. But you should at least create a method that can interpolate between two arbitrary colors with a given number of steps. In the code snippet below, this is done in the ´createColorsArrayArgb` method, which creates an array of ARGB colors from an arbitrary sequence of colors (I needed this recently). But you can probably boil it down to 2 colors, if you want to.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class ChangeColor
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new ChangeColor();
            }
        });
    }

    public ChangeColor()
    {
        JFrame frame = new JFrame();

        ColorPanel colorPanel = new ColorPanel(Color.BLUE);
        ColorInterpolator ci = new ColorInterpolator(colorPanel, Color.BLUE);

        colorPanel.addColorButton(createButton("Blue", Color.BLUE, ci));
        colorPanel.addColorButton(createButton("Green", Color.GREEN, ci));
        colorPanel.addColorButton(createButton("Red", Color.RED, ci));
        colorPanel.addColorButton(createButton("Cyan", Color.CYAN, ci));
        colorPanel.addColorButton(createButton("Yellow", Color.YELLOW, ci));
        colorPanel.addColorButton(createButton("Magenta", Color.MAGENTA, ci));

        frame.add(colorPanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static JButton createButton(String name, final Color color, 
        final ColorInterpolator colorInterpolator)
    {
        JButton button = new JButton(name);
        button.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                colorInterpolator.interpolateTo(color);
            }
        });
        return button;
    }


    /**
     * Creates an array with the given number of elements, that contains the
     * ARGB representations of colors that are linearly interpolated between the
     * given colors
     * 
     * @param steps The number of steps (the size of the resulting array)
     * @param colors The colors to interpolate between
     * @return The array with ARGB colors
     */
    static int[] createColorsArrayArgb(int steps, Color... colors)
    {
        int result[] = new int[steps];
        double normalizing = 1.0 / (steps - 1);
        int numSegments = colors.length - 1;
        double segmentSize = 1.0 / (colors.length - 1);
        for (int i = 0; i < steps; i++)
        {
            double relative = i * normalizing;
            int i0 = Math.min(numSegments, (int) (relative * numSegments));
            int i1 = Math.min(numSegments, i0 + 1);
            double local = (relative - i0 * segmentSize) * numSegments;

            Color c0 = colors[i0];
            int r0 = c0.getRed();
            int g0 = c0.getGreen();
            int b0 = c0.getBlue();

            Color c1 = colors[i1];
            int r1 = c1.getRed();
            int g1 = c1.getGreen();
            int b1 = c1.getBlue();

            int dr = r1 - r0;
            int dg = g1 - g0;
            int db = b1 - b0;

            int r = (int) (r0 + local * dr);
            int g = (int) (g0 + local * dg);
            int b = (int) (b0 + local * db);
            int argb = (0xFF << 24) | (r << 16) | (g << 8) | (b << 0);
            result[i] = argb;
        }
        return result;
    }
}

class ColorInterpolator
{
    private static final int DELAY = 20;

    private Color currentColor;
    private int currentIndex = 0;
    private int currentColorsArgb[];
    private final Timer timer;
    private final ColorPanel colorPanel;

    ColorInterpolator(final ColorPanel colorPanel, Color initialColor)
    {
        this.colorPanel = colorPanel;

        currentColor = initialColor;
        currentColorsArgb = new int[]{ initialColor.getRGB() };
        timer = new Timer(DELAY, new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                currentIndex++;
                if (currentIndex >= currentColorsArgb.length-1)
                {
                    timer.stop();
                    colorPanel.enableButtons();
                }
                else
                {
                    int argb = currentColorsArgb[currentIndex];
                    currentColor = new Color(argb);
                    colorPanel.setColor(currentColor);
                }
            }
        });
    }

    void interpolateTo(Color targetColor)
    {
        colorPanel.diableButtons();
        currentColorsArgb = ChangeColor.createColorsArrayArgb(
            40, currentColor, targetColor);
        currentIndex = 0;
        timer.start();
    }
}


class ColorPanel extends JPanel
{
    private Color currentColor;
    private List<JButton> buttons;

    public ColorPanel(Color initialColor)
    {
        currentColor = initialColor;
        buttons = new ArrayList<JButton>();
    }

    void addColorButton(JButton button)
    {
        buttons.add(button);
        add(button);
    }

    public void diableButtons()
    {
        for (JButton button : buttons)
        {
            button.setEnabled(false);
        }
    }

    public void enableButtons()
    {
        for (JButton button : buttons)
        {
            button.setEnabled(true);
        }
    }

    public void setColor(Color color)
    {
        currentColor = color;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.setColor(currentColor);
        g.fillRect(0, 0, getWidth(), getHeight());
    }

    @Override
    public Dimension getPreferredSize()
    {
        return new Dimension(600, 300);
    }
}


回答2:

For simplicity, you might look at doing the fade calculation in HSB color coordinates. The example below interpolates between the two hues, green and blue, but you can pass saturation and brightness, too. The color lookup table, clut, is precomputed and used in the timer's listener. Some related examples are seen here.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.Queue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

/**
 * @see https://stackoverflow.com/a/24718561/230513
 */
public class HSBTest {

    private static final float greenHue = 2 / 6f;
    private static final float blueHue = 4 / 6f;

    private void display() {
        JFrame f = new JFrame("HSBTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Fader fader = new Fader(greenHue, blueHue);
        f.add(fader);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        fader.start();
    }

    private static class Fader extends JPanel implements ActionListener {

        private final float N = 32;
        private final Queue<Color> clut = new LinkedList<Color>();
        Timer t = new Timer(50, this);

        public Fader(float h1, float h2) {
            float d = (h2 - h1) / N;
            for (int i = 0; i < N; i++) {
                clut.add(Color.getHSBColor(h1 + d * i, 1, 1));
            }
            for (int i = 0; i < N; i++) {
                clut.add(Color.getHSBColor(h2 - d * i, 1, 1));
            }
        }

        private void start() {
            t.start();
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            this.setBackground(clut.peek());
            clut.add(clut.remove());
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(256, 128);
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new HSBTest().display();
            }
        });
    }
}


回答3:

public void actionPerformed(ActionEvent e) {
    List<Color> colors = new ArrayList<Color>();
    colors.add(new Color(0,0,255);
    colors.add(new Color(255,0,0);
    colors.add(new Color(0,255,0);
    // add your other colors
    for(Color c : colors){
          setColor(c)
          Thread.sleep(1000); //wait 1 second to change the color
          repaint();
     }
}