根据Java Swing值动态设置Color

我正在使用Java Swing。 我想根据我计算的双值显示颜色。

编辑 – 我需要填充Path2D对象的颜色。 目前,我就是这样做的

 Path2D shape; // some code here g2d.setColor(Color.Red); g2d.fill(shape); 

现在我不希望将颜色固定为Color.Red但需要根据我计算的值来设置它。 双值可以是负值或正值。 值越负,颜色应越暗。 颜色不必是红色。 我怎么能这样做?

您必须知道double值的可能范围。 (至少,这会让事情变得更容易理解)。 在任何情况下,您都可以将double值转换为[0,1]范围内的值。 在许多情况下,无论如何都要做这种规范化是有益的。

所以你可以创建一个方法

 private static double normalize(double min, double max, double value) { return (value - min) / (max - min); } 

此方法将min和max之间的任何“值”转换为[0,1]中的值。 为了将此标准化值映射到颜色,您可以使用

 private static Color colorFor(double value) { value = Math.max(0, Math.min(1, value)); int red = (int)(value * 255); return new Color(red,0,0); } 

此方法将0.0到1.0之间的值转换为颜色:0.0将为黑色,1.0将为红色。

假设你在“min”和“max”之间有一个双“值”,你可以将它映射到这样的颜色:

 g2d.setColor(colorFor(normalize(min, max, value))); g2d.fill(shape); 

编辑:回复评论:我认为基本上有两种选择:

  • 您可以不断跟踪到目前为止遇到的当前最小/最大值。
  • 或者,您可以使用S形函数将[-Infinity,+ Infinity]的间隔映射到区间[0,1]

第一种选择的缺点在于,先前与某种颜色相关联的值可能突然具有不同的颜色。 例如,假设您将间隔[0,1]映射到颜色范围[黑色,红色]。 现在你获得一个新的最大值,如100000.然后你必须调整你的范围,值0和1将不再有视觉差异:它们都将被映射到’黑色’。

第二种选择的缺点是,初始值的微小差异不会对颜色产生显着影响,具体取决于发生这些差异的范围。 例如,您将无法看到10000和10001之间的差异。

因此,您必须清楚自己想要的颜色映射和行为。

但是,这是一个使用S形函数将[-Infinity,+ Infinity]的间隔映射到区间[0,1],并将此区间映射到颜色的示例:

 import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; class ColorRange { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(); } }); } private static void createAndShowGUI() { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.getContentPane().add(new ColorRangePanel()); f.setSize(1000, 200); f.setLocationRelativeTo(null); f.setVisible(true); } } class ColorRangePanel extends JPanel { @Override protected void paintComponent(Graphics gr) { super.paintComponent(gr); Graphics2D g = (Graphics2D)gr; double values[] = { -1e3, -1e2, -1e1, -1, -0.5, 0.0, 0.5, 1, 1e1, 1e2, 1e3 }; for (int i=0; i 

作为此处建议的TableCellRenderer方法的具体示例,实现Icon接口,如此处所示。 不要改变大小,而是使用Color.getHSBColor()选择基于不同饱和度或亮度的颜色,如下所示。

附录:与引用的示例一样,下面的渲染假设数据值在区间[0, 1)中标准化。 您需要扩展到数据模型的最小值和最大值。 如果模型经常更新,则每次添加可能值得更新这些值。

图片

 /** * @see https://stackoverflow.com/a/21756629/230513 * @see https://stackoverflow.com/a/2834484/230513 */ private static class DecRenderer extends DefaultTableCellRenderer implements Icon { private static final int N = 256; private static final int SIZE = 32; private static List clut = new ArrayList<>(N); private DecimalFormat df; public DecRenderer(DecimalFormat df) { this.df = df; this.setIcon(this); this.setHorizontalAlignment(JLabel.RIGHT); this.setBackground(Color.lightGray); for (float i = 0; i < N; i++) { clut.add(Color.getHSBColor(1, 1, i / N)); } } @Override protected void setValue(Object value) { setText((value == null) ? "" : df.format(value)); } @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); double v = Double.valueOf(this.getText()); final int i = (int) (v * N - 1); g2d.setColor(clut.get(i)); g2d.fillOval(x, y, SIZE, SIZE); } @Override public int getIconWidth() { return SIZE; } @Override public int getIconHeight() { return SIZE; } } 

这个问题缺乏背景。 所有Swing组件都有setBackground方法,可以更改不透明组件的背景。

如果要更改JTable单元格或JListJTableJComboBox的背景颜色,则需要提供能够执行此任务的自定义单元格渲染器,在这种情况下,您应该查看…

  • JTable ,使用自定义渲染器
  • JList ,编写自定义单元格渲染器
  • JComboBox ,提供自定义渲染器
  • JTree ,自定义树的显示

根据OP问题的更新,以示例更新

以下是颜色混合算法的示例,它允许您指定要使用的颜色以及它们应显示的比例/分数。 例如非常简单,它只使用三种颜色均匀分布在整个范围内,但您可以根据需要添加更多颜色或调整重量。

该示例采用一系列随机生成的值并对其进行归一化,以便当值趋向于0(或较低的正常范围)时,它将变得更暗,当它接近1时,它将变得更亮。

如果选择,您可以更改算法以分别标准化正值和负值。

酒吧

 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class ColorBars { public static void main(String[] args) { new ColorBars(); } public ColorBars() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { private PlotPane plotPane; private JSpinner valueAdd; public TestPane() { setLayout(new BorderLayout()); plotPane = new PlotPane(); add(plotPane); } } public class PlotPane extends JPanel { private Color[] colorRange = new Color[]{Color.BLACK, Color.RED, Color.WHITE}; private float[] ratioRanges = new float[]{0f, 0.5f, 1f}; // private Color maxColor = Color.WHITE; // private Color minColor = Color.RED; private List values; private double min = Double.MAX_VALUE; private double max = Double.MIN_VALUE; public PlotPane() { values = new ArrayList<>(25); Random rnd = new Random(); for (int index = 0; index < 10; index++) { addValue((rnd.nextDouble() * 2000) - 1000); } } public void addValue(double value) { max = Math.max(max, value); min = Math.min(min, value); values.add(value); repaint(); } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics g2d = (Graphics2D) g.create(); int height = getHeight(); int width = getWidth(); int barWidth = width / values.size(); int x = 0; for (Double value : values) { double norm = value - min; norm /= (max - min); int barHeight = (int) (height * norm); System.out.println(NumberFormat.getInstance().format(norm)); Color color = blendColors(ratioRanges, colorRange, (float)norm); g2d.setColor(color); g2d.fillRect(x, height - barHeight, barWidth, barHeight); x += barWidth; } g2d.dispose(); } } public static Color blendColors(float[] fractions, Color[] colors, float progress) { Color color = null; if (fractions != null) { if (colors != null) { if (fractions.length == colors.length) { int[] indicies = getFractionIndicies(fractions, progress); float[] range = new float[]{fractions[indicies[0]], fractions[indicies[1]]}; Color[] colorRange = new Color[]{colors[indicies[0]], colors[indicies[1]]}; float max = range[1] - range[0]; float value = progress - range[0]; float weight = value / max; color = blend(colorRange[0], colorRange[1], 1f - weight); } else { throw new IllegalArgumentException("Fractions and colours must have equal number of elements"); } } else { throw new IllegalArgumentException("Colours can't be null"); } } else { throw new IllegalArgumentException("Fractions can't be null"); } return color; } public static int[] getFractionIndicies(float[] fractions, float progress) { int[] range = new int[2]; int startPoint = 0; while (startPoint < fractions.length && fractions[startPoint] <= progress) { startPoint++; } if (startPoint >= fractions.length) { startPoint = fractions.length - 1; } range[0] = startPoint - 1; range[1] = startPoint; return range; } public static Color blend(Color color1, Color color2, double ratio) { float r = (float) ratio; float ir = (float) 1.0 - r; float rgb1[] = new float[3]; float rgb2[] = new float[3]; color1.getColorComponents(rgb1); color2.getColorComponents(rgb2); float red = rgb1[0] * r + rgb2[0] * ir; float green = rgb1[1] * r + rgb2[1] * ir; float blue = rgb1[2] * r + rgb2[2] * ir; if (red < 0) { red = 0; } else if (red > 255) { red = 255; } if (green < 0) { green = 0; } else if (green > 255) { green = 255; } if (blue < 0) { blue = 0; } else if (blue > 255) { blue = 255; } Color color = null; try { color = new Color(red, green, blue); } catch (IllegalArgumentException exp) { NumberFormat nf = NumberFormat.getNumberInstance(); System.out.println(nf.format(red) + "; " + nf.format(green) + "; " + nf.format(blue)); exp.printStackTrace(); } return color; } } 

您可以在以下位置看到此颜色混合算法:

  • 色彩衰落算法?
  • Java:平滑的颜色过渡