2013-01-22 2 views
1

Моя проблема заключается в том, что у меня есть таблица, в которой один из столбцов имеет ProgressBars в ячейках таблицы, я хотел бы динамически изменять цвет строки ProgressBar динамически на основе номера строки и столбца , однако я не могу этого добиться. Также есть ограничения и Нимбуса. Я должен переопределить Nimbus UI по умолчанию для каждого компонента. Поэтому, если я хочу динамически изменять цвет ячеек ячейки, как я могу достичь этого, не меняя цвет текста ячейки?Как изменить цвет панели JProgressbar в ячейке таблицы Использование Nimbus Look And Feel

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

Кто-нибудь может помочь? – mbasol

ответ

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()):

    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); 

To:

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, который, кажется, основной цвет для прогресса баров. Мы стараемся придерживаться способа получения цветов Нимбусом.

И изменить 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, который не использует его. (В моем случае мне не нужны все разные состояния, поэтому я использовал значения по умолчанию, но не стесняйтесь добавлять любые другие параметры, чтобы справиться с ними).

И, наконец, Грааль! ;) (меняет цвет в соответствии со значением, которое должно быть в процентах: 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 с соответствующими перекрываться цветными художниками и вернуть их вместо this в getTableCellRendererComponent())
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»!

+0

, может быть, не хорошо, требуется глубочайший взгляд на него, но сделать необходимые вещи, +1 для усилий :-) – mKorbel

+0

Да, я устал от поиска о том, как настроить Нимбус, поэтому я быстро пошел на это. Если вы видите некоторые очевидные ошибки или улучшения, не стесняйтесь редактировать! Я в Swing всего месяц! – Matthieu