java JProgressbar:如何根据进度改变颜色?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12524121/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JProgressbar: how to change colour based on progress?
提问by Foo
Is it possible to be able to change the bar colour depending on the value of the progress? I tried the following but it doesn't work:
是否可以根据进度值更改条形颜色?我尝试了以下但它不起作用:
percentUsed = (int)(((float) used / (float) max) * BAR_PERCENTAGE);
if (percentUsed >= ORANGE_THRESHOLD && percentUsed < RED_THRESHOLD) {
if (!m_orangeIndicator) {
LOG.warn(String.format("Memory usage exceeds %d percent.", ORANGE_THRESHOLD));
m_orangeIndicator = true;
}
colour = Color.ORANGE;
m_redIndicator = false;
}
else if (percentUsed >= RED_THRESHOLD) {
if (!m_redIndicator) {
LOG.warn(String.format("Memory usage exceeds %d percent.", RED_THRESHOLD));
m_orangeIndicator = true;
m_redIndicator = true;
}
colour = Color.RED;
}
else {
m_orangeIndicator = false;
m_redIndicator = false;
colour = Color.GREEN;
}
m_memUsageBar.setForeground(colour);
m_memUsageBar.setValue(percentUsed);
m_memUsageBar.updateUI();
I am guessing it is not a trivial thing to do because JProgressbar is not meant to be used that way... But is it possible or are there alternatives?
我猜这不是一件微不足道的事情,因为 JProgressbar 不打算以这种方式使用......但是有可能吗或者有其他选择吗?
采纳答案by Foo
Thanks for the help but by trial and error I found a way to get the colour changing with using my existing code.
感谢您的帮助,但通过反复试验,我找到了一种使用现有代码更改颜色的方法。
I am not sure if its the quirk of JPrgressbar but if call do the following call the foreground bar colour can be changed dynamically with minimal rework:
我不确定它是否是 JPrgressbar 的怪癖,但如果调用执行以下调用,则可以通过最少的返工动态更改前景栏颜色:
progressBar.setStringPainted(true);
回答by aterai
- This sample was inspired from:
- 此示例的灵感来自:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;
import javax.swing.event.*;
public class GradientPalletProgressBarDemo {
public JComponent makeUI() {
final JProgressBar progressBar = new JProgressBar();
progressBar.setOpaque(false);
progressBar.setUI(new GradientPalletProgressBarUI());
JPanel p = new JPanel();
p.add(progressBar);
p.add(new JButton(new AbstractAction("Start") {
@Override public void actionPerformed(ActionEvent e) {
SwingWorker<Void,Void> worker = new SwingWorker<Void,Void>() {
@Override public Void doInBackground() {
int current = 0, lengthOfTask = 100;
while(current<=lengthOfTask && !isCancelled()) {
try { // dummy task
Thread.sleep(50);
} catch(InterruptedException ie) {
return null;
}
setProgress(100 * current / lengthOfTask);
current++;
}
return null;
}
};
worker.addPropertyChangeListener(new ProgressListener(progressBar));
worker.execute();
}
}));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new GradientPalletProgressBarDemo().makeUI());
frame.setSize(320, 240);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class ProgressListener implements PropertyChangeListener {
private final JProgressBar progressBar;
ProgressListener(JProgressBar progressBar) {
this.progressBar = progressBar;
this.progressBar.setValue(0);
}
@Override public void propertyChange(PropertyChangeEvent evt) {
String strPropertyName = evt.getPropertyName();
if("progress".equals(strPropertyName)) {
progressBar.setIndeterminate(false);
int progress = (Integer)evt.getNewValue();
progressBar.setValue(progress);
}
}
}
class GradientPalletProgressBarUI extends BasicProgressBarUI {
private final int[] pallet;
public GradientPalletProgressBarUI() {
super();
this.pallet = makeGradientPallet();
}
private static int[] makeGradientPallet() {
BufferedImage image = new BufferedImage(100, 1, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
Point2D start = new Point2D.Float(0f, 0f);
Point2D end = new Point2D.Float(99f, 0f);
float[] dist = {0.0f, 0.5f, 1.0f};
Color[] colors = { Color.RED, Color.YELLOW, Color.GREEN };
g2.setPaint(new LinearGradientPaint(start, end, dist, colors));
g2.fillRect(0, 0, 100, 1);
g2.dispose();
int width = image.getWidth(null);
int[] pallet = new int[width];
PixelGrabber pg = new PixelGrabber(image, 0, 0, width, 1, pallet, 0, width);
try {
pg.grabPixels();
} catch(Exception e) {
e.printStackTrace();
}
return pallet;
}
private static Color getColorFromPallet(int[] pallet, float x) {
if(x < 0.0 || x > 1.0) {
throw new IllegalArgumentException("Parameter outside of expected range");
}
int i = (int)(pallet.length * x);
int max = pallet.length-1;
int index = i<0?0:i>max?max:i;
int pix = pallet[index] & 0x00ffffff | (0x64 << 24);
return new Color(pix, true);
}
@Override public void paintDeterminate(Graphics g, JComponent c) {
if (!(g instanceof Graphics2D)) {
return;
}
Insets b = progressBar.getInsets(); // area for border
int barRectWidth = progressBar.getWidth() - (b.right + b.left);
int barRectHeight = progressBar.getHeight() - (b.top + b.bottom);
if (barRectWidth <= 0 || barRectHeight <= 0) {
return;
}
int cellLength = getCellLength();
int cellSpacing = getCellSpacing();
// amount of progress to draw
int amountFull = getAmountFull(b, barRectWidth, barRectHeight);
if(progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
// draw the cells
float x = amountFull / (float)barRectWidth;
g.setColor(getColorFromPallet(pallet, x));
g.fillRect(b.left, b.top, amountFull, barRectHeight);
} else { // VERTICAL
//...
}
// Deal with possible text painting
if(progressBar.isStringPainted()) {
paintString(g, b.left, b.top, barRectWidth, barRectHeight, amountFull, b);
}
}
}
回答by UVM
You can do either of this way:
您可以采用以下任一方式:
UIManager.put("ProgressBar.background", Color.BLACK); //colour of the background
UIManager.put("ProgressBar.foreground", Color.RED); //colour of progress bar
UIManager.put("ProgressBar.selectionBackground",Color.YELLOW); //colour of percentage counter on black background
UIManager.put("ProgressBar.selectionForeground",Color.BLUE); //colour of precentage counter on red background
There is a thread here. Setting the colors of a JProgressBar text
这里有一个线程。 设置 JProgressBar 文本的颜色
There is a sample demo here at this link as well. how to change color progressbar
此链接中还有一个示例演示。 如何更改颜色进度条
回答by kleopatra
As you noticed, is value-dependent "progress" painting not supported. Theoretically, setting the foregound of the progressBar instance dynamically (that is depending on value) is the way to go.
正如您所注意到的,不支持依赖于价值的“进步”绘画。理论上,动态设置progressBar 实例的前景(即取决于值)是可行的方法。
But: the details of progressBar painting are highlyLAF dependent
但是:progressBar 绘制的细节高度依赖于 LAF
- in simple LAFs (like Metal) setting the foreground is fine
- in fully skinnable LAFs (like synth-based LAF) that support per-instance skinning (f.i. Nimbus) you can try to provide a Painter which uses the foreground
- in not-skinnable LAFs there is no way (except overriding the concrete LAF and try to hook into the painting code)
- 在简单的 LAF(如 Metal)中设置前景很好
- 在支持每个实例换肤 (fi Nimbus) 的完全可换肤 LAF(如基于合成器的 LAF)中,您可以尝试提供一个使用前景的 Painter
- 在不可剥皮的 LAF 中没有办法(除了覆盖具体的 LAF 并尝试挂钩到绘画代码)
Some snippet:
一些片段:
final JProgressBar bar = new JProgressBar();
// used for Nimbus (beware: just a proof-of-concept - this looks extremely ugly!)
Painter p = new Painter() {
@Override
public void paint(Graphics2D g, Object object, int width, int height) {
JProgressBar bar = (JProgressBar) object;
g.setColor(bar.getForeground());
g.fillRect(0, 0, width, height);
}
};
// install custom painter on the bar
UIDefaults properties = new UIDefaults();
properties.put("ProgressBar[Enabled].foregroundPainter", p);
bar.putClientProperty("Nimbus.Overrides", properties);
// simulate progress
Action action = new AbstractAction("timer") {
@Override
public void actionPerformed(ActionEvent e) {
bar.setValue(bar.getValue() + 1);
// change foreground value-dependent
if (bar.getValue() > 10) {
bar.setForeground(Color.RED);
}
}
};
Timer timer = new Timer(100, action);
timer.start();