Advertisements

Chat bubble in java swing

chatBubble

This article will explain you “how to draw chat bubble in  java swing application?” Chat bubble is same as call-out or thought bubble. Today most of the chat application is showing conversion in this format, so this article will help you to do the same in desktop application made in java swing.

Following class is used to draw first chat bubble: (Arrow at the left side of bubble)

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JPanel;
/**
 * @author harsh
 */
public class LeftArrowBubble extends JPanel {
   private static final long serialVersionUID = -5389178141802153305L;
   private int radius = 10;
   private int arrowSize = 12;
   private int strokeThickness = 3;
   private int padding = strokeThickness / 2;
   @Override
   protected void paintComponent(final Graphics g) {
      final Graphics2D g2d = (Graphics2D) g;
      g2d.setColor(new Color(0.5f, 0.8f, 1f));
      int x = padding + strokeThickness + arrowSize;
      int width = getWidth() - arrowSize - (strokeThickness * 2);
      int bottomLineY = getHeight() - strokeThickness;
      g2d.fillRect(x, padding, width, bottomLineY);
      g2d.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING,   RenderingHints.VALUE_ANTIALIAS_ON));
      g2d.setStroke(new BasicStroke(strokeThickness));
      RoundRectangle2D.Double rect = new RoundRectangle2D.Double(x, padding, width, bottomLineY, radius, radius);
      Polygon arrow = new Polygon();
      arrow.addPoint(20, 8);
      arrow.addPoint(0, 10);
      arrow.addPoint(20, 12);
      Area area = new Area(rect);
      area.add(new Area(arrow));
      g2d.draw(area);
   }
}

Following code is to draw second chat bubble. (Arrow at the right side of bubble):

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JPanel;
/**
 * @author harsh
 */
public class RightArrowBubble extends JPanel {
   private static final long serialVersionUID = -5389178141802153305L;
   private int strokeThickness = 3;
   private int radius = 10;
   private int arrowSize = 12;
   private int padding = strokeThickness / 2;
   @Override
   protected void paintComponent(final Graphics g) {
      final Graphics2D g2d = (Graphics2D) g;
      g2d.setColor(new Color(0.5f, 0.5f, 1f));
      int bottomLineY = getHeight() - strokeThickness;
      int width = getWidth() - arrowSize - (strokeThickness * 2);
      g2d.fillRect(padding, padding, width, bottomLineY);
      RoundRectangle2D.Double rect = new RoundRectangle2D.Double(padding, padding, width, bottomLineY,  radius, radius);
      Polygon arrow = new Polygon();
      arrow.addPoint(width, 8);
      arrow.addPoint(width + arrowSize, 10);
      arrow.addPoint(width, 12);
      Area area = new Area(rect);
      area.add(new Area(arrow));
      g2d.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
      g2d.setStroke(new BasicStroke(strokeThickness));
      g2d.draw(area);
   }
}

And here is the code for using above 2 classes:

import java.awt.HeadlessException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
 * @author harsh
 */
public class TestPanel extends JPanel {
	private static final long serialVersionUID = 9029457020704524363L;
	private JLabel messageLbl1, userImageLbl1, messageLbl, userImageLbl;
    private JPanel msgPanel1, msgPanel;
    String userImageUrl = "http://cdn1.iconfinder.com/data/icons/nuvola2/22x22/apps/personal.png";
    public TestPanel() throws MalformedURLException {
        userImageLbl = new JLabel();
        msgPanel = new LeftArrowBubble();
        messageLbl = new JLabel();
        messageLbl1 = new JLabel();
        msgPanel1 = new RightArrowBubble();
        userImageLbl1 = new JLabel();

        userImageLbl.setIcon(new ImageIcon(new URL(userImageUrl)));
        messageLbl.setText("Hi, How are you?");

        GroupLayout msgPanelLayout = new GroupLayout(msgPanel);
        msgPanel.setLayout(msgPanelLayout);
        msgPanelLayout.setHorizontalGroup(
            msgPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(msgPanelLayout.createSequentialGroup()
                .addGap(21, 21, 21)
                .addComponent(messageLbl)
                .addContainerGap(162, Short.MAX_VALUE))
        );
        msgPanelLayout.setVerticalGroup(
            msgPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(msgPanelLayout.createSequentialGroup()
                .addComponent(messageLbl)
                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        messageLbl1.setIcon(new ImageIcon(new URL(userImageUrl)));
        userImageLbl1.setText("I'm Good.");

        GroupLayout jPanel1Layout = new GroupLayout(msgPanel1);
        msgPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                .addContainerGap(171, Short.MAX_VALUE)
                .addComponent(userImageLbl1)
                .addGap(22, 22, 22))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addComponent(userImageLbl1)
                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        GroupLayout layout = new GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(userImageLbl)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
                    .addComponent(msgPanel1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(msgPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addComponent(messageLbl1)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                    .addComponent(userImageLbl)
                    .addComponent(msgPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                    .addComponent(messageLbl1)
                    .addComponent(msgPanel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addContainerGap(22, Short.MAX_VALUE))
        );
    }
    public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				try {
					JOptionPane.showMessageDialog(null, new TestPanel());
				} catch (HeadlessException e) {
					e.printStackTrace();
				} catch (MalformedURLException e) {
					e.printStackTrace();
				}
			}
		});
	}
}

At least try it once and feel free to comment about it. 🙂

Advertisements

Infinite progress bars in swing

Following are some infinite progress bars built in java swing 2d using JPanel’s paintComponent(Graphics g) method.

Windows XP

I have seen this kind of loading icon while setting up windows XP, you might have also seen it:
xp_loader
So how one can simulate same in swing? Here is the answer:

/**
 * Some custom infinite progress bars in JPanel using Graphics2D object.
 * @author harsh
 */
public class CustomInfiniteProgressBar extends JPanel {
    private static final long serialVersionUID = 223086939802246968L;
    private static final int DELAY = 100;
    private static final int MAX_AMOUNT = 100;
    private static final int SPACE = 30;
    private static final int NUMBER_OF_RECTS = 5;
    private Timer timer;
    private int value = 0, darkRect = 0;

    public CustomInfiniteProgressBar() {
        timer = new Timer(DELAY, new TimerActionListener());
        timer.start();
    }

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

        // draw rectangular progress
        int paddingToFrameBorders = 10; //dummy values for position
        int smallerSize = 5, largerSize = 10; //dummy values for rectangle size

        int rectX, rectY;
        for (int i = 0; i < NUMBER_OF_RECTS; i++) {
            rectX = paddingToFrameBorders + i * SPACE;
            rectY = paddingToFrameBorders;
            if(darkRect == i) {
                g2d.fillRect(rectX, rectY, largerSize, largerSize);
            } else {
                // to center smaller rectangle respective to larger rectangle.
                rectX += (largerSize - smallerSize) / 2;
                rectY += (largerSize - smallerSize) / 2;

                g2d.drawRect(rectX, rectY, smallerSize, smallerSize);
            }
        }
    }

    /**
    * Action Listener of Timer.
    */
    private class TimerActionListener implements ActionListener {
        public void actionPerformed(ActionEvent event) {
            value++;
            if(value == MAX_AMOUNT) { // you can have some condition here to stop the timer.
                timer.stop();
            }
            darkRect = (value % NUMBER_OF_RECTS);
            repaint();
        }
    }
}

Circular infinite progress bar

circles_loading

For this you just have to replace rectangle drawing logic to circle drawing logic and its done:

// global constants
private static final int RADIUS = 30;
private static final int NUMBER_OF_CIRCLES = 10;

private int darkCircle = 0;

//inside paintComponent(g) method
int centerX, centerY; centerX = centerY = 75; //dummy values for position
int circularX, circularY;
for (int i = 0; i < NUMBER_OF_CIRCLES; i++) {
    circularX = centerX + (int) (RADIUS * Math.sin((360 / NUMBER_OF_CIRCLES) * i * 3.14 / 180));
    circularY = centerY + (int) (RADIUS * Math.cos((360 / NUMBER_OF_CIRCLES) * i * 3.14 / 180));
    if(darkCircle == i) {
        g2d.fillOval(circularX, circularY, 10, 10);
    } else {
        g2d.drawOval(circularX, circularY, 10, 10);
    }
}

// in timer action class
darkCircle = NUMBER_OF_CIRCLES - 1 - (value % NUMBER_OF_CIRCLES);

Another example of such progress bar:
circular_loaing_2

for this use following code inside paintComponent(g) everything else will same as above:

//inside paintComponent(g) method
BasicStroke drawingStroke = new BasicStroke(3, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{9}, 0);
g2d.setStroke(drawingStroke);
for (int i = 0; i < NUMBER_OF_CIRCLES; i++) {
    circularX = centerX + (int) (RADIUS * Math.sin((360 / NUMBER_OF_CIRCLES) * i * 3.14 / 180));
    circularY = centerY + (int) (RADIUS * Math.cos((360 / NUMBER_OF_CIRCLES) * i * 3.14 / 180));
    if(darkCircle == i) {
        g2d.setColor(new Color(100, 200, 150));
        g2d.drawLine(circularX, circularY, circularX + 10, circularY + 10);
    } else {
        g2d.setColor(Color.black);
        g2d.drawLine(circularX, circularY, circularX + 10, circularY + 10);
    }
}

Arrow shape for progress bar

I’m not sure if following can be used as progress bar, but it can be used for highlighting something or some similar kind of task.
arrow loading highlighting
The code for this as follows:

// inside paintComponent(g) method
for (int i = 0; i < NUMBER_OF_RECTS; i++) {
    if(darkRect == i)
        g2d.fill(getArrowShape(i * 10, 50, 150));
    else
        g2d.draw(getArrowShape(i * 10, 50, 150));
}

// the getArrowShape method
/**
 * Returns arrow shape(a triangle).
 * Points are:
 * A (x + i, y)
 * | \
 * |  \
 * |   \
 * |    C ((x + 10) + i, (y + 10))
 * |   /
 * |  /
 * | /
 * B (x + i, (y + 20))
*/
private Shape getArrowShape(int i, int x, int y) {
    final Polygon result = new Polygon();
    result.addPoint(x + i, y); // A
    result.addPoint(x + i, (y + 20)); // B
    result.addPoint((x + 10) + i, (y + 10)); // C
    return result;
}

That’s all for now.
Hope You like it. 🙂

%d bloggers like this: