# Nimbus ProgressBar Colors



## Highchiller (9. Dez 2013)

Hallo Leute,

ich hab mal wieder eine Nimbus frage an euch. Angeblich soll es ja so leicht sein die DefaultWerte von Nimbus zu ändern aber ich find nicht raus wie ich meine Änderungen hinbekommen.

Meine JProgressBar ist im Nimbus Look and Feel. Das gefällt mir gut, aber wenn ich einen Text hinzufüge ist dieser auch schwarz wenn sich die Bar füllt. Schwarze Schrift auf dunkel-Orangen Hintergrund ist aber nicht gut zu lesen.

Wie ich die Schriftfarbe anpassen könnte ist hier super gelöst:
Change Textcolor of progressBar

Aber wenn ich von BasicProgressBarUI erbe dann ist die ProgressBar ja komplett abgeändert. Ich will aber die NimbusProgressBar nur mit den weißer Schrift wenn die Bar gefüllt ist, ansonsten schwarz.

Ich hoffe ihr könnt mir helfen.

Ich glaub Code ist hier nicht zwingen nötig.
Vielen Dank schon mal 

PS: Am besten wäre natürlich das für alle JProgressBars gleichzeitig zu ändern. Aber eine lokale Lösung würde mich auch erst mal reichen.


----------



## Highchiller (10. Dez 2013)

Also ich bekomme immerhin die Schrift weiß:


```
/* Die Imports kommen aus:
javax.swing.UIDefaults;
javax.swing.UIManager;
*/
  //... irgendwo weit vorher wurde das LookAndFeel auf Nimbus gesetzt
  UIDefaults defaults = UIManager.getLookAndFeelDefaults();
  defaults.put("ProgressBar[Enabled].textForeground", Color.WHITE);
  
  // this ist hier die JProgressBar in der ich mich befinde
  this.putClientProperty("Nimbus.Overrides.InheritDefaults", Boolean.TRUE);
  this.putClientProperty("Nimbus.Overrides", defaults);
```

Nun ist halt der ganze Text weiß unabhängig vom Hintergrund. Der Anfangspost hat ja angedeutet das es möglichkeiten gibt das so abzuändern, wenn man sich mit der BasicProgressBarUI zufrieden gibt schauts echt easy aus:

```
setUI(new BasicProgressBarUI() {
      protected Color getSelectionBackground() { return Color.black; }
      protected Color getSelectionForeground() { return Color.white; }
    });
```
Setting the colors of a JProgressBar text

Ich find einfach keinen Weg... :bahnhof: Gibts nicht irgendwie eine Möglichkeit vom NimbusLookAndFeel der ProgressBarUI zu erben? Sowas wie ne Klasse NimbusProgressBarUI gibts ja leider nicht...

Ich hoffe ihr kommt weiter als ich :/

Grüße
Highchiller


----------



## X5-599 (10. Dez 2013)

Leider gibt es keinen einfachen Weg. Bei meinen Recherchen bin ich soweit gekommen, dass das Nimbus Look and Feel das SynthProgressBarUI benutzt. Die Klasse ist package private also kann man da nichts überschreiben. Dann wird das NimbusStyle benutzt. Das ist wiederum eine final Klasse. Auch nichts mit überschreiben. Also wenn die Macher vorhatten dass da BLOSS keiner was anpasst haben sie ihr Ziel mehr als erfüllt. Ich habe jedenfalls bis jetzt keine Möglichkeit gefunden da irgendwo anzugreifen.
Wenn jemand mehr Erfolg hatte, oder andere Erkenntnisse hat würde ich mich über eine Nachhilfestunde freuen.


----------



## Highchiller (10. Dez 2013)

Oh man, das ist ja ärgerlich -.-

Könnte man irgendwie wild rumtricksen indem man drüber zeichnet?
Auch wenn ich grad keine Ahnung habe wie ich das am ehesten realisiere exakt 2 ProgressBars übereinander zu legen, die obere durchsichtig zu machen und nur den Text zu zeichnen...

Moaaaaaan


----------



## Highchiller (11. Dez 2013)

Letzte Idee, könnt ich da mit Reflection ran kommen? Macht kein Sinn wa?


----------



## X5-599 (11. Dez 2013)

Reflection habe ich auch drüber nachgedacht. Bin aber nicht weit gekommen. (und fände das auch ziemlich unschön...)
Ansonsten, drüber zeichnen hört sich eigentlich gut an. Willst du normale JProgressBars benutzen, oder kann das auch eine eigene Klasse sein, die JProgressBar beerbt?

Für "normale" JProgressBars könntest du sowas machen:

```
private static JProgressBar createProgressBar(final String text)
{
	@SuppressWarnings("serial")
	JProgressBar pr = new JProgressBar() {
			
		@Override
		protected void paintComponent(Graphics g)
		{
			super.paintComponent(g);
				
			Rectangle bounds = getBounds();
			FontMetrics fm = g.getFontMetrics();
			Rectangle2D rect = fm.getStringBounds(text, g);
				
			int x = (int)((bounds.width / 2) - (rect.getWidth() / 2));
			int y = (bounds.height / 2) + ((fm.getAscent()+fm.getDescent())/2);
				
			g.setColor(Color.WHITE);
			g.drawString(text, x, y-3);
		}
	};
		
	return pr;
}
```

So hast du natürlich immer einen weissen Text. Um die Farbe anzupassen, wenn z.B. der ProgressBar drübergelaufen ist, bedarf es schon etwas mehr Arbeit.


EDIT: Ach, ich seh' gerade man kann auch einfach folgendes machen:

```
JProgressBar progress = new JProgressBar();
progress.setForeground(Color.WHITE);
```

Da ist dann auch der ganze Text immer weiss. Nimbus ändert die Farbe anscheinend auch nie in Abhängigkeit des Füllstandes...


----------



## Highchiller (12. Dez 2013)

Naja wie gesagt, den ganzen Text auf einmal weiß zu bekommen ginge ja so:


Highchiller hat gesagt.:


> ```
> /* Die Imports kommen aus:
> javax.swing.UIDefaults;
> javax.swing.UIManager;
> ...



Aber ich glaub das übermalen ist gar nicht so schlecht. :bloed:
Meinste ich könnte dem Graphics-Object jetzt noch ein Clipping geben damit er nur mit Weiß übermalt wo auch die ProgressBar ausgefüllt ist und damit die restliche Schrift (schwarz) nicht übermalt? Das Clipping kann ja praktischer Weise ein simples Rectangle sein.
Oder versteh ich clip(Shape s) aus Graphics falsch?

Ich konnts noch nicht testen aber das klingt mir nach der (wenn auch umständlichen) Lösung :applaus:

Grüße
Highchiller

PS: Ja ich erbe sowieso von der JProgressBar also wird das ganze noch aufgeräumter


----------



## X5-599 (12. Dez 2013)

Dann habe ich was für dich. Ich habe mich dreisterweise beim BasicProgressBarUI bedient, was das Zeichnen anging . Mit clip() wird da gearbeitet. Ist eigentlich ganz verständlich, auch wenn ich noch nie damit gearbeitet habe. Die Positionierung ist komplett von mir. Die ließ sich nicht übernehmen, da das BasicProgressBarUI gerne mit SwingUtilities2 arbeitet...
Was hälst du davon?


```
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;

import javax.swing.BoundedRangeModel;
import javax.swing.JProgressBar;


public class MyJProgressBar2 extends JProgressBar
{
	private static final long serialVersionUID = 7011699579650095776L;
	private boolean stringPaintedOverride = false;
	private Color textColorOutsidePaint = Color.BLACK;
	private Color textColorInsidePaint = Color.WHITE;
	
	public MyJProgressBar2()
	{
		setStringPainted(false);
	}
	
	@Override
	protected void paintComponent(Graphics g)
	{
		super.paintComponent(g);
		
		if(stringPaintedOverride)
		{
			drawString(g);
		}
	}
	
	@Override
	public void setStringPainted(boolean painted)
	{
		super.setStringPainted(false);
		setStringPaintedOverride(painted);
	}
	
	private void setStringPaintedOverride(boolean stringPaintedOverride)
	{
		this.stringPaintedOverride = stringPaintedOverride;
	}
	
	public void setTextColorOutsidePaint(Color textColorOutsidePaint)
	{
		this.textColorOutsidePaint = textColorOutsidePaint;
	}
	
	public void setTextColorInsidePaint(Color textColorInsidePaint)
	{
		this.textColorInsidePaint = textColorInsidePaint;
	}
	
	private void drawString(Graphics g)
	{
		g.setFont(getFont());
		Rectangle oldClip = g.getClipBounds();
		
		Insets b = getInsets(); // area for border
		int barRectWidth = getWidth() - (b.right + b.left);
		int barRectHeight = getHeight() - (b.top + b.bottom);
		
		int amountFull = 0;
		BoundedRangeModel model = getModel();
		
		if ( (model.getMaximum() - model.getMinimum()) != 0) {
		    if (getOrientation() == JProgressBar.HORIZONTAL) {
		        amountFull = (int)Math.round(barRectWidth *
						     getPercentComplete());
		    } else {
		        amountFull = (int)Math.round(barRectHeight *
						     getPercentComplete());
		    }
		}
		
		int fillStart;
		Point renderLocation = getStringPlacement(g);
		
		if (getOrientation() == JProgressBar.HORIZONTAL)
		{
			if(getComponentOrientation().isLeftToRight())
				fillStart = b.left;
			else
				fillStart = b.left + barRectWidth - amountFull;
			
		    g.setColor(textColorOutsidePaint);
		    drawString(g, renderLocation.x, renderLocation.y);
		    
		    g.setColor(textColorInsidePaint);
	        g.clipRect(fillStart, b.top, amountFull, barRectHeight);
		    drawString(g, renderLocation.x, renderLocation.y);
		}
		else
		{
			// VERTICAL
			fillStart = b.top + barRectHeight - amountFull;
			
	        AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2);
	        g.setFont(getFont().deriveFont(rotate));
	        g.setColor(textColorOutsidePaint);
		    drawString(g, renderLocation.x, renderLocation.y);
		    
		    g.setColor(textColorInsidePaint);
		    g.clipRect(b.left, fillStart, barRectWidth, amountFull);
		    drawString(g, renderLocation.x, renderLocation.y);
		}
		
		g.setClip(oldClip);
	}
	
	private Point getStringPlacement(Graphics g)
	{
		FontMetrics fontSizer = getFontMetrics(getFont());
		if (getOrientation() == JProgressBar.HORIZONTAL)
		{
			int x = (getWidth() / 2) - (int)Math.round(fontSizer.getStringBounds(progressString, g).getWidth() / 2);
			int y = (getHeight() - (int)Math.round((getHeight()-fontSizer.getStringBounds(progressString, g).getHeight()) / 2)) - 3;
			return new Point(x, y);
		}
		else
		{
			// VERTICAL
			int x = ((getWidth() / 2) - (int)Math.round(fontSizer.getStringBounds(progressString, g).getHeight() / 2)) + 4;
			int y = (int)Math.round((getHeight() - fontSizer.getStringBounds(progressString, g).getWidth()) / 2);
			return new Point(x, y);
		}
	}
	
	private void drawString(Graphics g, int x, int y)
	{
		if(g != null)
		{
			if(isIndeterminate())
				g.setColor(Color.BLACK);
			
			g.drawString(progressString, x, y);
		}
	}
}
```

EDIT: Ich sehe gerade Zeile 22 kannst du rausnehmen. Ist unwichtig, da paintString sowiso standardmäßig false ist.


----------



## Highchiller (12. Dez 2013)

Hey X5-599,

na Mensch! Das ist doch Prima  Das ist obendrein gleich noch viel mehr als ich gebraucht hätte. Ich glaub das kann in den CodeSchnippsel bereich verschobene werden, sowas gibts doch hier 

Gefällt mir sehr gut. Ich konnts noch nicht testen aber so wie ich den Code-Lese schauts richtig gut aus. Da müsste sogar das Nimbus LookAndFeel erhalten bleiben 

Wenn sich noch Probleme auftun meld ich mich noch mal.

Vielen Dank noch mal  Das hat mir extrem geholfen.

Grüße
Highchiller


----------



## X5-599 (12. Dez 2013)

Danke für die Blumen 

Keine Ahnung, ob das ein Moderator verschieben (kopieren) möchte...

Ja, das Look And Feel bleibt erhalten. Bloss das Vorgehen des Zeichnens des Strings ist jetzt immer gleich. Normalerweise macht das ja jedes Look And Feel auf seine Weise. Evtl könnte man ja einen Schalter einbauen, der das Zeichnen bei Bedarf wieder auf "alte" Weise macht.


----------

