1

我的问题是我有一个表格,其中一列在表格单元格中有 ProgressBars,我想根据行号和列号动态更改 ProgressBar 的栏颜色,但是我无法实现它。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。

4

2 回答 2

2

类似的东西?;)

JTable 单元格上的不同 JProgressBar

您遇到的问题是,为特定组件实例覆盖 Nimbus 的默认颜色非常痛苦(请参阅相关问题)。

大多数 Nimbus 画家定义了大约 50 种不同的颜色,这些颜色源自一两个基本颜色(thenimbusBlueGrey和 Famous nimbusOrange)。最好的方法是在要更改的组件的UIDefaultsfound inNimbus.Override属性中覆盖它们,但这不是他们所做的(我想打开一个错误;),不认真!)。

我一直在努力实现完全相同的目标,最终能够通过......(闭上眼睛)复制粘贴并将javax.swing.plaf.nimbus.ProgressBarPainter类破解到我自己的代码中!为什么?因为该类是包私有的,不能被覆盖(这会更干净一些......)。尽管我讨厌这样做,但它确实有效......

这是修改它的方法(我不会发布整个代码,因为它太大而且没那么有趣):

  1. ProgressBarPainter()首先在构造函数之后添加以下方法。(它们基本上是您可以按照该decodeColor()方法找到的内容的复制粘贴,AbstractRegionPainter然后NimbusLookAndFeel再到NimbusDefaults.getDerivedColor()最后DerivedColor.rederiveColor()):

    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);
    }
    
  2. 将静态生成 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
}

您将ctxNimbusDefaults. 但是,请注意枚举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那些使用的分配nimbusOrange,因为它们将由调用生成initColors()
  • 保留这些使用的分配nimbusBlueGrey,因为我们不会更改它们,并且不要将它们包含在initColors(). 这样就可以initColors()生成 26 种颜色(17 到 28、30、33 到 44 和 50)。
  • 如果像我一样,您只有几种颜色可以代表所有进度条,请预先生成ProgressBarPainter您将使用的所有 s 并在getTableCellRendererComponent()
  • (或者在我的情况下,使用适当的覆盖颜色画家创建三个private static JProgressBar red, orange, green并返回它们而不是thisin getTableCellRendererComponent()
于 2013-06-28T07:27:38.820 回答
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 ”更干净(高效)!

于 2013-06-28T07:37:09.480 回答