I've been working on a Java Paint application for practice; however, the part I'm stuck at right now is how to change the color of my pen without changing the color of anything I have previously drawn? I've been advised to create another ArrayList and incorporate it into my paintComponent but now I'm confused and unsure of what to do. Can anyone help me? I didn't include my tester class but it has the buttons created already, this is just what my code does far.
package drawing;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class Drawing extends JPanel {
private final ArrayList<Point> points = new ArrayList<>();
private boolean drawingInProgress;
private Color shapeColor = Color.BLACK;
public void setShapeColor(Color color)
{
this.shapeColor = color;
}
public Drawing(){
setBackground(Color.white);
drawingInProgress = false;
addMouseListener(
new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent ev)
{
if(!drawingInProgress)
{
drawingInProgress = true;
} else {
drawingInProgress = false;
}
}
}
);
addMouseMotionListener(
new MouseMotionAdapter(){
#Override
public void mouseMoved(MouseEvent event)
{
if (drawingInProgress){
points.add(event.getPoint());
repaint();
} else {
}
}
}
);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
//g.setColor(shapeColor); What I had before that was wrong.
for (Point point: points)
g.fillOval(point.x, point.y, 8, 8);
}
public void red() {
shapeColor = Color.RED;
repaint();
}
public void blue() {
shapeColor = Color.BLUE;
repaint();
}
public void green() {
shapeColor = Color.GREEN;
repaint();
}
}
You could create pseudo "shape" which carries not just the information it needs to paint it self, but also the color (and any other properties)
public interface PaintShape {
public Rectangle getBounds();
public Color getColor();
public void paint(Graphics2D g2d);
}
Then you can create what ever shapes you want...
public abstract class AbstractPaintShape implements PaintShape {
private final Rectangle bounds;
private final Color color;
public AbstractPaintShape(Rectangle bounds, Color color) {
this.bounds = bounds;
this.color = color;
}
#Override
public Rectangle getBounds() {
return bounds;
}
#Override
public Color getColor() {
return color;
}
}
public class OvalPaintShape extends AbstractPaintShape {
private Ellipse2D oval;
public OvalPaintShape(Rectangle bounds, Color color) {
super(bounds, color);
oval = new Ellipse2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
}
#Override
public void paint(Graphics2D g2d) {
g2d.setColor(getColor());
g2d.fill(oval);
}
}
Or something similar
You should take a closer look at 2D Graphics and Working with Geometry for more ideas
One way to go would be to create a class like MyShape consisting of a list of points (like you already have) and a color.
For the whole painting you would have a list of such MyShape objects.
Now whenever the user begins to draw a line (i.e. mouse-down) you'd create a new MyShape object with the current color and collect all the mouse movements in the points list of the object until mouse-up.
In repaint you'd paint all MyShape's in the list of shapes, each with it's own color.
In this case where you store the points and repaint the list of points, you would have to save the color of each Point with the point information, and then upon drawing ask each point what color it is. Perhaps create a class ColoredPoint that also has a Color.
for (ColoredPoint cp : points) {
g.setColor(cp.getColor());
...
You can refactor this to store the shapes separately to what draws them.
public class Shape {
private final ArrayList<Point> points = new ArrayList<>();
public final Color color;
public Shape() {
this(Color.BLACK);
}
public Shape(final Color color) {
this.color = color;
}
public void addPoint(final Point point) {
this.points.add(point);
}
public List<Point> getPoints() {
return points;
}
}
Your drawing class would then have
public class Drawing extends JPanel {
private final List<Shape> shapes = new ArrayList<>():
// ...
// a mouse listener that creates shapes and gives them points
// ...
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Shape shape: shapes
g.setColor(shape.color);
for (Point point: shape.getPoints()) {
g.fillOval(point.x, point.y, 8, 8);
}
}
}
Related
I'm trying to create a JPanel to make a simple paint program that paints whenever the user drags their mouse. However, upon resizing the window, the graphics that I've already drawn disappear. Here is the PaintPanel class:
public class PaintPanel extends JPanel {
private static final long serialVersionUID = 4267027584083413157L;
private class MouseMotionHandler implements MouseMotionListener {
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
Graphics2D g2 = (Graphics2D)getGraphics();
g2.setPaint(color);
g2.fillOval(x, y, size, size);
}
public void mouseMoved(MouseEvent e) {
}
}
class JSliderHandler implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
JSlider colorChange = (JSlider)e.getSource();
if (!colorChange.getValueIsAdjusting()) {
colVal = (int)colorChange.getValue();
color = new Color(colVal, colVal, colVal);
System.out.print(colVal);
}
}
}
class JSpinnerHandler implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
JSpinner thickChange = (JSpinner)e.getSource();
size = (int)thickChange.getValue();
}
}
private Color color;
private int colVal = 0;
private int size;
public PaintPanel() {
color = new Color(colVal, colVal, colVal);
size = 8;
addMouseMotionListener(new MouseMotionHandler());
}
}
a simple paint program that paints whenever the user drags their mouse.
See Custom Painting Approaches. It demonstrates two common ways to do custom painting:
Store objects to paint in an ArrayList and then iterate through the ArrayList in the paintComponent(...) method to paint each Object
Paint directly to a BufferedImage and then just paint the BufferedImage.
I have program where I draw rectangles, however when I change the color of my graphics object(the mouse), it changes all of it too. Do I have to make another arraylist or is it possible to add on to existing one.
public class Rectangles extends JPanel {
private JRadioButton red, black;
private Color c;
private ArrayList<Point> points;
public Rectangles() {
setLayout(new FlowLayout());
setBackground(Color.white);
JPanel pane = new JPanel();
pane.setBackground(Color.gray);
points = new ArrayList<Point>();
addMouseListener(new MovementListener());
red = new JRadioButton("Red");
black = new JRadioButton("Black");
red.addActionListener(new ChangeColorListener());
black.addActionListener(new ChangeColorListener());
ButtonGroup group = new ButtonGroup();
group.add(red);
group.add(black);
red.setBackground(Color.red);
black.setBackground(Color.black);
add(pane);
pane.add(red);
pane.add(black);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(c);
for (int i = 0; i < points.size(); i++) {
Point p = points.get(i);
g.drawRect(p.x, p.y, 15, 15);
}
}
private class MovementListener extends MouseInputAdapter {
public void mouseClicked(MouseEvent ex) {
addMouseMotionListener(new MovementListener());
}
public void mouseMoved(MouseEvent ex) {
Point point = ex.getPoint();
points.add(point);
repaint();
}
}
private class ChangeColorListener implements ActionListener {
public void actionPerformed(ActionEvent ex) {
if (ex.getSource() == red) {
c = Color.red;
} else if (ex.getSource() == black) {
c = Color.black;
}
}
}
You will probably need to add another properties to these objects in the future. I recommend to create another class for that.
class MyPoint {
// if the values would be unchangeable make them final
private Point point;
private Color color;
public MyPoint(Point point, Color color) {
this.point = point;
this.color = color;
}
// getters
}
Also a small advice, in constructor you should only set the parameters. In your case I would create a method named "init()" and there create all there panels etc.
So what I want to achieve, is to create a simple program that lets the user create rectangles on the screen and then move them around.
I know that I can declare a new object in the code (i.e rectangle i = new rectangle(x,y,sizex,sizey)) however that will create only one, moreover it forces me to declare it in the code:
block1 = new block
block2 = new block
etc
Question is: How can I let the user create infinite rectangles with the use of lets say a button (not necessarily a button, it can be anything) and then let the user be capable of modyfing them (location/size etc).
Examples would be nice. I just feel there is a better way than declaring a gazillion objects in the code and then displaying them one by one. In C++ i could declare a malloc expandable container that would just hold the values, and then just display things using these values, not sure for java.
Simple code for reference:
public static void main(String[] args){
JFrame frame = new JFrame("A.L.T.E.S");
//Container container = frame.getContentPane();
frame.setSize(1024, 768);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Block object = new Block(10,10,20,20);
frame.add(object);
object.reDraw();
}
public class Block extends JPanel{
int yPos;
int xPos;
int xSize;
int ySize;
public Block(int xPos, int yPos, int xSize, int ySize){
this.xPos = xPos;
this.yPos = yPos;
this.xSize = xSize;
this.ySize = ySize;
}
public void setYPos(int yPos){
this.yPos = yPos;
}
public void setXPos(int xPos){
this.xPos = xPos;
}
public void setXSize(int xSize){
this.xSize = xSize;
}
public void setYSize(int ySize){
this.ySize = ySize;
}
public int getYPos(){
return yPos;
}
public int getXPos(){
return xPos;
}
public int getYSize(){
return ySize;
}
public int getXSize(){
return xSize;
}
public void reDraw(){
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(xPos, yPos, xSize, ySize);
}
}
Nothing in Java is simple.
First, Java already has a Rectangle class that holds the origin and size of a Rectangle. In your code, you're making all the rectangles blue. Suppose you want the user to set the color of a Rectangle. You can define your Block class like this.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
public class Block {
private Color color;
private Rectangle rectangle;
public Block(int x, int y, int width, int height) {
this(new Rectangle(x, y, width, height));
}
public Block(Rectangle rectangle) {
this.rectangle = rectangle;
this.color = Color.BLUE;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public Rectangle getRectangle() {
return rectangle;
}
public void draw(Graphics g) {
g.setColor(getColor());
g.fillRect(rectangle.x, rectangle.y,
rectangle.width, rectangle.height);
}
}
Next, you need a model class to hold all of the Blocks that your user defines.
Something like this BlockList class.
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
public class BlockList {
private List<Block> blockList;
public BlockList() {
this.blockList = new ArrayList<Block>();
}
public void init() {
this.blockList.clear();
}
public void addBlock(Block block) {
this.blockList.add(block);
}
public void draw(Graphics g) {
for (int i = 0; i < blockList.size(); i++) {
blockList.get(i).draw(g);
}
}
}
Now that you have your GUI model defined, you would build your GUI. Your drawing JPanel would call the draw method in your BlockList class.
I strongly suggest that you go through the Oracle tutorial on Swing. Go through the complete tutorial before you attempt to create a Swing GUI.
In java, use a Collection. In this case, use a List. You can create an ArrayList<Block>, then invoke add to add new rectangles. Then, you can iterate through this collection by using iterator, then calling hasNext and next on the iterator to find all the elements. I'm sure this brief hypnosis is going to be confusing, and if so, check out the Java Tutorial on Collections, which explains everything in all the detail you are going to need.
Here's my code in question:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
import sun.java2d.loops.DrawRect;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
public class Board extends JPanel implements MouseListener
{
//instance variables
private int width;
private int height;
private Block topLeft;
private Block topRight;
private Block botLeft;
private Block botRight;
public Board() //constructor
{
width = 200;
height = 200;
topLeft=new Block(0,0,width/2-10,height/2-10,Color.RED);
topRight=new Block(width/2,0,width/2-10,height/2-10,Color.GREEN);
botLeft=new Block(0,height/2,width/2-10,height/2-10,Color.BLUE);
botRight=new Block(width/2,height/2,width/2-10,height/2-10,Color.YELLOW);
setBackground(Color.WHITE);
setVisible(true);
//start trapping for mouse clicks
addMouseListener(this);
}
//initialization constructor
public Board(int w, int h) //constructor
{
width = w;
height = h;
topLeft=new Block(0,0,width/2-10,height/2-10,Color.RED);
topRight=new Block(width/2,0,width/2-10,height/2-10,Color.GREEN);
botLeft=new Block(0,height/2,width/2-10,height/2-10,Color.BLUE);
botRight=new Block(width/2,height/2,width/2-10,height/2-10,Color.YELLOW);
setBackground(Color.WHITE);
setVisible(true);
//start trapping for mouse clicks
addMouseListener(this);
}
public void update(Graphics window)
{
paint(window);
}
public void paintComponent(Graphics window)
{
super.paintComponent(window);
topRight.draw(window);
topLeft.draw(window);
botRight.draw(window);
botLeft.draw(window);
}
public void swapTopRowColors()
{
Color temp = topLeft.getColor(topRight);
topRight.setColor(temp);
repaint();
}
public void swapBottomRowColors()
{
}
public void swapLeftColumnColors()
{
}
public void swapRightColumnColors()
{
}
How would I swap the colors of 2 of these "squares" using the .getColor() method? I'm thinking I'm on the right track to achieving it but haven't had to do something like this with colors before.
You're going to need to use setColor(), but before that you need to create a temp of one of the colours.
public void swapColors(Block g1, Block g2) {
Color c = g1.getColor();
g1.setColor(g2.getColor());
g2.setColor(c);
repaint();
}
Also using this method header, you can swap two colours from the Block objects without needing a different method for each combination, just pass through the two you want to swap as arguments.
EDIT:
It seems you need to add a getters and setters to your Block class for color, so just add:
public Color getColor() {
return this.color;
}
public void setColor(Color c) {
this.color = c;
}
public void swapTopRowColors()
{
Color temp = topLeft.getColor(topRight);
topLeft.setColor(topRight.getColor()); //<-- line you're missing
topRight.setColor(temp);
repaint();
}
=== Following comment ===
you'll need to add getter and setter in your Block class:
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
You have 2 almost indentical constructors Board() and Board(h,w), su in default constructor call:
public Board() //constructor
{
Board(200,200);
}
If you use this method, in future you will need to edit only one constructor, not both.
I need some help with this program I have to create for Uni. The problem is that the setColor and getColor methods do no work, and the line doesn't change color when I want it too.
What do I need to do to change the color of the line to red?
Cheers
import java.awt.Color;
import java.awt.Point;
import javax.swing.JPanel;
import java.awt.*;
public class Shape extends JPanel {
static Point startPoint = new Point(0, 0);
Point controlPoint = new Point(0, 0);
Color colour = Color.BLACK;
public Shape() {
this(startPoint);
}
public Shape(Point startPoint) {
// initialise variable startPoint
this.startPoint = startPoint;
// execute methods setColour and setControlPoint
setColor(colour);
setControlPoint(controlPoint);
// change startPoint
startPoint.x = 50;
startPoint.y = 50;
}
public void setColor(Color colour) {
this.colour = colour;
colour = Color.RED;
}
public Color getColor() {
return colour;
}
public void setControlPoint(Point controlPoint) {
controlPoint.x = 150;
controlPoint.y = 150;
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
g.setColor(colour);
g.drawLine(startPoint.x, startPoint.y, controlPoint.x, controlPoint.y);
}
}
You need to call repaint() after the color is set
public void setColor(Color colour) {
this.colour = colour;
colour = Color.RED;
// Repaint so the component uses the new color
repaint();
}
Or, you can get rid of the setColor() method.
Then you can use:
setForeground( colour );
to control the color of the line to be drawn.
The color of the Graphics object will be set to the foreground colour so you can also get rid of:
g.setColor( colour );