Use Buttons and mouse to control draw-board - java

I am doing a GUI that is supposed to work like a Paint application. My current problem is adding proper functionality to my draw line and draw rectangle buttons. They currently don't work as I expected them to work. Help will be greatly appreciated.
I searched many code snippets on learning how to draw shapes but none of them show how to make them work based on if they are activated based on the buttons, and how to alternate from drawing a line to drawing rectangles.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class paintGUI extends JComponent {
// Image in which we're going to draw
private Image image;
// Graphics2D object ==> used to draw on
private Graphics2D g2;
// Mouse coordinates
private int currentX, currentY, oldX, oldY;
public paintGUI() {
setDoubleBuffered(false);
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
// save coord x,y when mouse is pressed
oldX = e.getX();
oldY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
// coord x,y when drag mouse
currentX = e.getX();
currentY = e.getY();
if (g2 != null) {
// draw line if g2 context not null
//g2.drawLine(oldX, oldY, currentX, currentY);
//Need to implement these to their button
//g2.drawRect(oldX, oldY, currentX, currentY);
//g2.fillRect(oldX, oldY, currentX, currentY);
// refresh draw area to repaint
repaint();
// store current coords x,y as olds x,y
oldX = currentX;
oldY = currentY;
}
}
});
}
#Override
protected void paintComponent(Graphics g) {
if (image == null) {
// image to draw null ==> we create
image = createImage(getSize().width, getSize().height);
g2 = (Graphics2D) image.getGraphics();
// clear draw area
clear();
}
g.drawImage(image, 0, 0, null);
}
// now we create exposed methods
public void clear() {
g2.setPaint(Color.white);
// draw white on entire draw area to clear
g2.fillRect(0, 0, getSize().width, getSize().height);
g2.setPaint(Color.black);
repaint();
}
public void thin() {
g2.setStroke(new BasicStroke(3));
}
public void thick() {
g2.setStroke(new BasicStroke(10));
}
public void red() {
// apply red color on g2 context
g2.setPaint(Color.red);
}
public void black() {
g2.setPaint(Color.black);
}
public void magenta() {
g2.setPaint(Color.magenta);
}
public void drawLine() {
g2.drawLine(oldX, oldY, currentX, currentY);
}
public void drawRectangle() {
g2.drawRect(oldX, oldY, currentX, currentY);
g2.fillRect(oldX, oldY, currentX, currentY);
}
}
class GUIPaint {
JButton clearBtn, blackBtn, redBtn, magentaBtn, filledRectangleBtn, lineBtn, thinBtn, thickBtn;
paintGUI paintGUI;
ActionListener actionListener = e -> {
if (e.getSource() == clearBtn) {
paintGUI.clear();
} else if (e.getSource() == thinBtn) {
paintGUI.thin();
} else if (e.getSource() == thickBtn) {
paintGUI.thick();
} else if (e.getSource() == blackBtn) {
paintGUI.black();
} else if (e.getSource() == redBtn) {
paintGUI.red();
} else if (e.getSource() == magentaBtn) {
paintGUI.magenta();
} else if (e.getSource() == filledRectangleBtn) {
paintGUI.drawLine();
} else if (e.getSource() == lineBtn) {
paintGUI.drawRectangle();
}
};
public static void main(String[] args) {
new GUIPaint().show();
}
public void show() {
// create main frame
JFrame frame = new JFrame("Swing Paint");
Container content = frame.getContentPane();
// set layout on content pane
content.setLayout(new BorderLayout());
// create draw area
paintGUI = new paintGUI();
// add to content pane
content.add(paintGUI, BorderLayout.CENTER);
// create controls to apply colors and call clear feature
JPanel controls = new JPanel();
clearBtn = new JButton("Clear");
clearBtn.addActionListener(actionListener);
blackBtn = new JButton("Black");
blackBtn.addActionListener(actionListener);
redBtn = new JButton("Red");
redBtn.addActionListener(actionListener);
magentaBtn = new JButton("Magenta");
magentaBtn.addActionListener(actionListener);
lineBtn = new JButton("Line");
lineBtn.addActionListener(actionListener);
filledRectangleBtn = new JButton("Filled Rectangle");
filledRectangleBtn.addActionListener(actionListener);
thickBtn = new JButton("Thick Line");
thickBtn.addActionListener(actionListener);
thinBtn = new JButton("Thin Line");
thinBtn.addActionListener(actionListener);
controls.add(lineBtn);
controls.add(filledRectangleBtn);
controls.add(thinBtn);
controls.add(thickBtn);
controls.add(blackBtn);
controls.add(redBtn);
controls.add(magentaBtn);
controls.add(clearBtn);
// add to content pane
content.add(controls, BorderLayout.NORTH);
frame.setSize(800, 800);
// can close frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// show the swing paint result
frame.setVisible(true);
}
}
I need the program to properly respond if I click the line button to be able to draw a line or if the rectangle button is pressed than draw rectangle.

The basic idea is to let the controls (buttons, mouse) change the attributes (color, shape, stroke, coordinates) and invoke repaint.
paintComponent uses those attributes to draw the right shape.
Note the commented modifications of your code.
The code is one-file mre: the entire code can be copy pasted into GUIPaint.java and run:
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import swing_tests.PaintGUI.SHAPE;
public class GUIPaint {
private PaintGUI paintGUI;
public void showGui() {
JFrame frame = new JFrame("Swing Paint");
Container content = frame.getContentPane();
content.setLayout(new BorderLayout());
paintGUI = new PaintGUI();
content.add(paintGUI, BorderLayout.CENTER);
// create controls to apply colors and call clear feature
JPanel controls = new JPanel();
//todo: reduce duplicate code by having a method that constructs
//and adds a button
//todo: use button groups where only one button can be selected
JButton clearBtn = new JButton("Clear");
JButton blackBtn = new JButton("Black");
JButton redBtn = new JButton("Red");
JButton magentaBtn = new JButton("Magenta");
JButton lineBtn = new JButton("Line");
JButton filledRectangleBtn = new JButton("Filled Rectangle");
JButton thickBtn = new JButton("Thick Line");
JButton thinBtn = new JButton("Thin Line");
//todo: register an Action listner to each button by using lambda
//for example clearBtn.addActionListener(e-> paintGUI.clear());
ActionListener actionListener = e -> {
if (e.getSource() == clearBtn) {
paintGUI.clear();
}else if (e.getSource() == thinBtn) {
paintGUI.thin();
} else if (e.getSource() == thickBtn) {
paintGUI.thick();
} else if (e.getSource() == blackBtn) {
paintGUI.black();
} else if (e.getSource() == redBtn) {
paintGUI.red();
} else if (e.getSource() == magentaBtn) {
paintGUI.magenta();
} else if (e.getSource() == filledRectangleBtn) {
paintGUI.setShape(SHAPE.RECTANGLE);
} else if (e.getSource() == lineBtn) {
paintGUI.setShape(SHAPE.LINE);
}
};
clearBtn.addActionListener(actionListener);
blackBtn.addActionListener(actionListener);
redBtn.addActionListener(actionListener);
magentaBtn.addActionListener(actionListener);
lineBtn.addActionListener(actionListener);
filledRectangleBtn.addActionListener(actionListener);
thickBtn.addActionListener(actionListener);
thinBtn.addActionListener(actionListener);
controls.add(lineBtn);
controls.add(filledRectangleBtn);
controls.add(thinBtn);
controls.add(thickBtn);
controls.add(blackBtn);
controls.add(redBtn);
controls.add(magentaBtn);
controls.add(clearBtn);
content.add(controls, BorderLayout.NORTH);
frame.setSize(800, 800);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> new GUIPaint().showGui());
}
}
class PaintGUI extends JComponent {
//states defined by enum
enum SHAPE {RECTANGLE, LINE}
private SHAPE shape; // store state
private static final Color BACKGROUND_COLOR = Color.WHITE;
private int startX, startY, endX, endY; //shape coordinates
private Color color = Color.BLACK; //draw color
private BasicStroke stroke = new BasicStroke(3); //draw stroke
private boolean isClear = false;
public PaintGUI() {
setDoubleBuffered(false);
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
//save coord x,y where mouse was pressed
startX = e.getX();
startY = e.getY();
endX = startX; endY = startY;
clear(); //clear draw board
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
//update end coord as mouse dragged
endX = e.getX();
endY = e.getY();
repaint(); //keep repainting while drag lasts
}
});
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// draw white on entire draw area to clear
g2.setColor(BACKGROUND_COLOR);
g2.fillRect(0, 0, getSize().width, getSize().height);
if(isClear || shape == null){
isClear = false;
return;
}
//draw using color , stroke and shape attributes
g2.setColor(color);
g2.setStroke(stroke);
switch (shape){
case RECTANGLE:
drawFilledRectangle(g2);
break;
case LINE:
drawLine(g2);
break;
default:
break;
}
}
public void clear() {
isClear = true;
repaint();
}
public void drawLine(Graphics2D g2) {
g2.drawLine( startX, startY, endX, endY);
repaint();
}
public void drawFilledRectangle(Graphics2D g2) {
//to allow rectangle dragged from bottom up and left to right
//use min x and min y as origin
int x = Math.min(startX, endX);
int y = Math.min(startY, endY);
int width = Math.abs(endX-startX); //to account for negative width
int height = Math.abs(endY-startY); //or height
g2.fillRect(x,y,width,height);
}
public void thin() {
setStroke(3);
}
public void thick() {
setStroke(10);
}
public void setStroke(int width) {
stroke = new BasicStroke(width);
repaint();
}
public void red() {
setColor(Color.red);
}
public void black() {
setColor(Color.black);
}
public void magenta() {
setColor(Color.magenta);
}
void setColor(Color color){
this.color = color;
repaint();
}
void setShape(SHAPE shape) {
this.shape = shape;
clear();
}
}

Related

how to output a user selected shape & color, whose location and dimensions depend upon the coordinate location of user clicks

As part of a larger project I'm trying to create a basic UI that will allow a user to click a JButton to select a desired color and then allow that user to click another JButton to designate a shape to be displayed, filled in according to the previously selected color. I understand that I must make use of action events.
Please note I am referencing this similar question:
GUI Application that allows the user to choose the shape and color of a drawing
My code thus far is:
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
public class GUI extends JFrame implements ActionListener, WindowListener
{
private final JButton circleButton, rectangleButton, redButton;
private final JButton greenButton, blueButton, exitButton;
private final JTextArea textArea;
private final JLabel label1;
private final JPanel colorPane;
private String shapeColor = "black";
private String actualShape = "rectangle";
private static final int ROWS = 2, COLS = 3;
public GUI (String title)
{
super(title);
//setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
colorPane = new JPanel();
label1 = new JLabel("current date here");
label1.setVerticalAlignment(SwingConstants.BOTTOM);
label1.setHorizontalAlignment(SwingConstants.LEFT);
label1.setPreferredSize(new Dimension(200,0));
getContentPane().add(label1, BorderLayout.WEST);
colorPane.setLayout(new GridLayout(ROWS,COLS));
getContentPane().add(colorPane, BorderLayout.CENTER);
redButton = makeButton("Red");
colorPane.add(redButton);
greenButton = makeButton("Green");
colorPane.add(greenButton);
blueButton = makeButton("Blue");
colorPane.add(blueButton);
rectangleButton = makeButton("Rectangle");
colorPane.add(rectangleButton);
circleButton = makeButton("Circle");
colorPane.add(circleButton);
exitButton = makeButton("Exit");
colorPane.add(exitButton);
textArea = new JTextArea(0,20);
getContentPane().add(textArea, BorderLayout.EAST);
pack();
}
public void paint(Graphics g, String color)
{
if (shapeColor.equalsIgnoreCase("blue") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.BLUE);
g.fillRect(50, 90, 100, 50);
}
else if (shapeColor.equalsIgnoreCase("green") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.GREEN);
g.fillOval(50, 180, 55, 55);
}
else if (shapeColor.equalsIgnoreCase("red") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.RED);
g.fillRect(50, 90, 100, 50);
}
else if (shapeColor.equalsIgnoreCase("green") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.GREEN);
g.fillRect(50,90,100,50);
}
else if (shapeColor.equalsIgnoreCase("blue") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.BLUE);
g.fillOval(50, 180, 55, 55);
}
else if (shapeColor.equalsIgnoreCase("red") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.RED);
g.fillOval(50, 180, 55, 55);
}
}
//method designed to create new JButtons while avoiding code duplication
private JButton makeButton(String text)
{
JButton b = new JButton(text);
b.setHorizontalAlignment(SwingConstants.LEFT);
b.addActionListener(this);
b.setPreferredSize(new Dimension(125,55));
return b;
}
#Override
public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
#Override
public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowIconified(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowDeactivated(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent e)
{
System.out.println( ( (JButton)e.getSource() ).getText() + " button pressed ");
if ( ( ((JButton) e.getSource()).getText().equalsIgnoreCase("Red")) )
{
setShapeColor("Red");
System.out.println("selected color is: " + shapeColor + " selected shape is: " + actualShape);
//paint(this.getGraphics());
}
else if ( ( ((JButton) e.getSource()).getText().equalsIgnoreCase("Blue")) )
{
setShapeColor("Blue");
System.out.println("selected color is: " + shapeColor + " selected shape is: " + actualShape);
//paint(this.getGraphics());
}
else if ( ( ((JButton) e.getSource()).getText().equalsIgnoreCase("Green")) )
{
setShapeColor("Green");
System.out.println("selected color is: " + shapeColor + " selected shape is: " + actualShape);
//paint(this.getGraphics());
}
if ( ( ((JButton) e.getSource()).getText().equalsIgnoreCase("Rectangle")) )
{
setActualShape("rectangle");
System.out.println("selected shape is: " + actualShape + " selected color is: " + shapeColor);
paint(this.getGraphics(), shapeColor);
}
else if ( ( ((JButton) e.getSource()).getText().equalsIgnoreCase("Circle")) )
{
setActualShape("circle");
System.out.println("selected shape is: " + actualShape + " selected color is: " + shapeColor);
paint(this.getGraphics(), shapeColor);
}
}
public String getShapeColor() {
return shapeColor;
}
public void setShapeColor(String shapeColor) {
this.shapeColor = shapeColor;
}
public String getActualShape() {
return actualShape;
}
public void setActualShape(String actualShape) {
this.actualShape = actualShape;
}
public static void main(String[] args)
{
new GUI("My Gui").setVisible(true);
}
}
What I've thus far achieved is an output that shows both the selected color as well as the selected shape to be rendered in the selected color.
Furthermore, I've been successful in outputting a shape whose position is hard-coded but whose type (either circle or square) and whose color (red, blue or green), is correctly output as a result of the user clicks.
The final phase, upon which I am struggling, is the implementation of the shape's output so that the user's sequence of clicks determines the location and dimensions of the shape output to the screen.
The goal is to achieve the functionality demonstrated here:
https://metrostate.learn.minnstate.edu/content/2020/4560296-20201000539/ICS372%20-%20Assignment%202%20Video.mp4?d2lSessionVal=ARifwbCHriCBrkgxBWpL9g8fL&ou=4560296
I'm relatively certain that the correct solution is similar to the following code:
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/**
* Note: Normally the ButtonPanel and DrawingArea would not be static
classes.
* This was done for the convenience of posting the code in one class and
to
* highlight the differences between the two approaches. All the
differences
* are found in the DrawingArea class.
*/
public class DrawOnComponent
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
DrawingArea drawingArea = new DrawingArea();
ButtonPanel buttonPanel = new ButtonPanel( drawingArea );
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("Draw On Component");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().add(drawingArea);
frame.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
frame.setSize(400, 400);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
static class ButtonPanel extends JPanel implements ActionListener
{
private DrawingArea drawingArea;
public ButtonPanel(DrawingArea drawingArea)
{
this.drawingArea = drawingArea;
add( createButton(" ", Color.BLACK) );
add( createButton(" ", Color.RED) );
add( createButton(" ", Color.GREEN) );
add( createButton(" ", Color.BLUE) );
add( createButton(" ", Color.ORANGE) );
add( createButton(" ", Color.YELLOW) );
add( createButton("Clear Drawing", null) );
}
private JButton createButton(String text, Color background)
{
JButton button = new JButton( text );
button.setBackground( background );
button.addActionListener( this );
return button;
}
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton)e.getSource();
if ("Clear Drawing".equals(e.getActionCommand()))
drawingArea.clear();
else
drawingArea.setForeground( button.getBackground() );
}
}
static class DrawingArea extends JPanel
{
private final static int AREA_SIZE = 400;
private ArrayList<ColoredRectangle> coloredRectangles = new ArrayList<ColoredRectangle>();
private Rectangle shape;
public DrawingArea()
{
setBackground(Color.WHITE);
MyMouseListener ml = new MyMouseListener();
addMouseListener(ml);
addMouseMotionListener(ml);
}
#Override
public Dimension getPreferredSize()
{
return isPreferredSizeSet() ?
super.getPreferredSize() : new Dimension(AREA_SIZE, AREA_SIZE);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
// Custom code to paint all the Rectangles from the List
Color foreground = g.getColor();
g.setColor( Color.BLACK );
g.drawString("Add a rectangle by doing mouse press, drag and release!", 40, 15);
for (DrawingArea.ColoredRectangle cr : coloredRectangles)
{
g.setColor( cr.getForeground() );
Rectangle r = cr.getRectangle();
g.drawRect(r.x, r.y, r.width, r.height);
}
// Paint the Rectangle as the mouse is being dragged
if (shape != null)
{
Graphics2D g2d = (Graphics2D)g;
g2d.setColor( foreground );
g2d.draw( shape );
}
}
public void addRectangle(Rectangle rectangle, Color color)
{
// Add the Rectangle to the List so it can be repainted
ColoredRectangle cr = new ColoredRectangle(color, rectangle);
coloredRectangles.add( cr );
repaint();
}
public void clear()
{
coloredRectangles.clear();
repaint();
}
class MyMouseListener extends MouseInputAdapter
{
private Point startPoint;
public void mousePressed(MouseEvent e)
{
startPoint = e.getPoint();
shape = new Rectangle();
}
public void mouseDragged(MouseEvent e)
{
int x = Math.min(startPoint.x, e.getX());
int y = Math.min(startPoint.y, e.getY());
int width = Math.abs(startPoint.x - e.getX());
int height = Math.abs(startPoint.y - e.getY());
shape.setBounds(x, y, width, height);
repaint();
}
public void mouseReleased(MouseEvent e)
{
if (shape.width != 0 || shape.height != 0)
{
addRectangle(shape, e.getComponent().getForeground());
}
shape = null;
}
}
class ColoredRectangle
{
private Color foreground;
private Rectangle rectangle;
public ColoredRectangle(Color foreground, Rectangle rectangle)
{
this.foreground = foreground;
this.rectangle = rectangle;
}
public Color getForeground()
{
return foreground;
}
public void setForeground(Color foreground)
{
this.foreground = foreground;
}
public Rectangle getRectangle()
{
return rectangle;
}
}
}
}
I know that I must override the 'paint' method and as a hard-coded exercise I have included the following in my code:
public void paint(Graphics g, String color)
{
if (shapeColor.equalsIgnoreCase("blue") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.BLUE);
g.fillRect(50, 90, 100, 50);
}
else if (shapeColor.equalsIgnoreCase("green") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.GREEN);
g.fillOval(50, 180, 55, 55);
}
else if (shapeColor.equalsIgnoreCase("red") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.RED);
g.fillRect(50, 90, 100, 50);
}
else if (shapeColor.equalsIgnoreCase("green") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.GREEN);
g.fillRect(50,90,100,50);
}
else if (shapeColor.equalsIgnoreCase("blue") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.BLUE);
g.fillOval(50, 180, 55, 55);
}
else if (shapeColor.equalsIgnoreCase("red") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.RED);
g.fillOval(50, 180, 55, 55);
}
}
}
I am unsure how to record coordinates of a user's button click and to then pass those coordinates into the constructor of the desired shape.
There are a couple of errors to change in your code:
Don't extend JFrame, see Extends JFrame vs. creating it inside the program, instead create an instance of it inside your class. If you need to extend from a JComponent let it be a more flexible one such as JPanel.
Don't override paint(...) method, you need to override JPanel's paintComponent(...) method and don't forget to call super.paintComponent(g) as the first line in it, otherwise you might break the paint chain and have funny / weird behaviors. Neither pass the getGraphics() object, see the Tutorial on Custom Painting
Use the Shape API rather than drawing directly on the JPanel as it provides more functionality. See this post: Create the square, rectangle, triangle of java in jframe
Don't call setPreferredSize, override the getPreferredSize, see: Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
Place your program on the EDT, see point #7 in the linked post in point #3 in this same answer.
So, here's an example that follows the above recommendations:
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
import java.awt.event.*;
public class PaintExample {
private JFrame frame;
private JPanel pane;
private JPanel buttonsPane;
private CustomShape customShape;
private JButton squareButton;
private JButton circleButton;
private JButton purpleButton;
private JButton blueButton;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new PaintExample().createAndShowGUI());
}
private void createAndShowGUI() {
frame = new JFrame(getClass().getSimpleName()); //Create a new JFrame with a title = this class name
pane = new JPanel();
buttonsPane = new JPanel();
buttonsPane.setLayout(new GridLayout(2, 2, 5, 5)); // We generate a grid layout of 2 x 2 for our JButtons
squareButton = new JButton("Square");
circleButton = new JButton("Circle");
purpleButton = new JButton("Purple");
blueButton = new JButton("Blue");
squareButton.addActionListener(listener);
circleButton.addActionListener(listener);
purpleButton.addActionListener(listener);
blueButton.addActionListener(listener);
buttonsPane.add(squareButton);
buttonsPane.add(circleButton);
buttonsPane.add(purpleButton);
buttonsPane.add(blueButton);
customShape = new CustomShape(); // We create an instance of our custom JPanel class
pane.setLayout(new BorderLayout());
pane.add(customShape);
pane.add(buttonsPane, BorderLayout.SOUTH);
frame.add(pane);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
ActionListener listener = e -> { //Java 8+, for Java 7- add the actionPerformed method instead of the lambda expression
// We check which button was clicked and set the shape / color for our custom class
if (e.getSource().equals(squareButton)) {
customShape.setShape(ShapeToDraw.SQUARE);
} else if (e.getSource().equals(circleButton)) {
customShape.setShape(ShapeToDraw.CIRCLE);
} else if (e.getSource().equals(purpleButton)) {
customShape.setColor(Color.MAGENTA);
} else if (e.getSource().equals(blueButton)) {
customShape.setColor(Color.BLUE);
}
};
enum ShapeToDraw {
SQUARE, CIRCLE // You can define here other properties for each enum option
}
class CustomShape extends JPanel {
private Color color;
private ShapeToDraw shape;
public CustomShape() {
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
this.repaint(); // Everytime we set the color we ask the component to repaint itself
}
public ShapeToDraw getShape() {
return shape;
}
public void setShape(ShapeToDraw shape) {
this.shape = shape;
this.repaint(); // Everytime we set the shape we ask the component to repaint itself
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200); // We define the panel's size
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(color != null ? color : Color.BLACK); //If we haven't set the Color yet, we default it to black, otherwise we set the color to the one chosen by the user.
if (shape == ShapeToDraw.SQUARE) { //If the shape is a square, we draw a square
g2d.draw(new Rectangle2D.Double(50, 50, 100, 100)); // Change the coordinates that you get by user click using the MouseListener
} else if (shape == ShapeToDraw.CIRCLE) { // Or we draw a circle
g2d.draw(new Ellipse2D.Double(50, 50, 100, 100));
}
}
}
}
This is how the program looks like:
I am unsure how to record coordinates of a user's button click and to then pass those coordinates into the constructor of the desired shape.
To get the coordinates relative to your window see: How to get location of a mouse click relative to a swing window
The following is a suggested implementation, also incorporating the good guidance you got from Frakcool:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class GUI
{
private final ButtonGroup colorGroup; //group buttons
private final ButtonGroup shapeGroup; //so only one can be selected at any given time
private final Map<String, Color> colors; //map colors to it names.
private Color color; // color for painting
private Shape shape; //shape to paint
private JFrame frame;
private JPanel buttonsPane;
private JTextArea textArea;
private static final int ROWS = 2, COLS = 3;
private static final String[] BUTTONS_LABELS = {"Rectangle", "Circle", "Exit"};
public GUI()
{
shapeGroup = new ButtonGroup(); colorGroup = new ButtonGroup();
colors = new HashMap<>();
colors.put("Red", Color.RED); colors.put("Green", Color.GREEN); colors.put("Blue", Color.BLUE);
}
private void createAndShowGUI(String title) {
frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//use a GridLayout for the buttons pane
buttonsPane = new JPanel();
buttonsPane.setLayout(new GridLayout(ROWS, COLS));
frame.getContentPane().add(buttonsPane, BorderLayout.CENTER);//each BorderLayout position can hold ONE component
for(String colorName : colors.keySet()){
JToggleButton button = makeButton(colorName);
buttonsPane.add(button);
colorGroup.add(button);
button.addActionListener(changeColorAction());
}
for(String text : BUTTONS_LABELS){
JToggleButton button = makeButton(text);
buttonsPane.add(button);
shapeGroup.add(button);
button.addActionListener(changeShapeAction());
}
setDefaults();
frame.getContentPane().add(new Draw(), BorderLayout.WEST);
textArea = new JTextArea(0,20);
frame.getContentPane().add(textArea, BorderLayout.EAST);
frame.pack();
frame.setVisible(true);
}
private JToggleButton makeButton(String text) {
JToggleButton b = new JToggleButton(text); //use toggle buttons
b.setHorizontalAlignment(SwingConstants.LEFT);
b.setPreferredSize(new Dimension(100, 80)); //set preferred and let Layout manager do its work
return b;
}
private ActionListener changeColorAction() {
return e->{
color = colors.get(((JToggleButton)e.getSource()).getText());
frame.repaint();
};
}
private ActionListener changeShapeAction() {
return e->{
switch (((JToggleButton)e.getSource()).getText()){
case "Circle":
shape = Shape.CIRCLE;
break;
case "Rectangle":
shape = Shape.RECTANGLE;
break;
default: System.exit(0);
}
frame.repaint();
};
}
private void setDefaults() {
colorGroup.getElements().nextElement().setSelected(true);
color = colors.get(colorGroup.getElements().nextElement().getText());
shapeGroup.getElements().nextElement().setSelected(true);
shape = Shape.RECTANGLE;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new GUI().createAndShowGUI("My Gui"));
}
class Draw extends JPanel{
private final Point[] points; // an array to hold clicked points
private int mouseClicks = 0;
private static final int POINT_SIZE = 2;
Draw(){
setLayout(new BorderLayout());
setBackground(Color.WHITE);
setPreferredSize(new Dimension(200, 200));
JLabel help = new JLabel("Click 2 points to draw");
help.setHorizontalAlignment(SwingConstants.CENTER);
add(help, BorderLayout.PAGE_START);
JLabel timeLabel = new JLabel("current time here");
timeLabel.setHorizontalAlignment(SwingConstants.LEFT);
add(timeLabel, BorderLayout.PAGE_END);
points = new Point[2];
addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent e) {
addPoint(e.getX(), +e.getY() );
}
});
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(color);
for(Point point : points)
if(point != null){
g.drawOval(point.x, point.y, POINT_SIZE, POINT_SIZE);
}
drawShape((Graphics2D)g);
}
private void addPoint(int x, int y) {
if(mouseClicks ==2){
mouseClicks = 0;
points[1] = null;
}
points[mouseClicks++] = new Point(x, y);
repaint();
}
private void drawShape(Graphics2D g2d) {
if(points[0] == null || points[1] == null) return;
if(shape == Shape.RECTANGLE) {
drawRectangle(g2d);
}else{
drawCircle(g2d);
}
}
private void drawRectangle(Graphics2D g2D) {
int minX = Math.min(points[0].x, points[1].x);
int minY = Math.min(points[0].y, points[1].y);
int maxX = Math.max(points[0].x, points[1].x);
int maxY = Math.max(points[0].y, points[1].y);
int width = maxX - minX;
int height = maxY - minY;
Rectangle2D.Double rectangle = new Rectangle2D.Double(minX, minY, width, height);
g2D.draw(rectangle);
}
private void drawCircle(Graphics2D g2D) {
int minX = Math.min(points[0].x, points[1].x);
int minY = Math.min(points[0].y, points[1].y);
int maxX = Math.max(points[0].x, points[1].x);
int maxY = Math.max(points[0].y, points[1].y);
double dx = maxX - minX;
double dy = maxY - minY;
double radius = Math.sqrt(dx*dx + dy*dy)/2;
double centerX = minX + dx/2;
double centerY = minY + dy/2;
g2D.draw(new Ellipse2D.Double(centerX - radius , centerY - radius, 2* radius, 2* radius));
}
}
enum Shape {
RECTANGLE, CIRCLE
}
}

Removing a rectangle with color on mouse release

I am developing a game and in some part of my game I want the rectangle to disappear on mouse release. I have placed 26 rectangles in an arrayList and remove the particular rectangle clicked as the mouse is released. So if I remove the fill methods, the rectangle disappears successfully but if the fill methods are there, it does not work anymore.
Here is my paint method:
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Image img = Toolkit.getDefaultToolkit().getImage(Rectangles2.class.getResource("background.jpg"));
g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle s : rectanglesList) {
g2.draw(s);
}
g2.setColor(bColor);
g2.fill(box1);
g2.fill(box2);
g2.fill(box3);
g2.fill(box4);
g2.fill(box5);
g2.fill(box6);
g2.fill(box7);
g2.fill(box8);
g2.fill(box9);
g2.fill(box10);
g2.fill(box11);
g2.fill(box12);
g2.fill(box25);
g2.setColor(wColor);
g2.fill(box13);
g2.fill(box14);
g2.fill(box15);
g2.fill(box16);
g2.fill(box17);
g2.fill(box18);
g2.fill(box19);
g2.fill(box20);
g2.fill(box21);
g2.fill(box22);
g2.fill(box23);
g2.fill(box24);
g2.fill(box26);
}
Here is how I did the removing of the rectangle (Just an excerpt):
if (box1.getBounds().contains(x, y)) {
pickedPanelNum = 0;
rectanglesList.remove(box1);
panelsPane.repaint();
}
Here are the values of the bColor and wColor:
Color bColor = Color.BLACK;
Color wColor = Color.WHITE;
NOTE:
The pickedPanelNum is just for assigning an int value and has no connection to the problem.
I think it is because when I repaint, the fill methods are still there. However I have no idea for an alternate way of painting the rectangles.
I hope my problem is stated clearly. If you have ideas how I could solve this, please tell me. Thank you!
UPDATE:
Here is a shorter, runnable version of my program. (Background image isn't included though):
import java.awt.*;
import java.awt.Color.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.geom.Rectangle2D;
public class Rec extends JComponent
{
public ArrayList<Rectangle> rectanglesList = new ArrayList<Rectangle>();
public int arrx[] = new int[120];
public int arry[] = new int[120];
JFrame frame = new JFrame();
public int xSize = 2000;
public int ySize = 1000;
public int x;
public int y;
public int pickedPanelNum = 0;
public String pickedPanelDash = "";
public String pickedPanelColor = "";
Color bColor = Color.BLACK;
Color wColor = Color.WHITE;
boolean removedPanel = false;
public void launchFrame()
{
Random rand = new Random();
for(int x = 0;x<120;x++)
{
arrx[x] = rand.nextInt(640);
arry[x] = rand.nextInt(590);
}
Rectangle box1 = new Rectangle(arrx[103],arry[59],80,90);
Rectangle box2 = new Rectangle(arrx[105],arry[3],80,90);
rectanglesList.add(box1);
rectanglesList.add(box2);
JPanel mainPanel = new JPanel();
JPanel panelsPane = new JPanel()
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Image img = Toolkit.getDefaultToolkit().getImage(Rectangles2.class.getResource("background.jpg"));
g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle s : rectanglesList) {
g2.draw(s);
}
g2.setColor(bColor);
g2.fill(box1);
g2.setColor(wColor);
g2.fill(box2);
}
};
JPanel rightPane = new JPanel();
panelsPane.addMouseListener (new MouseAdapter ()
{
public void mousePressed(MouseEvent event)
{
x = event.getX();
y = event.getY();
}
public void mouseReleased(MouseEvent event)
{
if (box1.getBounds().contains(x, y)) {
pickedPanelNum = 0;
rectanglesList.remove(box1);
panelsPane.repaint();
}
if (box2.getBounds().contains(x, y)) {
pickedPanelNum = 1;
rectanglesList.remove(box2);
panelsPane.repaint();
}
}
});
panelsPane.addMouseMotionListener (new MouseAdapter ()
{
public void mouseDragged(MouseEvent event)
{
Rec obj = new Rec();
int dx = event.getX() - x;
int dy = event.getY() - y;
if (box1.getBounds().contains(x, y)) {
box1.x += dx;
box1.y += dy;
panelsPane.repaint();
}
if (box2.getBounds().contains(x, y)) {
box2.x += dx;
box2.y += dy;
panelsPane.repaint();
}
x += dx;
y += dy;
}
public void mouseReleased(MouseEvent event) {}
public void mouseClicked(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
});
panelsPane.setPreferredSize(new Dimension (800, ySize-315));
rightPane.setPreferredSize(new Dimension (530, ySize-315));
mainPanel.setPreferredSize(new Dimension (xSize, ySize));
frame.setPreferredSize(new Dimension (xSize, ySize));
rightPane.setBackground(Color.gray);
mainPanel.add(panelsPane);
mainPanel.add(rightPane);
frame.add(mainPanel);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
}
public static void main(String args[])
{
Rec obj = new Rec();
obj.launchFrame();
}
}
Even if you remove box1 from the List, there is nothing stopping it from getting filled in your paintComponent method, the for-loop is only drawing the outline of the rectangles within the list, but you code implicitly fills them anyway.
So, first, get rid of all the box{n} variables. Next change the paintComponent method...
public void paintComponent(Graphics g) {
super.paintComponent(g);
//Image img = Toolkit.getDefaultToolkit().getImage(Rectangles2.class.getResource("background.jpg"));
//g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle s : rectanglesList) {
g2.setColor(bColor);
g2.fill(s);
g2.setColor(wColor);
g2.draw(s);
}
}
So, this just uses the rectanglesList to first draw the rectangles and the fill them
Then, lets update the mouseReleased...
public void mouseReleased(MouseEvent event) {
// Because the rectangles are painted in order, the later
// rectangles are painted over the eailer ones, so, we reverse
// the list so we can check for the higher positioned
// rectangles
List<Rectangle> copy = new ArrayList<>(rectanglesList);
Collections.reverse(copy);
for (Rectangle r : copy) {
if (r.contains(event.getPoint())) {
rectanglesList.remove(r);
break;
}
}
event.getComponent().repaint();
}
Okay, this is little more funky, but basically, we reverse the list of rectangles (because those rectangles that appear later in the list are painted over those that appear before them) and checks to see if the mouse was clicked within any one of them. The moment we find a match, we break out of the loop and repaint the component which generated the event
And, because it's nice to see this stuff running, a complete example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Rec extends JComponent {
public ArrayList<Rectangle> rectanglesList = new ArrayList<Rectangle>();
public int arrx[] = new int[120];
public int arry[] = new int[120];
JFrame frame = new JFrame();
public int xSize = 2000;
public int ySize = 1000;
public int x;
public int y;
public int pickedPanelNum = 0;
public String pickedPanelDash = "";
public String pickedPanelColor = "";
Color bColor = Color.BLACK;
Color wColor = Color.WHITE;
boolean removedPanel = false;
public void launchFrame() {
Random rand = new Random();
for (int x = 0; x < 10; x++) {
arrx[x] = rand.nextInt(640);
arry[x] = rand.nextInt(590);
rectanglesList.add(new Rectangle(arrx[x], arry[x], 80, 90));
}
JPanel mainPanel = new JPanel();
JPanel panelsPane = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Image img = Toolkit.getDefaultToolkit().getImage(Rectangles2.class.getResource("background.jpg"));
// g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle s : rectanglesList) {
g2.setColor(bColor);
g2.fill(s);
g2.setColor(wColor);
g2.draw(s);
}
}
};
JPanel rightPane = new JPanel();
panelsPane.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent event) {
x = event.getX();
y = event.getY();
}
public void mouseReleased(MouseEvent event) {
// Because the rectangles are painted in order, the later
// rectangles are painted over the eailer ones, so, we reverse
// the list so we can check for the higher positioned
// rectangles
List<Rectangle> copy = new ArrayList<>(rectanglesList);
Collections.reverse(copy);
for (Rectangle r : copy) {
if (r.contains(event.getPoint())) {
rectanglesList.remove(r);
break;
}
}
event.getComponent().repaint();
}
});
panelsPane.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent event) {
}
public void mouseReleased(MouseEvent event) {
}
public void mouseClicked(MouseEvent event) {
}
public void mouseEntered(MouseEvent event) {
}
public void mouseExited(MouseEvent event) {
}
});
panelsPane.setPreferredSize(new Dimension(800, ySize - 315));
rightPane.setPreferredSize(new Dimension(530, ySize - 315));
mainPanel.setPreferredSize(new Dimension(xSize, ySize));
frame.setPreferredSize(new Dimension(xSize, ySize));
rightPane.setBackground(Color.gray);
mainPanel.add(panelsPane);
mainPanel.add(rightPane);
frame.add(mainPanel);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
}
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();
}
Rec obj = new Rec();
obj.launchFrame();
}
});
}
}

My screen will not repaint despite the rectangle being clicked

I have my code set up to where the Boolean boxDetect will be set to true if the mouse is clicked within the Rectangle startButton. The rest is just formatting nothing special! This is the initial screen before you press inside the rectangle, and once inside the rectangle and pressed it should repaint the screen to a rectangle at points 400,400.
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.*;
public class spaceInvadersIntroScreen implements MouseListener
{
private JFrame frame;
private MyPanel panel;
private double startButtonX = 0;
private double startButtonY = 0;
private Rectangle startButton;
private Boolean boxDetect = false;
public static void main(String[] args){ new spaceInvadersIntroScreen(); }
public spaceInvadersIntroScreen()
{
frame = new JFrame("Space Invaders");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
startButtonX = screenSize.getWidth() / 2; //Finds the X value of the center of the screen
startButtonY = screenSize.getHeight() / 2; //Finds the Y value of the center of the screen
frame.setSize(screenSize); //width and height
panel = new MyPanel();
frame.getContentPane().add(panel);
frame.setVisible(true);
startButton = new Rectangle((int)(startButtonX - 200), (int)(startButtonY - 75), 400, 150); //Creates Rectangle in the middle of the screen
}
class MyPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public void paint(Graphics g)
{
if(boxDetect == false)
{
Graphics2D g2d = (Graphics2D) g;
//Background
g2d.setColor(Color.BLACK);
g2d.fillRect(0,0, 1440, 870);
//Code for an X centered title regardless of the screen length
String title = "SPACE INVADERS";
Font textFont = new Font("monospaced", Font.BOLD, 150);
FontMetrics textMetrics = g2d.getFontMetrics(textFont);
g2d.setFont(textFont);
int centeredX = (this.getWidth()/2) - (textMetrics.stringWidth(title)/2);
//Prints SPACE INVADERS to the screen
g2d.setColor(Color.WHITE);
g2d.setFont(textFont);
g2d.drawString(title, centeredX, 200);
//draw the Button
g2d.setColor(Color.white);
g2d.fill(startButton);
}
else
{
g.setColor(Color.black);
g.drawRect(400, 400, 400, 400);
}
}
}
#Override
public void mouseReleased(MouseEvent e)
{
double xCoord = e.getX();
double yCoord = e.getY();
if(startButton.contains(xCoord,yCoord) == true)
{
boxDetect = true;
}
panel.repaint();
}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
You need to add the MouseListener for it to work. Question: Where do you call addMouseListener(...)? Answer: you don't. Solution: make this method call to add the MouseListener to the component that needs it.

Problems making a paint program

I'm kinda new to java and have been trying to make a simple paint program, I have gotten everything to work except the color of the paint brush. Rigth now I set the color to blue but I want to make the color of the paint brush the same color as the color selected by the color slider.
Here's the code I got so far
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class Paint extends JFrame implements ChangeListener{
PaintPanel color;
PaintPanel2 paint;
JSlider red;
JSlider green;
JSlider blue;
public Paint(){
super("Paint");
setSize(300,290);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
color = new PaintPanel();
paint = new PaintPanel2();
red = new JSlider(0,255,255);
green = new JSlider(0,255,0);
blue = new JSlider(0,255,0);
red.setMajorTickSpacing(50);
red.setMinorTickSpacing(10);
red.setPaintTicks(true);
red.setPaintLabels(true);
red.addChangeListener(this);
green.setMajorTickSpacing(50);
green.setMinorTickSpacing(10);
green.setPaintTicks(true);
green.setPaintLabels(true);
green.addChangeListener(this);
blue.setMajorTickSpacing(50);
blue.setMinorTickSpacing(10);
blue.setPaintTicks(true);
blue.setPaintLabels(true);
blue.addChangeListener(this);
JLabel redLabel = new JLabel("Red: ");
JLabel greenLabel = new JLabel("Green: ");
JLabel blueLabel = new JLabel("Blue: ");
GridLayout grid = new GridLayout(5,1);
FlowLayout flow = new FlowLayout(FlowLayout.RIGHT);
setLayout(grid);
JPanel redPanel = new JPanel();
redPanel.setLayout(flow);
redPanel.add(redLabel);
redPanel.add(red);
add(redPanel);
JPanel greenPanel = new JPanel();
greenPanel.setLayout(flow);
greenPanel.add(greenLabel);
greenPanel.add(green);
add(greenPanel);
JPanel bluePanel = new JPanel();
bluePanel.setLayout(flow);
bluePanel.add(blueLabel);
bluePanel.add(blue);
add(bluePanel);
add(color);
add(paint);
setVisible(true);
}
public void stateChanged(ChangeEvent e){
JSlider source = (JSlider) e.getSource();
if(source.getValueIsAdjusting() != true){
Color mainColor = new Color(red.getValue(),
green.getValue(),
blue.getValue());
color.changeColor(mainColor);
color.repaint();
}
}
public static void main(String[] args){
Paint p = new Paint();
}
}
class PaintPanel extends JPanel{
Color background;
public PaintPanel(){
background = Color.red;
}
public void paintComponent(Graphics comp){
Graphics2D comp2D = (Graphics2D) comp;
comp2D.setColor(background);
comp2D.fillRect(0,0,getSize().width,getSize().height);
}
void changeColor(Color newBackground){
background = newBackground;
}
}
class PaintPanel2 extends JPanel{
Image image;
Graphics2D comp2D;
int currentX, currentY, oldX, oldY;
PaintPanel color;
public PaintPanel2(){
color = new PaintPanel();
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
oldX = e.getX();
oldY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
currentX = e.getX();
currentY = e.getY();
if(comp2D != null)
comp2D.drawLine(oldX, oldY, currentX, currentY);
repaint();
oldX = currentX;
oldY = currentY;
}
});
}
public void paintComponent(Graphics comp){
if(image == null){
image = createImage(getSize().width, getSize().height);
comp2D = (Graphics2D)image.getGraphics();
comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
comp2D.setPaint(Color.white);
comp2D.fillRect(0, 0, getSize().width, getSize().height);
comp2D.setPaint(Color.blue);
repaint();
}
comp.drawImage(image, 0, 0, null);
}
}
The problem was that you weren't setting the chosen color in PaintPanel2. I changed the stateChanged method and the PaintPanel2 as follows, and now it works as I assume you intended:
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider) e.getSource();
if (source.getValueIsAdjusting() != true) {
Color mainColor = new Color(red.getValue(),
green.getValue(),
blue.getValue());
color.changeColor(mainColor);
paint.setPaintColor(mainColor);
color.repaint();
}
}
class PaintPanel2 extends JPanel {
Image image;
Graphics2D comp2D;
int currentX, currentY, oldX, oldY;
public PaintPanel2() {
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
oldX = e.getX();
oldY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
currentX = e.getX();
currentY = e.getY();
if (comp2D != null) {
comp2D.drawLine(oldX, oldY, currentX, currentY);
}
repaint();
oldX = currentX;
oldY = currentY;
}
});
}
public void paintComponent(Graphics comp) {
if (image == null) {
image = createImage(getSize().width, getSize().height);
comp2D = (Graphics2D) image.getGraphics();
comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
comp2D.setPaint(Color.white);
comp2D.fillRect(0, 0, getSize().width, getSize().height);
comp2D.setPaint(Color.blue);
repaint();
}
comp.drawImage(image, 0, 0, null);
}
public void setPaintColor(Color color) {
comp2D.setColor(color);
}
}

Object issues in Java

I'm attempting to implement the dragging functionality of shapes on a canvas. My Shape class inherits from JPanel.
Absolutely nothing happens when I click on a shape, drag it and let go of the mouse button. It just remains where it was originally. Any ideas?
You need a few basic things:
A field for the shape itself (you already had)
Fields to keep track of the offset of the click within the shape (already had)
A field to keep track of if you're dragging
Overwrite the paintComponent method to paint your shape
A MouseListener and MouseMotionListener added to the Panel (MouseAdapter does both of these)
Here's a basic working example.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DrawTest extends JPanel{
//Shape doesn't have a location field - you'd have to keep track of
//this yourself if you're set on using the shape interface
private Rectangle shape = new Rectangle(100, 100);
// The location within the shape you clicked
private int xOffset = 0;
private int yOffset = 0;
// To indicate dragging is happening
boolean isDragging = false;
public DrawTest(){
MouseAdapter listener = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
// Starts dragging and calculates offset
if(shape.contains(e.getPoint())){
isDragging = true;
xOffset = e.getPoint().x - shape.x;
yOffset = e.getPoint().y - shape.y;
}
}
#Override
public void mouseReleased(MouseEvent e) {
// Ends dragging
isDragging = false;
}
#Override
public void mouseDragged(MouseEvent e) {
// Moves the shape - doesn't actually need to be a method
// but is because you had it as one
if(isDragging){
moveShape(e);
}
}
private void moveShape(MouseEvent e) {
Point newLocation = e.getPoint();
newLocation.x -= xOffset;
newLocation.y -= yOffset;
shape.setLocation(newLocation);
repaint();
}
};
//Add a mouse mostion listener (for dragging) and regular listener (for clicking)
addMouseListener(listener);
addMouseMotionListener(listener);
}
// So we have a play area to work with
public Dimension getPreferredSize(){
return new Dimension(400,300);
}
//Paints the shape
public void paintComponent(Graphics g){
super.paintComponent(g);
g.clearRect(0,0,getWidth(), getHeight());
g.fillRect(shape.x, shape.y, shape.width, shape.height);
}
public static void main(String[] args)
{
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawTest());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Tried a small simple example
Dragging the rectangle will make it move with the cursor it also checks the bounds so the rectangle cannot be dragged off screen:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ShapeMover {
public ShapeMover() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Shape Mover");
initComponents(frame);
frame.pack();
frame.setVisible(true);
}
public static void main(String s[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ShapeMover();
}
});
}
private void initComponents(JFrame frame) {
frame.getContentPane().add(new DragPanel());
}
}
class DragPanel extends JPanel {
Rectangle rect = new Rectangle(0, 0, 100, 50);
int preX, preY;
boolean isFirstTime = true;
Rectangle area;
boolean pressOut = false;
private Dimension dim = new Dimension(400, 300);
public DragPanel() {
setBackground(Color.white);
addMouseMotionListener(new MyMouseAdapter());
addMouseListener(new MyMouseAdapter());
}
#Override
public Dimension getPreferredSize() {
return dim;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (isFirstTime) {
area = new Rectangle(dim);
rect.setLocation(50, 50);
isFirstTime = false;
}
g2d.setColor(Color.black);
g2d.fill(rect);
}
boolean checkRect() {
if (area == null) {
return false;
}
if (area.contains(rect.x, rect.y, 100, 50)) {
return true;
}
int new_x = rect.x;
int new_y = rect.y;
if ((rect.x + 100) > area.getWidth()) {
new_x = (int) area.getWidth() - 99;
}
if (rect.x < 0) {
new_x = -1;
}
if ((rect.y + 50) > area.getHeight()) {
new_y = (int) area.getHeight() - 49;
}
if (rect.y < 0) {
new_y = -1;
}
rect.setLocation(new_x, new_y);
return false;
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
preX = rect.x - e.getX();
preY = rect.y - e.getY();
if (rect.contains(e.getX(), e.getY())) {
updateLocation(e);
} else {
pressOut = true;
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (!pressOut) {
updateLocation(e);
} else {
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (rect.contains(e.getX(), e.getY())) {
updateLocation(e);
} else {
pressOut = false;
}
}
public void updateLocation(MouseEvent e) {
rect.setLocation(preX + e.getX(), preY + e.getY());
checkRect();
repaint();
}
}
}
Reference:
http://www.java2s.com/Code/Java/Event/MoveShapewithmouse.htm

Categories