kann man zwei JProgressBar übereinander legen?
Das ist normaler Weise nicht hübsch. Nebeneinander ginge da schon eher. Oder Du trickst das UI aus, so würde ich's machen. Eine (ausführbare) Beispielimplementation. Die Main()-Methode würde man natürlich nach dem Spielen löschen: [HIGHLIGHT="Java"]import java.awt.Color;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
/**
* An enhanced progress bar, painting the bar content with an alternative
* color from a given threshold value. Note that the threshold calculation is
* based on the bare idea that the UI distributes the values uniformly in the
* whole content area (the component size without the insets).
*
* @author Ebenius
*/
public class JXProgressBar extends JProgressBar {
// -------------------------------------------------------------------------
// Instance fields
// -------------------------------------------------------------------------
private transient volatile boolean paintingAlternativeForeground;
private float alternativeThreshold = 0.5f;
private Color alternativeForeground = null;
// -------------------------------------------------------------------------
// Overridden methods for alternative paint support
// -------------------------------------------------------------------------
@Override
public Color getForeground() {
return paintingAlternativeForeground ? getAlternativeForeground() : super
.getForeground();
}
@Override
protected void paintComponent(Graphics g) {
if (alternativeForeground == null) {
super.paintComponent(g);
} else if (ui != null) {
Graphics scratchGraphics = (g == null) ? null : g.create();
try {
ui.update(scratchGraphics, this);
/* clip graphics for alternative painting */
final Insets ins = getInsets();
final int w = getWidth();
final int h = getHeight();
switch (getOrientation()) {
case SwingConstants.VERTICAL:
final int offset =
(int) ((h - ins.top - ins.bottom) * alternativeThreshold);
ins.top += offset;
break;
case SwingConstants.HORIZONTAL:
default:
if (getComponentOrientation().isLeftToRight()) {
ins.left += (w - ins.left - ins.right) * alternativeThreshold;
} else {
ins.right += (w - ins.left - ins.right) * alternativeThreshold;
}
break;
}
final int wNet = w - ins.left - ins.right;
final int hNet = h - ins.top - ins.bottom;
scratchGraphics.setClip(ins.left, ins.top, wNet, hNet);
/* paint the alternative part clipped */
try {
paintingAlternativeForeground = true;
ui.paint(scratchGraphics, this);
} finally {
paintingAlternativeForeground = false;
}
} finally {
scratchGraphics.dispose();
}
}
}
// -------------------------------------------------------------------------
// Bean getters and setters
// -------------------------------------------------------------------------
/**
* Get the foreground color used for values above the adjusted threshold
* value. If this color is {@code null}, alternative color paining is
* disabled. By default the value is {@code null}.
*
* @return the alternative foreground color – possibly {@code null}
*/
public Color getAlternativeForeground() {
return alternativeForeground;
}
/**
* Set the foreground color used for values above the adjusted threshold
* value. If this color is {@code null}, alternative color paining is
* disabled. By default the value is {@code null}.
*
* @param fg the alternative foreground color – possibly {@code null}
*/
public void setAlternativeForeground(Color fg) {
final Color old = this.alternativeForeground;
this.alternativeForeground = fg;
firePropertyChange("alternativeForeground", old, fg); //$NON-NLS-1$
}
/**
* Returns the threshold for the alternative color painting. This threshold
* is guaranteed to be a {@code float} number between {@code 0.f} and
* {@code 1.f} (both inclusive). By default the value is {@code 0.5f}.
*
* @return the threshold
*/
public float getAlternativeThreshold() {
return alternativeThreshold;
}
/**
* Sets the threshold for the alternative color painting. This threshold is
* a {@code float} number between {@code 0.f} and {@code 1.f} (both
* inclusive). If the bounds are violated, an
* {@link IllegalArgumentException} is thrown. By default the value is
* {@code 0.5f}.
*
* @param value the threshold to set
* @throws IllegalArgumentException if {@code value} is out of bounds
*/
public void setAlternativeThreshold(float value) {
if (value < 0.f || value > 1.f || Float.isNaN(value)) {
throw new IllegalArgumentException("value: " //$NON-NLS-1$
+ value
+ " is not in bounds [0.f,1.f]"); //$NON-NLS-1$
}
final float old = this.alternativeThreshold;
this.alternativeThreshold = value;
firePropertyChange("alternativeThreshold", old, value); //$NON-NLS-1$
}
// -------------------------------------------------------------------------
// Program Entry Point
// -------------------------------------------------------------------------
/**
* Test main method.
*
* @param args ignored
*/
public static void main(String[] args) {
/* progress bar */
final JXProgressBar bar = new JXProgressBar();
bar.setMinimum(0);
bar.setMaximum(100);
bar.setStringPainted(true);
bar.setString("Running"); //$NON-NLS-1$
bar.setAlternativeForeground(new Color(220, 117, 119));
bar.setAlternativeThreshold(0.45f);
// bar.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
/* timer */
final Timer timer = new Timer(20, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
final int n = bar.getValue() + 1;
if (n > bar.getMaximum()) {
((Timer) e.getSource()).stop();
bar.setString("Done"); //$NON-NLS-1$
return;
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
bar.setValue(n);
}
});
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
/* frame */
final JFrame f = new JFrame("Progress Bar Fun");
f.setContentPane(new JScrollPane(bar));
f.pack();
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setVisible(true);
}
}[/HIGHLIGHT]
Ebenius