JProgressBar Farbverlauf Rot zu Grün

Hallo,

ich möchte gern eine JProgressBar realisieren die je nach Prozentwert die Farbe als Verlauf ändert. Beispiel siehe Grafik.

Ich habe mich schon im Netz etwas umgesehen aber konnte nichts richtiges finden, das meiste was ich dazu fand war entweder in JavaScript oder C geschrieben. Ich wollte daher fragen ob von euch jemand schon so eine JProgressBar realisiert hat und wenn ja wie ist er da vorgegangen.

Ich bedanke mich schon mal für mögliche Antworten.

t_2

Ich denke es ist am einfachsten sich hierfür auf Basis von JPanel oder JComponent etwas eigenes zu schreiben. Damit hat man maximale gestalterische Freiheit bzgl. Form und Farbe bei vergleichsweise wenig Implementierungsaufwand.
In Deinem Fall wäre es ja nur ein Balken mit einem Farbverlauf von Rot nach Grün der entsprechend dem Fortschritt zum Teil angezeigt wird.

hast du die englische Übersetzung ‘color gradient’ oder GradientPaint aus Java in deine Suchen einfließen lassen?
ein Link ist etwa

wobei dort der schnelle Blick auf das (zum Glück vorhandene) Bild einfarbiges zeigt,
aber als Ausgangslage vielleicht zu gebrauchen, nur die Zeichnung auszutauschen? oder noch andere Suchergebnisse

Bin zwar kein Fan davon, komplette Lösungen zu posten, aber da mir meine Arbeit gerade echt gefällt will ich diese dann doch gerne Teilen :). Aber immerhin: der Code kann definitiv noch etwas pflege gebrauchen. Solltest du es verwenden wollen, überlasse ich es dir selbigen für dein Projekt aufzuräumen :-P.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Paint;
import java.awt.geom.Point2D;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

@SuppressWarnings("serial")
public class PaintTest extends JComponent {
	private float progress = 0.0f;
	private boolean simpleMode = true;
	
	private Color[] simpleColors = {
		Color.ORANGE,
		Color.GREEN
	};
	
	private Color[] extendedColors = {
		Color.RED,
		Color.ORANGE,
		Color.GREEN,
		Color.GREEN.darker()		
	};
	
	public static void main(final String[] args) {
		final JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);		
		
		final PaintTest test = new PaintTest();
		test.setPreferredSize(new Dimension(400, 20));
		test.setProgress(0.0f);
		test.setSimpleMode(true);
		frame.add(test, BorderLayout.NORTH);		
		
		final PaintTest test2 = new PaintTest();
		test2.setPreferredSize(new Dimension(400, 20));
		test2.setProgress(0.0f);
		test2.setSimpleMode(false);
		frame.add(test2, BorderLayout.SOUTH);
		
		frame.setSize(new Dimension(400, 90));
		
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {				
				frame.setLocationRelativeTo(null);				
				frame.setVisible(true);
			}
		});
		
		new Thread() {
			@Override
			public void run() {
				for(float i = .0f; i <= 1.0; i+=0.01) {
					test.setProgress(i);
					test2.setProgress(i);
					try {
						Thread.sleep(25);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}									
				}				
			}
		}.start();			
	}
	
	@Override
	protected void paintComponent(final Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		
		drawBackground(g2d);
		
		if(simpleMode) {
			drawSimpleProgress(g2d);
		} else {
			drawProgress(g2d);
			//drawProgress(g2d);
		}
		
		drawOverlay(g2d);
		
		drawBoarder(g2d);
	}
	
	private void drawOverlay(final Graphics2D g) {
		Graphics2D g2d = (Graphics2D) g.create();
			
		g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
		g2d.setPaint(new GradientPaint(new Point2D.Float(getWidth()/2, 0), Color.WHITE, new Point2D.Float(getWidth()/2, getHeight()), Color.GRAY));
		
		g2d.fillRect(0,0,(int) (getWidth()*progress),getHeight());
		
		g2d.dispose();
	}
	
	private void drawBackground(final Graphics2D g) {
		Paint paint = g.getPaint();
		
		g.setPaint(new GradientPaint(new Point2D.Float(getWidth()/2, 0), Color.WHITE, new Point2D.Float(getWidth()/2, getHeight()), Color.LIGHT_GRAY));
		g.fillRect(0, 0, getWidth()-1, getHeight()-1);
		
		g.setPaint(paint);
	}
	
	private void drawSimpleProgress(final Graphics2D g) {
		Paint paint = g.getPaint();
		
		g.setPaint(new GradientPaint(new Point2D.Float(0, getHeight()/2), simpleColors[0], new Point2D.Float(getWidth(), getHeight()/2), simpleColors[1]));
		g.fillRect(0, 0, (int) (getWidth()*progress), getHeight()-1);
		
		g.setPaint(paint);
	}
	
	private void drawProgress(final Graphics2D g) {
		Graphics2D g2d = (Graphics2D) g.create();
		
		float[] dist = {0f, .33f, .66f, 1f};
		
		g2d.setPaint(new LinearGradientPaint(new Point2D.Float(0, getHeight()/2), new Point2D.Float(getWidth(), getHeight()/2), dist, extendedColors));
		g2d.fillRect(0, 0, (int) (getWidth()*progress), getHeight());
		
		g2d.dispose();
	}	
		
	private void drawBoarder(final Graphics2D g) {
		g.setColor(Color.BLACK);
		g.drawRect(0, 0, getWidth()-1, getHeight()-1);
	}
	
	public void setProgress(final float progress) {
		this.progress = progress;
		
		repaint();
	}
	
	public void setSimpleMode(final boolean simpleMode) {
		this.simpleMode = simpleMode;
	}
}

Hallo,

zunächst einmal vielen Dank für die Antworten und Entschuldigt das ich gestern nicht mehr geantwortet habe.

@_Michael
Das mit dem JPanel bzw. der JComponent war ein guter Tipp ich hatte mich auf eine JProgressBar fixiert und wollte davon irgendwie nicht weg, aber der Tipp mit dem Panel hat mich zum Umdenken gebracht.

@SlaterB
Die Seite die Du geteilt hast kannte ich schon, allerdings hatte ich sie wieder verworfen da es ja kein Verlauf war sondern eben nur einfarbig. Es wäre zwar eine Notlösung gewesen aber nur rein vom Optischen her wollte ich gern eine ProgressBar mit Verlauf. Zu meinen wenigen Treffern kam es womöglich weil ich keine Englischen Begrifflichkeiten verwendet habe. Ich vergesse das immer da Englisch und Ich wie Pech und Schwefel sind.

@Tomate_Salat
Ich danke Dir dafür das Du den gesamten Source Code teilst, ich bin eigentlich auch kein Fan davon wenn man mir fertige Lösungen hinklatscht, ich finde da geht der Lerneffekt verloren. Jedoch bin ich in diesem Falle äußerst erfreut darüber. Denn ich habe mit den Grafischen Klassen und Methoden so gut wie noch nie gearbeitet. Die Klasse GradientPaint war mir noch völligst unbekannt und kam mir erstmalig bei meinen Recherchen mit Farbverlauf und JPanel unter die Augen. Ich werde mich jetzt erstmal hinsetzen und den Code verstehen, wenn ich noch Fragen haben sollte werde ich mich nochmal melden.

ich habe eine Seite geteilt? ja, das gibt es wohl in der neuen Sprache…,
lese ich zum ersten Mal auf mich bezogen, dem zu Ehren erlaube ich mir ein Spam-Posting :wink:

alternative Schreibweisen sind immer eine Frage, hier wäre es aber leicht gewesen:
„Die Seite die Du geteilt hast kannte ich schon“ == „Die Seite/ Den Link kannte ich schon“

In Zeiten wo alles nur noch “geteilt” und “geliked” wird, ist die Aussage zu vertreten. Aber bescheuert hört sich das schon an, da hast Du recht.

Also, um es richtig zu stellen “Den Link den du gepostet bzw. genannt hast, kannte ich schon.”

@Tomate_Salat
Ich habe mir dein Beispiel mal genauer angesehen und hab es auch recht schnell verstanden, allerdings sind da zwei Sachen die mir nicht einleuchten.

In den Methoden private void drawOverlay(final Graphics2D g) und private void drawProgress(final Graphics2D g) erzeugst Du doch mit Graphics2D g2d = (Graphics2D) g.create(); eine Kopie des Übergebenen Objektes. Ich verstehe nur nicht ganz warum Du das nochmal auf ein Graphics2D Objekt Castest, es wird doch schon ein G2D Objekt übergeben.
Desweiteren leuchtet mir nicht ganz ein das die Border nicht gezeichnet werden, wenn diese Kopie nicht erstellt wird. Ich dachte immer es wird in der Reihenfolge gezeichnet wie auch aufgerufen wird.
Das Zeichnen der Border ist doch aber in der protected void paintComponent(final Graphics g) der letzte Aufruf.

Die Methoden private void drawBackground(final Graphics2D g) und private void drawSimpleProgress(final Graphics2D g) verwirren mich auch etwas. Beim Einstieg in die Methoden holst Du dir mit Paint paint = g.getPaint(); vom Übergebenen Objekt die aktuelle Farbe des Inhalts. Mit g.setPaint(...) legst Du die neuen Attribute fest und am Ende überschreibst Du sie wieder mit den zu Beginn geholten Werten g.setPaint(paint);. Um es nachvollziehen zu können habe ich die Zeilen mal Auskommentiert und mußte feststellen das sich nichts geändert hat. Es wird noch alles genauso gezeichnet wie mit den Zeilen und das verwirrt mich.

Könntest Du mir die zwei Sachen nochmal etwas genauer Beschreiben ansonsten nochmals vielen Dank für dein Beispiel. Du hast mir viel Arbeit und Kopfschmerzen erspart.

1.)
Weil g.create(); als Rückgabewert einfach nur Graphics hat. Das Objekt ist zwar vom Typ Graphics2D, aber dafür ist eben der extra cast notwendig.
Warum die Border scheinbar(!) nicht gezeichnet werden ist ganz einfach: ich verändere den Zustand von dem Graphics2D-Objekt (setComposite, setPaint). Da ich keine Lust hatte, den Originalzustand wiederherzustellen, habe ich mir die Kopie erzeugt. Die Border werden also schon gezeichnet - nur mit falschen Einstellungen.

Der Gedanke dahinter ist der gleiche wie bei punkt 1: das GraphicsObjekt wieder in den Zustand zu setzen, wie ich es bekommen habe.