我的问题是我有一个表,其中一个列在表格单元格中有ProgressBars,我想根据行号和列号动态地动态更改ProgressBar的Bar颜色,但是我无法实现它。 Nimbus也有局限性。 我必须覆盖每个组件的Nimbus UI默认值。因此,如果我想动态更改单元格的条形颜色,如何在不更改单元格文本颜色的情况下实现它?
public class ProgressRenderer extends JProgressBar implements TableCellRenderer {
private static final long serialVersionUID = 1L;
public ProgressRenderer(int min, int max) {
super(min, max);
this.setStringPainted(true);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
this.setValue((Integer) value);
UIDefaults defaults = new UIDefaults();
defaults.put("ProgressBar[Enabled].foregroundPainter", new MyPainter(Color.RED));
defaults.put("ProgressBar[Enabled+Finished].foregroundPainter", new MyPainter(Color.RED));
putClientProperty("Nimbus.Overrides.InheritDefaults", Boolean.TRUE);
putClientProperty("Nimbus.Overrides", defaults);
return this;
}
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);
}
}
}
上面是我的代码片段,我使用的是TableCellRenderer。
答案 0 :(得分:2)
那样的东西? ;)
您遇到的问题是,覆盖特定组件实例的Nimbus默认颜色非常很痛苦(请参阅related question)。
大多数Nimbus画家定义了大约50种不同的颜色,这些颜色来自一个或两个基本颜色(nimbusBlueGrey
和着名的nimbusOrange
)。最好的方法是在要更改的组件的UIDefaults
属性中的Nimbus.Override
中覆盖它们,但这不是他们所做的(我想打开一个错误; ),不认真!)。
我一直在努力达到完全相同的目的,终于能够通过......(闭上眼睛)复制粘贴并将javax.swing.plaf.nimbus.ProgressBarPainter
类隐藏到我自己的代码中!为什么?因为该类是包的私有,无法覆盖(这可能会更清洁......)。
尽管我讨厌这样做,但它有效......
以下是如何修改它(我不会发布整个代码,因为它太大而且不那么有趣):
首先在ProgressBarPainter()
构造函数之后添加以下方法。 (它们基本上是您在decodeColor()
方法之后找到的内容的复制粘贴,然后是AbstractRegionPainter
,然后是NimbusLookAndFeel
,然后是NimbusDefaults.getDerivedColor()
,最后是DerivedColor.rederiveColor()
):< / p>
private float clamp(float v) {
if (v < 0.0f)
return 0.0f;
if (v > 1.0f)
return 1.0f;
return v;
}
private int clamp(int v) {
if (v < 0)
return 0;
if (v > 255)
return 255;
return v;
}
// Got from javax.swing.plaf.nimbus.DerivedColor.rederiveColor()
private Color decodeColor(Color src, float hOffset, float sOffset, float bOffset, int aOffset) {
float[] tmp = Color.RGBtoHSB(src.getRed(), src.getGreen(), src.getBlue(), null);
tmp[0] = clamp(tmp[0] + hOffset);
tmp[1] = clamp(tmp[1] + sOffset);
tmp[2] = clamp(tmp[2] + bOffset);
int alpha = clamp(src.getAlpha() + aOffset);
return new Color((Color.HSBtoRGB(tmp[0], tmp[1], tmp[2]) & 0xFFFFFF) | (alpha << 24), true);
}
将静态生成50种颜色的代码复制粘贴到您将用于从您想要的颜色动态生成它们的方法:
来自:
private Color color1 = decodeColor("nimbusBlueGrey", 0.0f, -0.04845735f, -0.17647058f, 0);
...
private Color color50 = decodeColor("nimbusOrange", 0.0014062226f, -0.77816474f, 0.12941176f, 0);
要:
private void initColors(Color foreground) {
color1 = decodeColor("nimbusBlueGrey", 0.0f, -0.04845735f, -0.17647058f, 0);
// ...
color50 = decodeColor(foreground, 0.0014062226f, -0.77816474f, 0.12941176f, 0);
}
请注意,我们将我们想要的颜色作为参数传递,并将其用作nimbusOrange
的替代,这似乎是进度条的主要颜色。我们试图坚持使用Nimbus的颜色衍生方式。
并更改ProgressBarPainter()
构造函数以包含主要颜色并生成它们:
public ProgressBarPainter(int state, Color foreground) {
super();
this.state = state;
this.ctx = new AbstractRegionPainter.PaintContext(new Insets(5, 5, 5, 5), new Dimension(29, 19), false);
initColors(foreground); // Generates appropriate colors
}
您将找到如何初始化ctx
来源中的NimbusDefaults
字段。但请注意,枚举类中不会显示枚举AbstractRegionPainter.PaintContext.CacheMode
,因此您将无法使用所有奇特的功能。幸运的是,AbstractRegionPainter.PaintContext
有一个更简单的构造函数,它不使用它。
(在我的情况下,我不需要所有不同的状态,所以我使用默认值,但随意添加任何其他参数来应对它们。)
最后,Graal! ;)
(我根据应该是百分比的值来改变颜色:green
如果超过75%,orange
如果超过50%,则red
。
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
int v = ((Integer)value).intValue();
Color c;
if (val >= 75)
c = Color.GREEN;
else if (val >= 50)
c = Color.ORANGE;
else
c = Color.RED;
setValue(v);
UIDefaults defaults = new UIDefaults();
ProgressBarPainter painter = new ProgressBarPainter(ProgressBarPainter.FOREGROUND_ENABLED, c);
defaults.put("ProgressBar[Enabled].foregroundPainter", painter);
putClientProperty("Nimbus.Overrides", defaults);
return this;
}
现在,让我们“清理”一点(尽管我们可以称之为“干净”的工作):
private Color colorXX
的{{1}}的分配,因为它们将通过调用nimbusOrange
生成。initColors()
的分配,因为我们没有更改它们,也不会将它们包含在nimbusBlueGrey
中。这样就会产生initColors()
生成26种颜色(17到28,30,33到44和50)。initColors()
并在ProgressBarPainter
<中指定正确的颜色/ LI>
getTableCellRendererComponent()
并在private static JProgressBar red, orange, green
中返回它们而不是this
)答案 1 :(得分:2)
或者,我最终做的是扩展JPanel
并用自己想要的颜色为自己绘制一个进度条:
public class ProgressBarCellRenderer extends JPanel implements TableCellRenderer {
int val = 0;
private static Paint generatePaint(Color c, int height) {
return new LinearGradientPaint(0.0f, 0.0f, 0.0f, (float)height, new float[]{0.0f, 0.5f, 1.0f}, new Color[]{c.darker(), c.brighter(), c.darker()}, CycleMethod.REFLECT);
}
private static Paint greenPaint = generatePaint(Color.GREEN);
private static Paint orangePaint = generatePaint(Color.ORANGE);
private static Paint redPaint = generatePaint(Color.RED);
@Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
int x = 1;
int y = 1;
int w = getWidth()-2;
int h = getHeight()-2;
g2d.setColor(Color.LIGHT_GRAY);
g2d.fillRect(x, y, w, h);
Paint backPaint;
if (val >= 75)
backPaint = greenPaint;
else if (val >= 50)
backPaint = orangePaint;
else
backPaint = redPaint;
g2d.setPaint(backPaint);
int wd = (int)Math.round(w * val / 100.0);
g2d.fillRect(x, y, wd, h);
g2d.draw3DRect(x, y, wd, h, true);
// Draw some text here if you want
}
}
结果看起来对我来说足够好,我发现它比“Nimbus hack”更清洁(和更有效)!