如何使用Nimbus外观和感觉更改表格单元格中的JProgressbar栏颜色

时间:2013-01-22 21:52:23

标签: java swing jprogressbar tablecellrenderer nimbus

我的问题是我有一个表,其中一个列在表格单元格中有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。

2 个答案:

答案 0 :(得分:2)

那样的东西? ;)

Different JProgressBar on JTable cells

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

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

我一直在努力达到完全相同的目的,终于能够通过......(闭上眼睛)复制粘贴并将javax.swing.plaf.nimbus.ProgressBarPainter类隐藏到我自己的代码中!为什么?因为该类是包的私有,无法覆盖(这可能会更清洁......)。 尽管我讨厌这样做,但它有效......

以下是如何修改它(我不会发布整个代码,因为它太大而且不那么有趣):

  1. 首先在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);
    }
    
  2. 将静态生成50种颜色的代码复制粘贴到您将用于从您想要的颜色动态生成它们的方法:

  3. 来自:

    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并用自己想要的颜色为自己绘制一个进度条:

Custom-drawn progress bar with colors

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”更清洁(和更有效)!

相关问题