How to make a Round Rectangle JTextField? - java

I want to make a round rectangle JTextField. I write a sub class of AbstractBorder to realize it.But I run into some problems.
My requirement is:
What I get is:
My code is :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.AbstractBorder;
import javax.swing.border.EmptyBorder;
public class JTextFieldTest {
JTextField textField;
boolean activate = false;
public void createUI(){
JFrame frame = new JFrame("Test JTextField");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
MainPanel mainPanel = new MainPanel();
frame.add(mainPanel,BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
JTextFieldTest jTextFieldTest = new JTextFieldTest();
jTextFieldTest.createUI();
}
#SuppressWarnings("serial")
class MainPanel extends JPanel{
public MainPanel(){
textField = new JTextField("Please input:");
Font fieldFont = new Font("Arial", Font.PLAIN, 20);
textField.setFont(fieldFont);
textField.setBackground(Color.white);
textField.setForeground(Color.gray.brighter());
textField.setColumns(30);
textField.setBorder(BorderFactory.createCompoundBorder(new CustomeBorder(),
new EmptyBorder(new Insets(10, 20, 10, 20))));
textField.addActionListener(new FieldListener());
textField.addMouseListener(new FieldMouseListener());
add(textField,BorderLayout.CENTER);
setBackground(Color.blue);
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
}
}
#SuppressWarnings("serial")
class CustomeBorder extends AbstractBorder{
#Override
public void paintBorder(Component c, Graphics g, int x, int y,
int width, int height) {
// TODO Auto-generated method stub
super.paintBorder(c, g, x, y, width, height);
g.setColor(Color.black);
g.drawRoundRect(x, y, width, height, 20, 20);
}
}
class FieldListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println(textField.getText());
}
}
class FieldMouseListener implements MouseListener{
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
if(activate == false){
textField.setText("");
}
activate = true;
textField.setForeground(Color.black);
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
}
I can get another effect by using
textField.setOpaque(false);
g.setColor(Color.white);
g.drawRoundRect(x, y, width - 1, height - 1, 20, 20);
Another effect is:
In sum, what can I do to realize my requirement?
#Arijit, it's the effect of your solution when it runs on my computer.

Use a TextBubbleBorder.
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.AbstractBorder;
class TextBubbleBorder extends AbstractBorder {
private Color color;
private int thickness = 4;
private int radii = 8;
private int pointerSize = 7;
private Insets insets = null;
private BasicStroke stroke = null;
private int strokePad;
private int pointerPad = 4;
RenderingHints hints;
TextBubbleBorder(
Color color) {
this(color, 4, 8, 7);
}
TextBubbleBorder(
Color color, int thickness, int radii, int pointerSize) {
this.thickness = thickness;
this.radii = radii;
this.pointerSize = pointerSize;
this.color = color;
stroke = new BasicStroke(thickness);
strokePad = thickness/2;
hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int pad = radii + strokePad;
int bottomPad = pad + pointerSize + strokePad;
insets = new Insets(pad,pad,bottomPad,pad);
}
#Override
public Insets getBorderInsets(Component c) {
return insets;
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
return getBorderInsets(c);
}
#Override
public void paintBorder(
Component c,
Graphics g,
int x, int y,
int width, int height) {
Graphics2D g2 = (Graphics2D)g;
int bottomLineY = height-thickness-pointerSize;
RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
0+strokePad,
0+strokePad,
width-thickness,
bottomLineY,
radii,
radii
);
Polygon pointer = new Polygon();
// left point
pointer.addPoint(
strokePad+radii+pointerPad,
bottomLineY);
// right point
pointer.addPoint(
strokePad+radii+pointerPad+pointerSize,
bottomLineY);
// bottom point
pointer.addPoint(
strokePad+radii+pointerPad+(pointerSize/2),
height-strokePad);
Area area = new Area(bubble);
area.add(new Area(pointer));
g2.setRenderingHints(hints);
Area spareSpace = new Area(new Rectangle(0,0,width,height));
spareSpace.subtract(area);
g2.setClip(spareSpace);
g2.clearRect(0,0,width,height);
g2.setClip(null);
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(area);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTextField o = new JTextField(
"The quick brown fox jumps over the lazy dog!");
o.setBorder(new TextBubbleBorder(Color.MAGENTA.darker(),2,4,0));
JOptionPane.showMessageDialog(null, o);
}
});
}
}

I have a solution and I don't need to use
textField.setOpaque(false);
I just use the following code to fill the space.
#SuppressWarnings("serial")
class CustomeBorder extends AbstractBorder{
#Override
public void paintBorder(Component c, Graphics g, int x, int y,
int width, int height) {
// TODO Auto-generated method stubs
super.paintBorder(c, g, x, y, width, height);
Graphics2D g2d = (Graphics2D)g;
g2d.setStroke(new BasicStroke(10));
g2d.setColor(new Color(68,184,224));
g2d.drawRoundRect(x, y, width - 1, height - 1, 20, 20);
}
}
You should adjust the width of BasicStroke based on your JTextField.
The final result is:

Use this:
JTextField Mytxtfield = new JTextField()
{protected void paintComponent( Graphics g )
{
if ( !isOpaque( ) )
{
super.paintComponent( g );
return;
}
Graphics2D g2d = (Graphics2D)g;
GradientPaint gp = new GradientPaint(
0, 0, color1,
0, 20, color2);
g2d.setPaint( gp );
// g2d.fillRect( 0, 0, w, h );
g2d.fillRoundRect(0, 0, getWidth()-1, getHeight()-1, 10, 10);
setOpaque( false );
super.paintComponent( g );
setOpaque( true );
}};
Full Working code:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Shape;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
public class DBconnection extends JFrame {
private JPanel contentPane;
private JTextField textFieldHost;
private Color color2 = Color.white;
private Color color1 = Color.white;
public DBconnection() throws SAXException, IOException, ParserConfigurationException {
setTitle("Connect To MDM Database");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(450, 200, 410, 280);
contentPane = new JPanel();
contentPane.setBackground(SystemColor.inactiveCaption);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
GridBagLayout gbl_contentPane = new GridBagLayout();
gbl_contentPane.columnWidths = new int[]{0, 0, 0, 0};
gbl_contentPane.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
gbl_contentPane.columnWeights = new double[]{0.0, 0.0, 1.0, Double.MIN_VALUE};
gbl_contentPane.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
contentPane.setLayout(gbl_contentPane);
textFieldHost = new JTextField()
{protected void paintComponent( Graphics g )
{
if ( !isOpaque( ) )
{
super.paintComponent( g );
return;
}
Graphics2D g2d = (Graphics2D)g;
GradientPaint gp = new GradientPaint(
0, 0, color1,
0, 20, color2);
g2d.setPaint( gp );
// g2d.fillRect( 0, 0, w, h );
g2d.fillRoundRect(0, 0, getWidth()-1, getHeight()-1, 10, 10);
setOpaque( false );
super.paintComponent( g );
setOpaque( true );
}};
GridBagConstraints gbc_textFieldHost = new GridBagConstraints();
gbc_textFieldHost.insets = new Insets(20, 40, 5, 0);
gbc_textFieldHost.fill = GridBagConstraints.HORIZONTAL;
gbc_textFieldHost.gridwidth=3;
gbc_textFieldHost.gridx = 2;
gbc_textFieldHost.gridy = 4;
gbc_textFieldHost.ipady=5;
contentPane.add(textFieldHost, gbc_textFieldHost);
textFieldHost.setBorder(javax.swing.BorderFactory.createEmptyBorder(2, 2,2,2));
}
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
DBconnection frame = new DBconnection();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Also by changing the value of color1 and color2, you can get a gradient effect.
I have modified your code and get this:
Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.AbstractBorder;
public class JTextFieldTest {
JTextField textField;
boolean activate = false;
public void createUI(){
JFrame frame = new JFrame("Test JTextField");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
MainPanel mainPanel = new MainPanel();
frame.add(mainPanel,BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
JTextFieldTest jTextFieldTest = new JTextFieldTest();
jTextFieldTest.createUI();
}
#SuppressWarnings("serial")
class MainPanel extends JPanel{
public MainPanel(){
textField = new JTextField("Test JTextField")
{protected void paintComponent( Graphics g )
{
if ( !isOpaque( ) )
{
super.paintComponent( g );
return;
}
Graphics2D g2d = (Graphics2D)g;
GradientPaint gp = new GradientPaint(
0, 0, Color.white,
0, 20, Color.white);
g2d.setPaint( gp );
// g2d.fillRect( 0, 0, w, h );
g2d.fillRoundRect(0, 0, getWidth()-1, getHeight()-1, 20, 20);
setOpaque( false );
super.paintComponent( g );
setOpaque( true );
}};
textField.setBorder(BorderFactory.createEmptyBorder());
Font fieldFont = new Font("Arial", Font.PLAIN, 20);
textField.setFont(fieldFont);
textField.setColumns(30);
textField.addActionListener(new FieldListener());
textField.addMouseListener(new FieldMouseListener());
add(textField,BorderLayout.CENTER);
setBackground(Color.blue);
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
}
}
class FieldListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println(textField.getText());
}
}
class FieldMouseListener implements MouseListener{
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
if(activate == false){
textField.setText("");
}
activate = true;
textField.setForeground(Color.black);
}
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
}

Related

Java AWT Draw on Translucent Frame

I am having trouble drawing on a translucent frame. When the "alphaValue" is 255 everything works as expected. But I need a translucent frame. I created a small test class below that demonstrates the problem. As you can see the "MIDDLE" rectangle appears all the time. But the "DRAW" rectangle only appears when "alphaValue" is 255. When it is <=254 you can see via print lines that the method is still called, but the image does not appear to refresh. Thank you in advance for any help.
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class TransparencyTest {
private static Point startPoint = new Point();
private static Point endPoint = new Point();
public static void main(String[] args) {
new TransparencyTest().test();
}
#SuppressWarnings("serial")
private void test() {
int alphaValue = 255;
Frame myFrame = new Frame();
myFrame.setUndecorated(true);
myFrame.setBackground(new Color(0, 0, 0, alphaValue));
myFrame.setSize(800, 800);
Panel myPanel = new Panel() {
public void paint(Graphics g) {
super.paint(g);
System.out.println("PAINT");
g.setColor(new Color(255, 0, 0, 255));
if(startPoint.equals(new Point())) {
System.out.println("MIDDLE");
g.drawRect(200, 200, 400, 400);
}
else {
System.out.println("DRAW");
g.drawRect(
(int)Math.min(startPoint.getX(), endPoint.getX()),
(int)Math.min(startPoint.getY(), endPoint.getY()),
(int)Math.abs(startPoint.getX() - endPoint.getX()),
(int)Math.abs(startPoint.getY() - endPoint.getY())
);
}
}
};
myFrame.add(myPanel);
MouseAdapter myMouseAdapter = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
endPoint = e.getPoint();
myPanel.repaint();
}
};
myPanel.addMouseListener(myMouseAdapter);
myPanel.addMouseMotionListener(myMouseAdapter);
myFrame.setVisible(true);
}
}
AWT components don't have a concept of transparency in of themselves, they are always opaque.
You have use a JPanel, which you use setOpaque to control the opacity (on or off) with. This will allow the panel to become see through and you should then be able to see the alpha affect applied directly to the frame...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TransparencyTest {
private static Point startPoint = new Point();
private static Point endPoint = new Point();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new TransparencyTest().test();
}
});
}
#SuppressWarnings("serial")
private void test() {
int alphaValue = 128;
JFrame myFrame = new JFrame();
myFrame.setUndecorated(true);
myFrame.setBackground(new Color(0, 0, 0, alphaValue));
// myFrame.setOpacity(0.1f);
myFrame.setSize(800, 800);
myFrame.setLocation(100, 100);
JPanel myPanel = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("PAINT");
g.setColor(new Color(255, 0, 0, 255));
if (startPoint.equals(new Point())) {
System.out.println("MIDDLE");
g.drawRect(200, 200, 400, 400);
} else {
System.out.println("DRAW");
g.drawRect(
(int) Math.min(startPoint.getX(), endPoint.getX()),
(int) Math.min(startPoint.getY(), endPoint.getY()),
(int) Math.abs(startPoint.getX() - endPoint.getX()),
(int) Math.abs(startPoint.getY() - endPoint.getY())
);
}
}
};
myPanel.setOpaque(false);
myFrame.add(myPanel);
MouseAdapter myMouseAdapter = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
endPoint = e.getPoint();
myPanel.repaint();
}
};
myPanel.addMouseListener(myMouseAdapter);
myPanel.addMouseMotionListener(myMouseAdapter);
myFrame.setVisible(true);
}
}

JSeparator dashed style

I am using a JSeparator in my java swing application. The normal implementation makes the separator normal line; but what I need is the separator should be dashed(like we create dashed border). Is there any way we can do that?
Thanks
To create a custom JSeparator, you can override the paint() method of BasicSeparatorUI, discussed here, and draw the line using a dashed Stroke, illustrated here.
Addendum: A more familiar approach overrides paintComponent(), as shown in the accepted answer and encapsulated conveniently in this StrokedSeparator. The variation below replaces drawLine() with draw() using a Line2D, which takes advantage of the stroke's geometry.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import static javax.swing.JSeparator.*;
/**
* #see https://stackoverflow.com/a/74657060/230513
*/
public class StrokeSepTest {
private static final int N = 10;
private void display() {
var f = new JFrame("StrokeSepTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
var stroke = new BasicStroke(8.0f, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER, 10.0f, new float[]{5.0f}, 0.0f);
var panel = new JPanel(new GridLayout(0, 1)) {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
};
panel.setBackground(Color.white);
for (int i = 0; i < N; i++) {
Color color = Color.getHSBColor((float) i / N, 1, 1);
panel.add(new StrokedSeparator(stroke, HORIZONTAL, color));
}
f.add(panel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
// #see https://stackoverflow.com/a/74657060/230513 */
private static class StrokedSeparator extends JSeparator {
private Stroke stroke;
public StrokedSeparator() {
this(new BasicStroke(1F), HORIZONTAL);
}
public StrokedSeparator(int orientation) {
this(new BasicStroke(1F), orientation);
}
public StrokedSeparator(Stroke stroke) {
this(stroke, HORIZONTAL);
}
public StrokedSeparator(Stroke stroke, int orientation) {
super(orientation);
this.stroke = stroke;
}
public StrokedSeparator(Stroke stroke, int orientation, Color color) {
super(orientation);
super.setForeground(color);
this.stroke = stroke;
}
#Override
public void paintComponent(Graphics g) {
var graphics = (Graphics2D) g;
var s = getSize();
graphics.setStroke(stroke);
graphics.setColor(getForeground());
if (getOrientation() == JSeparator.VERTICAL) {
graphics.draw(new Line2D.Double(0, 0, 0, s.height));
} else // HORIZONTAL
{
graphics.draw(new Line2D.Double(0, 0, s.width, 0));
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new StrokeSepTest()::display);
}
}
You can use the following code snippet to create a dashed line.
import java.awt.Container;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSeparator;
public class SeparatorSample {
public static void main(String args[]) {
JFrame f = new JFrame("JSeparator Sample");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container content = f.getContentPane();
content.setLayout(new GridLayout(0, 1));
JLabel above = new JLabel("Above Separator");
content.add(above);
JSeparator separator = new JSeparator() {
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g) {
for (int x = 0; x < 300; x += 15)
g.drawLine(x, 0, x + 10, 0);
}
};
content.add(separator);
JLabel below = new JLabel("Below Separator");
content.add(below);
f.setSize(300, 100);
f.setVisible(true);
}
}
With a slight modification to trashgod's answer, I found that using paintComponent() rather than paint() works very well for me:
Stroke stroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, new float[] { 5.0f },
0.0f);
JSeparator separator = new StrokedSeparator(stroke);
// Add separator to container
And here's the StrokedSeparator class:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import javax.swing.JSeparator;
public class StrokedSeparator extends JSeparator {
private static final long serialVersionUID = 1L;
private Stroke stroke;
public StrokedSeparator() {
this(new BasicStroke(1F), HORIZONTAL);
}
public StrokedSeparator(int orientation) {
this(new BasicStroke(1F), orientation);
}
public StrokedSeparator(Stroke stroke) {
this(stroke, HORIZONTAL);
}
public StrokedSeparator(Stroke stroke, int orientation) {
super(orientation);
this.stroke = stroke;
}
#Override
public void paintComponent(Graphics g) {
Dimension s = getSize();
Graphics2D graphics = (Graphics2D) g;
graphics.setStroke(stroke);
if (getOrientation() == JSeparator.VERTICAL) {
graphics.setColor(getForeground());
graphics.drawLine(0, 0, 0, s.height);
graphics.setColor(getBackground());
graphics.drawLine(1, 0, 1, s.height);
} else // HORIZONTAL
{
graphics.setColor(getForeground());
graphics.drawLine(0, 0, s.width, 0);
graphics.setColor(getBackground());
graphics.drawLine(0, 1, s.width, 1);
}
}
}

Updating JPanels and keeping JLabels Visible

I am developing a GUI for processing images, and I have trouble with displaying the images.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BottomLeftPanel extends JPanel {
public static BottomLeftPanel BLP;
public static BufferedImage original;
public static ImageIcon icon;
public static Polygon poly;
public static JLabel label;
public BottomLeftPanel() throws IOException {
super();
this.setBackground(new Color(255, 255, 255, 0));
original = Methods2.loadImage("bowser jr.png");
original = Methods2.toFourChannel(original);
poly = null;
icon = new ImageIcon(original);
label = new JLabel(icon);
this.add(new JLabel(icon));
this.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mousePressed(MouseEvent me) {
Point2D P = me.getPoint();
if(poly == null) {
poly = new Polygon(new int[]{(int) P.getX()}, new int[]{(int) P.getY()}, 1);
return;
}
int[] B = poly.xpoints;
int[] C = poly.ypoints;
int[] X = new int[poly.npoints + 1];
int[] Y = new int[poly.npoints + 1];
System.arraycopy(B, 0, X, 0, B.length);
System.arraycopy(C, 0, Y, 0, C.length);
X[B.length] = (int) P.getX();
Y[C.length] = (int) P.getY();
poly = new Polygon(X, Y, poly.npoints + 1);
System.out.println(poly.toString());
BLP.getGraphics().clearRect(0, 0, BLP.getHeight(), BLP.getWidth());
BLP.repaint(BLP.getGraphics());
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
});
BLP = this;
}
public void repaint(Graphics g) {
g.setColor(Color.black);
g.drawPolygon(poly);
icon = new ImageIcon(original);
label.setIcon(icon);
}
}
In the method mousePressed, polygon poly is updated, and the updated version is shown. However, after a few clicks, the ImageIcon which was part of the JLabel which was loaded onto the screen is no longer visible. How do I fix this while keeping the clearRect method in place (I need the clearRect method in order to remove the already drawn polygon and draw the new polygon)?
I was able to solve the problem. I first converted BottomLeftPanel to BottomLeftLabel and put it in a panel of its own. Then I did the painting in the paint(Graphics g) method. In the paint method, I used super.paint(Graphics g), but this is not important because the JLabel (BottomLeftLabel) would not clear the ImageIcon it held no matter what was painted. I do not mind using a static reference, since if I did not use a static reference, I would either have to make the class implement MouseListener, or create a seperate class which implements MouseListener, and since I am only running 1 GUI at a time, it does not make sense to do that (the static reference would not cause any problems here). Here is the code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BottomLeftLabel extends JLabel {
public static BottomLeftLabel BLP;
public static BufferedImage original;
public static ImageIcon icon;
public static Polygon poly;
// public static JLabel label;
public BottomLeftLabel() throws IOException {
super();
// this.setBackground(new Color(255, 255, 255, 0));
original = Methods2.loadImage("crash bandicoot picture.jpg");
// original = Methods2.loadImage("bowser jr.png");
// original = Methods2.loadImage("devil's tooth.jpg");
original = Methods2.toFourChannel(original);
// int[][] p = Methods.toIntegerArray(original);
// p = Methods.adjustTransparency(p, (float) 1.0);
// original = Methods.toBufferedImage(p);
// this.setSize(new Dimension(original.getWidth(), original.getHeight()));
// Graphics g = this.getGraphics();
poly = null;
icon = new ImageIcon(original);
// label = new JLabel(icon);
this.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mousePressed(MouseEvent me) {
Point2D P = me.getPoint();
if(poly == null) {
poly = new Polygon(new int[]{(int) P.getX()}, new int[]{(int) P.getY()}, 1);
return;
}
int[] B = poly.xpoints;
int[] C = poly.ypoints;
int[] X = new int[poly.npoints + 1];
int[] Y = new int[poly.npoints + 1];
System.arraycopy(B, 0, X, 0, B.length);
System.arraycopy(C, 0, Y, 0, C.length);
X[B.length] = (int) P.getX();
Y[C.length] = (int) P.getY();
poly = new Polygon(X, Y, poly.npoints + 1);
System.out.println(poly.toString());
// BLP.getGraphics().clearRect(0, 0, BLP.getHeight(), BLP.getWidth());
// BLP.removeAll();
// icon = new ImageIcon(original);
// BLP.add(new JLabel(icon));
BLP.paint(BLP.getGraphics());
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
});
this.setIcon(icon);
BLP = this;
// repaint(this.getGraphics());
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.clearRect(0, 0, WIDTH, HEIGHT);
if(poly != null) {
g.drawPolygon(poly);
}
}
// /**
// *
// * #param g
// */
// public void repaint(Graphics g) {
//// g.clearRect(0, 0, WIDTH, HEIGHT);
//
// g.setColor(Color.black);
// g.drawPolygon(poly);
// this.removeAll();
// icon = new ImageIcon(original);
// this.add(new JLabel(icon));
// }
// public void repaint(Graphics g) {
//
// }
}

Having two objects move in an SwingBot

I'm trying to make it so that both shapes move when the commands are pressed. My question is: How do I get the blue polygon to move along with the yellow rectangle? I can't seem to figure it out, no matter what I do. Any help is appreciated! thanks!
EDIT: Removed Timer Code (it is for something different)
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.Color;
import java.awt.Polygon;
import java.util.Scanner;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.Timer;
public class Original {
public static void main(String[] args) {
// contruction of new JFrame object
JFrame frame = new JFrame();
// mutators
frame.setSize(400,400);
frame.setTitle("SwingBot");
// program ends when window closes
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Robot r = new Robot();
frame.add(r);
// voila!
frame.setVisible(true);
// your Scanner-based command loop goes here
int noend = 0;
System.out.println("Type a Command:");
while(noend == 0)
{
Scanner input = new Scanner(System.in);
String command = input.next();
if(command.equals("left"))
r.moveBot(-10,0);
if(command.equals("right"))
r.moveBot(10,0);
if(command.equals("down"))
r.moveBot(0,10);
if(command.equals("up"))
r.moveBot(0,-10);
}
// call methods on the Robot instance like w.moveBot(10,10) in response to
// user input
}
public static class Robot extends JComponent
{
private Rectangle rect = new Rectangle(20,60);
private Polygon poly = new Polygon();
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
// set the color
g2.setColor(Color.ORANGE);
// draw the shape`
g2.fill(rect);
int xPoly[] = {75, 125, 170, 170, 200, 105, 60};
int yPoly[] = {75, 50, 88, 111, 125, 180, 150};
poly = new Polygon(xPoly, yPoly, xPoly.length);
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}
public void moveBot(int x, int y)
{
// move the rectangle
rect.translate(x,y);
poly.translate(x,y);
// redraw the window
repaint();
}
}
}
Suggestions:
Don't create the shapes in the paintComponent method.
When creating them give them variables that can be changed
In the Timer or key press, or where ever you are trying to move them, change those variable and call repaint()
For multiple objects you can have a an interface like Shape where each Shape has a move() method that can be called.
Loop through an data structure of those objects and call their move() methods, then repaint()`
A Shape can have a drawShape(Graphics g) method, and you can loop through the data structure of Shape inside the paintComponent method and call drawShape(g)
You can see this answer for an example.
UPDATE
Here's an example of all the points I mention above.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class MoveShape extends JPanel {
List<Shape> shapes;
public MoveShape() {
shapes = createShapeList();
InputMap im = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("RIGHT"), "moveRight");
ActionMap am = getActionMap();
am.put("moveRight", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
for (Shape sh : shapes) {
sh.moveRight();
repaint();
}
}
});
}
private List<Shape> createShapeList() {
List<Shape> list = new ArrayList<>();
int xPoly[] = {75, 125, 170, 170, 200, 105, 60};
int yPoly[] = {75, 50, 88, 111, 125, 180, 150};
list.add(new MyPolygon(xPoly, yPoly, 6));
list.add(new MyRectangle(75, 250, 150, 150));
return list;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Shape sh : shapes) {
sh.drawShape(g);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(450, 450);
}
public class MyRectangle implements Shape {
int x, y, width, height;
public MyRectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
#Override
public void drawShape(Graphics g) {
g.fillRect(x, y, width, height);
}
#Override
public void moveRight() {
x += INCREMENT;
}
}
public class MyPolygon implements Shape {
int[] xPoints;
int[] yPoints;
int numPoints;
public MyPolygon(int[] xPoints, int[] yPoints, int numPoints) {
this.xPoints = xPoints;
this.yPoints = yPoints;
this.numPoints = numPoints;
}
#Override
public void drawShape(Graphics g) {
g.fillPolygon(xPoints, yPoints, numPoints);
}
#Override
public void moveRight() {
for (int i = 0; i < xPoints.length; i++) {
xPoints[i] += INCREMENT;
}
}
}
public interface Shape {
public static final int INCREMENT = 5;
public void drawShape(Graphics g);
public void moveRight();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Move Shapes");
frame.add(new MoveShape());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
As #peeskillet has already pointed out...in your paintComponent method, you were re-creating the poly object each time it was called...meaning it never moved, and in fact was potential NullPointerException waiting to happen...
public void paintComponent(Graphics g)
{
//...
// This is a bad idea...
poly = new Polygon(xPoly, yPoly, xPoly.length);
//...
}
Instead, create the poloygon in the constructor to your Robot panel.
This example also demonstrates Initial Threads and key bindings and Stroking and Filling Graphics Primitives
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Original {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setTitle("SwingBot");
Robot r = new Robot();
frame.add(r);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class Robot extends JComponent {
private Rectangle rect = new Rectangle(20, 60);
private Polygon poly = new Polygon();
public Robot() {
int xPoly[] = {75, 125, 170, 170, 200, 105, 60};
int yPoly[] = {75, 50, 88, 111, 125, 180, 150};
poly = new Polygon(xPoly, yPoly, xPoly.length);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "Up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "Down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "Left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "Right");
ActionMap am = getActionMap();
am.put("Up", new MoveAction(0, -10));
am.put("Down", new MoveAction(0, 10));
am.put("Left", new MoveAction(-10, 0));
am.put("Right", new MoveAction(10, 0));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
// set the color
g2.setColor(Color.ORANGE);
// draw the shape`
g2.fill(rect);
g2.setColor(Color.BLUE);
g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.drawPolygon(poly);
g2.dispose();
}
public void moveBot(int x, int y) {
// move the rectangle
rect.translate(x, y);
poly.translate(x, y);
// redraw the window
repaint();
}
public class MoveAction extends AbstractAction {
private int xDelta;
private int yDelta;
public MoveAction(int xDelta, int yDelta) {
this.xDelta = xDelta;
this.yDelta = yDelta;
}
#Override
public void actionPerformed(ActionEvent e) {
moveBot(xDelta, yDelta);
}
}
}
}
Please, make sure you give all credit to #peeskillet, I just wanted to highlight some problem areas and solutions you might consider

Set background image for JPanel in Java Breakout Game

Okay, this seems like a really simple task but I can't seem to get it. All I want is to have an image (jpg) as the background to my breakout game. Here is my code:
Main Class:
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Breakout extends JFrame {
public Breakout()
{
add(new BreakBoard());
setTitle("Breakout");
setSize(BreakCommons.WIDTH, BreakCommons.HEIGTH);
setLocationRelativeTo(null);
setIgnoreRepaint(true);
setResizable(false);
setVisible(true);
}
public static void main(String[] args) {
new Breakout();
}
}
Board Class:
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BreakBoard extends JPanel implements BreakCommons {
ImageIcon icon = new ImageIcon("../pacpix/love.jpg");
Timer timer;
String message = "Game Over";
BreakBall ball;
BreakPaddle paddle;
BreakBrick bricks[];
boolean ingame = true;
int timerId;
public BreakBoard() {
setOpaque(false);
addKeyListener(new TAdapter());
setFocusable(true);
//setBackground(Color.white);
bricks = new BreakBrick[30];
setDoubleBuffered(true);
timer = new Timer();
timer.scheduleAtFixedRate(new ScheduleTask(), 1000, 10);
}
public void paint(Graphics g) {
super.paint(g);
g.drawImage(icon.getImage(), 10, 10, this);
if (ingame) {
g.drawImage(ball.getImage(), ball.getX(), ball.getY(),
ball.getWidth(), ball.getHeight(), this);
g.drawImage(paddle.getImage(), paddle.getX(), paddle.getY(),
paddle.getWidth(), paddle.getHeight(), this);
for (int i = 0; i < 30; i++) {
if (!bricks[i].isDestroyed())
g.drawImage(bricks[i].getImage(), bricks[i].getX(),
bricks[i].getY(), bricks[i].getWidth(),
bricks[i].getHeight(), this);
}
} else {
Font font = new Font("Verdana", Font.BOLD, 18);
FontMetrics metr = this.getFontMetrics(font);
g.setColor(Color.BLACK);
g.setFont(font);
g.drawString(message,
(BreakCommons.WIDTH - metr.stringWidth(message)) / 2,
BreakCommons.WIDTH / 2);
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
So the image is stored in variable icon and is located in my source files (along with my classes) so I know that the path is right. I tried setting the frame and panel to setOpaque(false) but that just changed the background to default grey. I can easily set the background color by setBackground(Color.white);, but how do I set an image?
I tried putting the image in a JLabel and then adding it to the JPanel, but that produced no results. I would appreciate any help, and thanks in advance! I can provide more information as needed.
easy way first create a separate class for jpane
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class JPanelDemo extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final Color BACKGROUND = Color.black;
private static final Color BACKGROUND_2 = Color.WHITE;
String path="/img/background.jpg";
#Override
protected void paintComponent(Graphics g) {
Graphics2D graphics = (Graphics2D) g.create();
int midY = 100;
Paint topPaint = new GradientPaint(0, 0, BACKGROUND,0, midY, BACKGROUND_2);
graphics.setPaint(topPaint);
graphics.fillRect(0, 0, getWidth(), midY);
Paint bottomPaint = new GradientPaint(0, midY + 1, BACKGROUND_2,0, getHeight(), BACKGROUND);
graphics.setPaint(bottomPaint);
graphics.fillRect(0, midY, getWidth(), getHeight());
Image img = new ImageIcon(getClass().getResource(path)).getImage();
int imgX = img.getWidth(null);
int imgY = img.getHeight(null);
graphics.drawImage(img, (getWidth() - imgX) / 2, (getHeight() - imgY) / 2, imgX, imgY, null);
// graphics.dispose();
}
}
how use it
JPanelDemo contentPane = new JPanelDemo();
This is a JPanel with a background image. Use IPanel in place of JPanel in your code. Tweak as necessary to suit your needs.
public class IPanel extends JPanel {
private static final long serialVersionUID = 1L;
private Image imageOrg = null;
private Image image = null;
{
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(final ComponentEvent e) {
final int w = IPanel.this.getWidth();
final int h = IPanel.this.getHeight();
image = w > 0 && h > 0 ? imageOrg.getScaledInstance(w, h, Image.SCALE_SMOOTH) : imageOrg;
IPanel.this.repaint();
}
});
}
public IPanel(final Image i) {
imageOrg = i;
image = i;
}
#Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
if (image != null)
g.drawImage(image, 0, 0, null);
}
}
Example:
final JPanel j = new IPanel(image);
j.setLayout(new FlowLayout());
j.add(new JButton("YoYo"));
j.add(new JButton("MaMa"));
j.add(new JLabel(icon));
Produces:
I got it to work finally!
public class BreakBoard extends JPanel implements BreakCommons {
Image love;
public BreakBoard() {
ImageIcon icon = new ImageIcon(this.getClass().getResource("../pacpix/love.jpg"));
love = icon.getImage();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(love, 10, 10, null);
}
}
For future searches or those that are curious, I used http://zetcode.com/tutorials/javagamestutorial/basics/. Great site for beginners! (Or those that need dumbing-down to understand)
JPanel panel = new JPanel()
{
#Override
public void paintComponent(Graphics g)
{
g.drawImage(ImageObject, 0, 0, null);
}
};

Categories