5

i am looking at putting a progress bar into a game i am making with a count down from a random number between 5 and 20 down to 0. this is my code so far:

package Software;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;

public class CountDownProgressBar extends JPanel {

    RandomValues randomNum;
    int timeValue;
    Timer timer;
    int length, newLength;

    public CountDownProgressBar() {
        timer = new Timer(24, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
               for (int i = timeValue; i > 0; --i) {
                        newLength = length - (length / timeValue);
                        length = newLength;
                        repaint();
                    }
                }
            });
        randomNum = new RandomValues();
        this.timeValue = 0;
        this.setBackground(Color.GRAY);
    }

    @Override
    public void paint(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.green);
        g.fillRect(0, 0, length, 50);
    }

    public void setTimeLength() {
        this.timeValue = randomNum.integer(5, 20);
    }

    public int getTimeLength() {
        return this.timeValue;
    }
}

I know most of it is wrong, i just cant figure out how to do. it needs to not use JProgressBar, instead use graphics (a green rectangle) where it gets smaller and smaller and the time counts down. and how would I make it so the screen can be resizable and the bar will still count down relative to the screen size. so it isnt jsut one fixed size but just goes across the bottom of the screen.

KrazyKat89
  • 81
  • 1
  • 5
  • You can make a custom JComponent – Extreme Coders Dec 26 '12 at 05:25
  • 6
    1) A `JProgressBar` *can* be drawn directly to a `Graphics` instance. 2) Don't block the EDT (Event Dispatch Thread) - the GUI will 'freeze' when that happens. Instead of calling `Thread.sleep(n)` implement a Swing `Timer` for repeating tasks. See [Concurrency in Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) for more details. 3) *"goes across the bottom of the screen."* Put the `JProgressBar` in the `PAGE_END` of a `BorderLayout` ***instead*** of over the game play area. – Andrew Thompson Dec 26 '12 at 05:33
  • +1 to @AndrewThompson comment. See my answer for an example using that logic: http://stackoverflow.com/a/14052118/1133011 – David Kroukamp Dec 27 '12 at 09:20
  • Also consider a [custom `ProgressBarUI`](http://stackoverflow.com/a/11148842/230513). – trashgod Dec 27 '12 at 12:14
  • 1
    @andrew That is an answer, not a comment. Why not post it as such? – dstibbe Dec 27 '12 at 13:10
  • 1
    @dstibbe It is usually a judgement call with this type of comment/answer. Since there are now 3 good examples either in, or linked from the thread, I think I'll leave it as a comment this time. – Andrew Thompson Dec 27 '12 at 14:04
  • @Andrew "without using `JProgressBar`" – Yousha Aleayoub Nov 22 '18 at 14:33

4 Answers4

11

This is the code of a custom JProgressBar I made long time ago (I know the question states to not use a JProgressBar but you can grab code ideas from it), it was designed to resemble the progress bar look & feel from the "Human" theme in ubuntu 9.04:

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JProgressBar;

/**
 * A progressBar that looks like the progress bar from Ubuntu 9.04 Human Theme
 */
public class HumanProgressBar extends JProgressBar {
    private static final long serialVersionUID = 1L;

    private static final String DISABLED_PERCENT_STRING = " --- ";

    private static final Color gradientEndingColor = new Color(0xc0c0c0);
    private static final Color borderColor = new Color(0x736a60);
    private static final Color disabledBorderColor = new Color(0xbebebe);    

    private static final Composite transparent = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.45f);
    private static final Composite veryTransparent = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.25f);

    private static GradientPaint gradient;

    private int oldWidth;
    private int oldHeight;

    private int displayWidth;
    private int displayHeight;

    private int insets[] = new int[4];
    private static final int TOP_INSET = 0;
    private static final int LEFT_INSET = 1;
    private static final int BOTTOM_INSET = 2;
    private static final int RIGHT_INSET = 3;

    private static final int PREFERRED_PERCENT_STRING_MARGIN_WIDTH = 3;

    public static final Color PREFERRED_PROGRESS_COLOR = new Color(0x1869A6);

    private boolean percentStringVisible = true;

    private Color progressColor;

    private String maxPercentString;

    public HumanProgressBar() {
        progressColor = PREFERRED_PROGRESS_COLOR;
    }

    public void updateGraphics() {
        update(getGraphics());
    }

    @Override
    protected void paintComponent(Graphics g) {
        int w = displayWidth != 0 ? displayWidth - 1 : getWidth() - 1;
        int h = displayHeight != 0 ? displayHeight - 1 : getHeight() - 1;

        int x = insets[LEFT_INSET];
        int y = insets[TOP_INSET];
        w -= (insets[RIGHT_INSET] << 1);
        h -= (insets[BOTTOM_INSET] << 1);

        if (gradient == null) {
            gradient = new GradientPaint(0.0f, 0.0f, Color.WHITE, 0.0f, h, gradientEndingColor);
        }
        Graphics2D g2d = (Graphics2D) g;
        // Clean background
        if (isOpaque()) {
            g2d.setColor(getBackground());
            g2d.fillRect(0, 0, getWidth(), getHeight());
        }

        g2d.translate(x, y);

        if (percentStringVisible) {
            FontMetrics fm = g.getFontMetrics();
            int stringW = 0;
            int stringH = 0;

            g2d.setColor(getForeground());

            if (isEnabled()) { 
                int p = getValue();
                String percent = Integer.toString(p, 10) + "%";
                if (p < 10) {
                    percent = "0" + percent;
                }

                if (maxPercentString == null) {
                    maxPercentString = Integer.toString(getMaximum(), 10) + "%";
                }
                stringW = fm.stringWidth(maxPercentString);
                stringH = ((h - fm.getHeight()) / 2) + fm.getAscent();

                g2d.drawString(percent, w - stringW, stringH);
            } else {
                stringW = fm.stringWidth(DISABLED_PERCENT_STRING);
                stringH = ((h - fm.getHeight()) / 2) + fm.getAscent();

                g2d.drawString(DISABLED_PERCENT_STRING, w - stringW, stringH);
            }
            w -= (stringW + PREFERRED_PERCENT_STRING_MARGIN_WIDTH);            
        }

        // Control Border
        g2d.setColor(isEnabled() ? borderColor : disabledBorderColor);
        g2d.drawLine(1, 0, w - 1, 0);
        g2d.drawLine(1, h, w - 1, h);
        g2d.drawLine(0, 1, 0, h - 1);
        g2d.drawLine(w, 1, w, h - 1);

        // Fill in the progress
        int min = getMinimum();
        int max = getMaximum();
        int total = max - min;
        float dx = (float) (w - 2) / (float) total;
        int value = getValue();
        int progress = 0; 
        if (value == max) {
            progress = w - 1;
        } else {
            progress = (int) (dx * getValue());            
        }

        g2d.setColor(progressColor);
        g2d.fillRect(1, 1, progress, h - 1);

        // A gradient over the progress fill
        g2d.setPaint(gradient);
        g2d.setComposite(transparent);
        g2d.fillRect(1, 1, w - 1, (h >> 1));
        final float FACTOR = 0.20f;
        g2d.fillRect(1, h - (int) (h * FACTOR), w - 1, (int) (h * FACTOR));

        if (isEnabled()) {
            for (int i = h; i < w; i += h) {
                g2d.setComposite(veryTransparent);
                g2d.setColor(Color.GRAY);
                g2d.drawLine(i, 1, i, h - 1);
                g2d.setColor(Color.WHITE);
                g2d.drawLine(i + 1, 1, i + 1, h - 1);
            }
        } else {
            for (int i = 0; i < w; i += h) {
                g2d.setComposite(veryTransparent);
                g2d.setColor(Color.RED);
                g2d.drawLine(i, h - 1, i + h, 1);
                g2d.setColor(Color.WHITE);
                g2d.drawLine(i + 1, h - 1, i + 1 + h, 1);
            }            
        }
    }

    public void setInsets(int top, int left, int bottom, int right) {
        insets[TOP_INSET] = top;
        insets[LEFT_INSET] = left;
        insets[BOTTOM_INSET] = bottom;
        insets[RIGHT_INSET] = right;
    }

    public void setPercentStringVisible(boolean percentStringVisible) {
        this.percentStringVisible = percentStringVisible;
    }

    @Override
    protected void paintBorder(Graphics g) {
    }

    @Override
    public void validate() {
        int w = getWidth();
        int h = getHeight();

        super.validate();
        if (oldWidth != w || oldHeight != h) {
            oldWidth = w;
            oldHeight = h;
            gradient = null;
        }
    }

    @Override
    public void setMaximum(int n) {
        super.setMaximum(n);
        maxPercentString = Integer.toString(n, 10) + "%";
    }

    public void setDisplaySize(int width, int height) {
        displayWidth = width;
        displayHeight = height;
    }

    public Color getProgressColor() {
        return progressColor;
    }

    public void setProgressColor(Color progressColor) {
        this.progressColor = progressColor;
    }
}

Here is a test program for the component:

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

public class T extends JFrame {
    public T() {
        super();
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLayout(null);
        this.setSize(350, 75);
        HumanProgressBar p = new HumanProgressBar();
        p.setValue(50);
        p.setBounds(15, 15, 300, 15);
        this.add(p);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new T();
            }
        });
    }
}

enter image description here

higuaro
  • 15,730
  • 4
  • 36
  • 43
  • 1
    +1 good example. please use SwingUtilities.invokeLater for bringup swing. – vels4j Dec 26 '12 at 05:56
  • thanks, it kind of helps. just this needs to be a very simple count down from say 20 to 0 that fills an entire jpanel at the bottom of a screen. every second, a section of the bar is taken away until the time runs out. – KrazyKat89 Dec 26 '12 at 06:31
  • Very nice, if OP didnt say without JProgressBar class – David Kroukamp Dec 27 '12 at 09:21
3

You might be able to adapt ProgressIcon, illustrated here in the tabs of a JTabbedPane.

image

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
2

+1 to AndrewThompsons comment.

Here is a short example I made, not the best but shows the logic needed to create your own JProgressBar from scratch by using JPanel:

enter image description here

it can also be set to indeterminate:

enter image description here

via uncommenting:

    myProgressBar.setBackground(new Color(0, 255, 0, 127));
    myProgressBar.setIndeterminate(true); //if progress unknown show ball moving from side to side

CustomProgressBarTest.java:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.border.LineBorder;

public class CustomProgressBarTest {

    public CustomProgressBarTest() {
        createAndShowGui();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new CustomProgressBarTest();
            }
        });
    }

    private void createAndShowGui() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final MyProgressBar myProgressBar = new MyProgressBar(0, 100);
        myProgressBar.setProgressColor(new Color(0, 255, 0, 127));
        //myProgressBar.setIndeterminate(true); //if progress unknown show ball moving from side to side

        JPanel dummyPanel = new JPanel() {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(300, 300);
            }
        };

        dummyPanel.add(new JLabel("DummyPanel"));

        frame.add(dummyPanel);

        frame.add(myProgressBar, BorderLayout.SOUTH);

        frame.pack();
        frame.setVisible(true);

        //create timer to decrease progressbar
        createAndStartDecrementTimer(myProgressBar);

        //create timer to increase progressbar
        //myProgressBar.setValue(0);//set to 0 so we can increment
        //createAndStartIncrementTimer(myProgressBar);
    }

    private void createAndStartIncrementTimer(final MyProgressBar myProgressBar) {
        Timer progressBarIncrementTimer = new Timer(100, new AbstractAction() {
            int count = 0;

            @Override
            public void actionPerformed(ActionEvent ae) {
                if (count == 100) {
                    System.out.println("Done");
                    ((Timer) ae.getSource()).stop();
                } else if (count < 100) {
                    //System.out.println("Here");
                    count++;
                    myProgressBar.setValue(count);
                }
            }
        });
        progressBarIncrementTimer.start();
    }

    private void createAndStartDecrementTimer(final MyProgressBar myProgressBar) {
        Timer progressBArCountDownTimer = new Timer(100, new AbstractAction() {
            int count = 100;

            @Override
            public void actionPerformed(ActionEvent ae) {
                if (count == 0) {
                    System.out.println("Done");
                    ((Timer) ae.getSource()).stop();
                } else if (count > 0) {
                    count--;
                    myProgressBar.setValue(count);
                    System.out.println(myProgressBar.getValue());
                }
            }
        });
        progressBArCountDownTimer.start();
    }
}

class MyProgressBar extends JPanel {

    private final int minValue, maxValue;
    private boolean indeterminate = false;
    private int currentValue;
    private ArrayList<Rectangle> rects = new ArrayList<>();
    private Color PROGRESS_COLOR = Color.blue;
    private int removeValue = 0;
    private Timer indeterminateTimer;
    private int x = 0, y = 0, ballSize = 25;
    private boolean changeDirection = false;

    public MyProgressBar(int min, int max) {
        indeterminateTimer = new Timer(50, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                repaint();
            }
        });
        maxValue = max;
        minValue = min;
        currentValue = maxValue;
        setBorder(new LineBorder(Color.BLACK));
    }

    @Override
    protected void paintComponent(Graphics grphcs) {
        super.paintComponent(grphcs);
        Graphics2D g2d = (Graphics2D) grphcs;

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        if (!indeterminate) {//if normal progress bar
            rects.clear();
            int rectWidths = getWidth() / maxValue;
            int startingX = 0;

            if (currentValue < maxValue) {//we started off with a value less than the max
                for (int i = minValue; i < currentValue; i++) {
                    rects.add(new Rectangle(startingX, 0, rectWidths, getHeight()));
                    startingX += rectWidths;
                }
            } else {
                for (int i = minValue; i < (maxValue - removeValue); i++) {
                    rects.add(new Rectangle(startingX, 0, rectWidths, getHeight()));
                    startingX += rectWidths;
                }
            }

            for (Rectangle r : rects) {
                g2d.setColor(PROGRESS_COLOR);
                g2d.fillRect(r.x, r.y, r.width, r.height);
            }
        } else {//if indeterminate
            if (!indeterminateTimer.isRunning()) {
                indeterminateTimer.start();
            }
            g2d.setColor(PROGRESS_COLOR);
            if (!changeDirection) {
                if (x + 10 < getWidth() - (ballSize / 2)) {
                    x += 10;
                } else {
                    changeDirection = true;
                }
            } else if (changeDirection) {
                if (x + 10 > 0) {
                    x -= 10;
                } else {
                    changeDirection = false;
                }
            }
            g2d.fillOval(x, y, ballSize, getHeight());
        }
    }

    int getValue() {
        return currentValue;
    }

    public void setIndeterminate(boolean indeterminate) {
        this.indeterminate = indeterminate;
    }

    void setValue(int value) {
        if (value > maxValue) {
            return;
        }
        if (value < minValue) {
            return;
        }
        if (value < currentValue) {
            removeValue++;
        } else {
            int rem = value - currentValue;
            removeValue -= rem;
        }
        currentValue = value;
        repaint();
    }

    void setProgressColor(Color c) {
        PROGRESS_COLOR = c;
    }

    Color getProgressColor() {
        return PROGRESS_COLOR;
    }
}
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
  • 2
    `myProgressBar.setBackground(Color.GREEN);` That might better be `myProgressBar.setBackground(new Color(0,255,0,127)); // partially transparent` since it presumably appears over an active game play area. – Andrew Thompson Dec 27 '12 at 09:32
  • 1
    @AndrewThompson +1 updated my code to fit above, with a few extras like `setIndeterminate(..)` and `getValue(..)` to make it more `JProgressBar` like :P – David Kroukamp Dec 27 '12 at 11:01
  • `protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.gray); int width = getWidth(); g.fillRect(0, 0, width, 20); for (int i = maxValue; i > 0; --i) { int rectWidth = width / maxValue; int newWidth = width - rectWidth; g.setColor(Color.green); g.fillRect(0, 0, newWidth, 20);` hi, I borrowed but modified alot of your code but i just can't seem to get mine to work. can you see where i might be going wrong in my paint components?? – KrazyKat89 Dec 27 '12 at 14:29
  • @KrazyKat89 that code is not enough you would need more. I.e everything in the if(!indeterminate) block, id suggest taking my class and get it working in your application than modify it as needed. – David Kroukamp Dec 27 '12 at 14:37
  • ok might be a simple question but i seem to have it working now but i want the height of it to be maybe triple what it is. nothing i try is working. where would i have to put the resize in? – KrazyKat89 Dec 28 '12 at 00:21
  • @KrazyKat89 where would you put resize? resize to resize what? Also our see in your edited question you override `paint(..)` please check I do not override that method, rather `paintComponent` – David Kroukamp Dec 28 '12 at 05:12
  • @DavidKroukamp is it supposed to be override paint() or override paintComponent()? i have override paintComponent(). what I wanted to make bigger was the progress bar. i wanted to make the height of it maybe 3 times what it is in your example. – KrazyKat89 Dec 28 '12 at 08:47
  • @KrazyKat89 if you want to change the size override getPreferredSize like I have done with dummy JPanel. And return an appropriate dimensions. – David Kroukamp Dec 28 '12 at 08:54
0

Here is what I made for my game. Feel free to utilize this anyone who may find this question like I did.

Enjoy.

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;

import javax.swing.JPanel;

import com.jayavon.game.client.MyClient;

public class CustomJProgressBar extends JPanel {
    private static final long serialVersionUID = 1L;
    private Color color;
    private int width, height;
    private double minimum = 0.0;
    private double maximum = 100.0;
    private double value = 100.0;
    private Font font = MyClient.theme_font.deriveFont(Font.PLAIN, 12);

    public CustomJProgressBar(Color color) {
        super();
        this.color = color;
        setBounds(0, 0, width, height);
        setFont(font);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        //border
        g.setColor(MyClient.THEME_LIGHT_TEXT);
        g.drawRect(0, 0, getWidth()-1, getHeight()-1);

        //progress
        int drawAmount = (int) (((value - minimum) / (maximum - minimum)) * getWidth());
        g.setColor(color);
        g.fillRect(1, 1, drawAmount-2, getHeight()-2); //-2 to account for border

        //string painting
        String stringToPaint = (int)value + "/" + (int)maximum;
        Canvas c = new Canvas();
        FontMetrics fm = c.getFontMetrics(font);
        final int stringWidth = fm.stringWidth(stringToPaint);
        final int stringHeight = fm.getHeight();
        g.setColor(MyClient.THEME_LIGHT_TEXT);
        g.drawString(stringToPaint, (getWidth()/2) - (stringWidth/2), ((getHeight()/2) + (stringHeight/2))-2); //-2 to account for border
    }

    public void setColor(Color _color){
        this.color = _color;
    }

    public void setMinimum(double _minimum){
        this.minimum = _minimum;
    }

    public void setMaximum(double _maximum){
        this.maximum = _maximum;
    }

    public void setValue(double _value){
        this.value = _value;
    }
}
KisnardOnline
  • 653
  • 4
  • 16
  • 42