JProgressBar text overflow
Asked Answered
B

2

2

My program writes text in a JProgressBar. The problem is the text is wider than the JProgressBar's width.

I have already changed the JProgressBar's height to be able to write the text on two lines but I don't want to the change the width.

How to change the JProgressBar's overflow to make the text going back to the next line if it is too wide?

I hope this is clear enough :)

Here is what I would like:

Overflow in JProgressBar

Thanks


EDIT

After @mKorbel reply the result looks like this:

enter image description here

The label works quite fine but why those strips?

My code:

// Construct progress bar
JProgressBar progressBar = new JProgressBar(0, 100);
// Set progressBar color
progressBar.setForeground(new Color(0,176,80));

// Edit progress bar height
Dimension prefSize = progressBar.getPreferredSize();
prefSize.height = 50;
progressBar.setPreferredSize(prefSize);

// Set the layout
progressBar.setLayout(new BorderLayout(5, 5));

// Set progress bar value
progressBar.setValue(38);

// Construct the label
JLabel progressLabel = new JLabel("<html>I have already changed the JProgressBar's height to be able to write the text on two lines but I don't want to the change the width.</html>");
// Set alignment
progressLabel.setHorizontalAlignment(JLabel.CENTER);
progressLabel.setVerticalAlignment(JLabel.CENTER);

// Set the borders
progressLabel.setBorder(new EmptyBorder(15, 15, 15, 15));

// Change the font
font = progressLabel.getFont();
font = font.deriveFont(Font.BOLD, 12);
progressLabel.setFont(font);

// Add label to the progress bar
progressBar.add(progressLabel, BorderLayout.CENTER);

// Add progress bar to the frame
frame.add(progressBar);
Bounder answered 21/8, 2013 at 7:0 Comment(7)
One suggestion is to bind the font size of the text with the width and make a function so that whenever the text is added the fontsize is calculated according to the width it has to be displayed in :)Intercommunion
It could be a solution but if there are too many characters the text may be very small and not readable.Bounder
Yes that is true @MAxbesterIntercommunion
this could be possible only by using JLayer, then there you can to paint JProgressBar under JLabel placed to JPanel,Steinke
just curious: how comes the text needs wrapping?Headwaters
my first thought was using html, but astonishingly (for me) the progressbar doesn't support it ...Headwaters
@Steinke the program is developed with Java 6. It seems JLayer is not available. If I'm wrong, could you provide some code on how to do this?Bounder
S
4

the program is developed with Java 6. It seems JLayer is not available. If I'm wrong, could you provide some code on how to do this?

  • could you provide some code on how to do this? --- > JLayer & JProgressBar by @aterai, for more ideas see his blog, for Java6 you can to use JXLayer

  • or with very similair logics by using GlassPane

enter image description hereenter image description hereenter image description here

some notes

  • should be used GBC instead of NullLayout

  • can be nicer with added Icon or transparent background

  • (by add LayoutManager to JLabel) there can be placed bunch of JComponents with the same effect as for JPanel

for example

import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.JRadioButton;
import javax.swing.UIManager;
//https://mcmap.net/q/1467516/-jprogressbar-low-values-will-not-be-displayed
public class ProgressSample {

    private JFrame frame = new JFrame("GlassPane instead of JLayer");
    private JLabel label;
    private GridBagConstraints gbc = new GridBagConstraints();
    private JProgressBar progressSeven;

    public ProgressSample() {
        frame.setLayout(new FlowLayout());
        frame.add(new JButton("test"));
        frame.add(new JCheckBox("test"));
        frame.add(new JRadioButton("test"));
        // Nothing is displayed if value is lover that 6
        JProgressBar progressSix = new JProgressBar(0, 100);
        progressSix.setValue(2);
        frame.add(progressSix);
        // but this works value is higher that 6
        progressSeven = new JProgressBar(0, 100);
        progressSeven.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentMoved(ComponentEvent e) {
                label.setBounds(
                        (int) progressSeven.getBounds().getX(),
                        (int) progressSeven.getBounds().getY(),
                        label.getPreferredSize().width,
                        label.getPreferredSize().height);
            }
        });
        progressSeven.setValue(7);
        frame.add(progressSeven);
        label = new JLabel();
        label.setText("<html> Concurency Issues in Swing<br>"
                + " never to use Thread.sleep(int) <br>"
                + " durring EDT, simple to freeze GUI </html>");
        label.setPreferredSize(new Dimension(label.getPreferredSize().width, label.getPreferredSize().height));
        Container glassPane = (Container) frame.getRootPane().getGlassPane();
        glassPane.setVisible(true);
        glassPane.setLayout(null);
        glassPane.add(label, gbc);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        ProgressSample dialogTest = new ProgressSample();
    }
}

EDIT

  • comments

my first thought was using html, but astonishingly (for me) the progressbar doesn't support it ... by @kleopatra

and

I think my question may not be clear enough. I don't want the text to exceed the JProgressBar borders. Plus, I don't want to insert manually line returns (ie no
). I added a picture of what I want. by @Maxbester

  • result is to use JProgressBar as Container, put there proper LayoutManager, overlay JProgressBar by JLabel

enter image description here

  • enhancements, to set EmptyBorder for JLabel, e.g. label.setBorder(new EmptyBorder(15, 15, 15, 15));

enter image description here

EDIT2 (Icon is, can be semi_transparent too, can overlay JProgressBar)

enter image description here

code could be something like as

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;

public class JProgressBarWithJLabel {

    private JFrame frame = new JFrame("JLabel in JProgressBar");
    private JLabel label;
    private JProgressBar progressSeven;

    public JProgressBarWithJLabel() {
        progressSeven = new JProgressBar(0, 100){
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(300, 60);
            }
        };
        progressSeven.setValue(38);
        progressSeven.setLayout(new BorderLayout(5, 5));
        label = new JLabel();
        label.setHorizontalTextPosition(JLabel.CENTER);
        label.setVerticalTextPosition(JLabel.CENTER);
        label.setBorder(new EmptyBorder(15, 15, 15, 15));
        label.setText("<html>I have already changed the JProgressBar's height "
                + "to be able to write the text on two lines but I don't want "
                + "to the change the width.</html>");
        progressSeven.add(label, BorderLayout.CENTER);
        frame.add(progressSeven);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        try {
            for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(laf.getName())) {
                    UIManager.setLookAndFeel(laf.getClassName());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new JProgressBarWithJLabel();
            }
        });
    }
}

EDIT3:

default stripping for WindowsClassicLookAndFeel (Icon isn't semi_transparent)

enter image description here

Steinke answered 21/8, 2013 at 10:40 Comment(6)
I think my question may not be clear enough. I don't want the text to exceed the JProgressBar borders. Plus, I don't want to insert manually line returns (ie no <br>). I added a picture of what I want. Anyway thanks for your reply.Bounder
Great code! Thanks! However I have some strips on the JProgressBar. See my question.Bounder
Actually it seems to be caused by the Windows Classic look and feel. Because if I switch to the Windows7 appearance, the strips disappear.Bounder
only in WindowsClassicLookAndFeel doeasn't matter if is used as container or for original untouched UISteinke
All things considered it is probably the default Windows Classic behaviour.Bounder
right, thanks for your nice Thread, and bases for my questionSteinke
M
0

The available answers didn't satisfy me. Thus I implemented the following alternative solution for my own needs.

import javax.swing.JProgressBar;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;

public class MultilineProgressBar extends JProgressBar
{
    private static final String FONT_NAME = "Dialog";
    private static final int FONT_SIZE = 12;

    private static final int INTERLINE_COEFFICIENT = 2;
    private static final int NEWLINE_OFFSET = FONT_SIZE * INTERLINE_COEFFICIENT;
    private static final int CENTERING_DIVISOR = 2;


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

        final String componentString = getString();

        int i = componentString.indexOf('\n');
        if (i == -1)
            return;

        // Draw first line of the component's string
        String currentString = componentString.substring(0, i);
        Rectangle2D stringBounds = getFontMetrics(getFont()).getStringBounds(currentString, graphics);
        graphics.setFont(new Font(FONT_NAME, Font.BOLD, FONT_SIZE));
        graphics.setColor(Color.WHITE);
        graphics.drawString(currentString,
                            (int) (getWidth() - stringBounds.getWidth()) / CENTERING_DIVISOR,
                            (int) (getHeight() - stringBounds.getHeight()) / CENTERING_DIVISOR);

        ++i;
        if (i >= componentString.length())
            return;

        // Draw second line of the component's string
        currentString = componentString.substring(i);
        stringBounds = getFontMetrics(getFont()).getStringBounds(currentString, graphics);
        graphics.drawString(currentString,
                            (int) (getWidth() - stringBounds.getWidth()) / CENTERING_DIVISOR,
                            (int) ((getHeight() - stringBounds.getHeight()) / CENTERING_DIVISOR) + NEWLINE_OFFSET);
    }
}
Methedrine answered 16/10, 2015 at 16:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.