Что-то такое? ;)
![Другой JProgressBar в ячейках JTable](https://i.stack.imgur.com/cp0Wd.png)
Проблема заключается в том, что чрезвычайно сложно переопределить цвета Nimbus по умолчанию для конкретного экземпляра компонента (см. swing-nimbus-lf-primary-color-per-component-instance">связанный с этим вопрос).
Большинство художников Nimbus определяют около 50 различных цветов, полученных из одного или двух основных цветов (nimbusBlueGrey
и знаменитого nimbusOrange
). Лучшим способом было бы переопределить их в свойстве UIDefaults
, найденном в свойстве Nimbus.Override
компонента, который вы хотите изменить, но это не то, что они сделали (я хотел бы открыть ошибку по этому поводу;), нет серьезно!).
Я пытался добиться того же самого и, наконец, смог... (закройте глаза) скопировать и вставить класс javax.swing.plaf.nimbus.ProgressBarPainter
в свой собственный код! Почему? Потому что этот класс является частным для пакета и не может быть переопределен (что было бы немного чище...). Как бы я ненавидел это делать, это сработало...
Вот как его изменить (я не буду публиковать весь код, так как он слишком большой и не очень интересный):
Начните с добавления следующих методов после конструктора 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);
}
Скопируйте и вставьте код, статически генерирующий 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
, который, по-видимому, является основным цветом для индикаторов выполнения. Мы пытаемся придерживаться способа получения цветов 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
есть более простой конструктор, который его не использует. (В моем случае мне не нужны были все разные состояния, поэтому я использовал значения по умолчанию, но не стесняйтесь добавлять любые другие параметры, чтобы справиться с ними).
И, наконец, Грааль! ;) (Я меняю цвет в соответствии со значением, которое должно быть в процентах: 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
, которые вы когда-либо будете использовать, и назначьте правильный в getTableCellRendererComponent()
.
- (или в моем случае создайте три
private static JProgressBar red, orange, green
с соответствующими переопределенными цветными рисунками и верните их вместо this
в getTableCellRendererComponent()
)
person
Matthieu
schedule
28.06.2013