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 );
Related
public void mouseEntered(MouseEvent e) {
int x = e.getX();
int y = e.getY();
m_View = new View(m_Mod);
int maxY = m_Mod.y1 + m_Mod.oheight;
int maxX = m_Mod.x1 + m_Mod.owidth;
if (x > m_Mod.x1 & x < maxX & y > m_Mod.y1 & x < maxY) {
Graphics g = m_Mod.frame.getGraphics();
m_View.draw(g);
System.out.print("IM KREIS");
}
}
Somehow my math does not work here. I want to redraw my oval as soon as the mouse enters it. So my graphics object "g" is my oval here. m_Mod.x1 / M_Mod.y1 is x and y of my oval and m_Mod.width / m_Mod.heigth are width and heigth of my oval.
As mentioned in comments, the key to a solution is to:
Do all drawing, all graphics and mouse listening within a single drawing JPanel
To specifically draw within the JPanel's paintComponent method override
To give your GUI a boolean field that is set to true
To use an Ellipse2D object to define your oval
To add a MouseMotionListener to the drawing JPanel
Within this MouseMotionListener, check if the mouse point is within the ellipse
Then set the boolean field with this result and call repaint()
The paintComponent method will then determine what to draw based on the state of the boolean
For example, in the code below I have an Ellise2D field,
private Ellipse2D myOval = new Ellipse2D.Double(OVAL_X, OVAL_Y, OVAL_W, OVAL_H);
Then there is a boolean field, private boolean insideOval = false; that is set to false and that is changed within a MouseMotionListener to true if the mouse point is within the ellpise (here called myOval):
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
// true if the mouse point is within the oval. Otherwise false
insideOval = myOval.contains(e.getPoint());
// redraw the JPanel to draw the state of insideOval
repaint();
}
});
Then the paintComponent method will use the state of insideOval to determine what color to fill the oval with, an "active color" if the boolean is true and a clear color if not:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // does house-keeping drawing
Graphics2D g2 = (Graphics2D)g;
// allow for smooth curves
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// vary the oval fill color depending on the state of the insideOval field
Color c = insideOval ? ACTIVE_COLOR : INACTIVE_COLOR;
g2.setColor(c);
// fill the oval
g2.fill(myOval);
// then draw the oval's border
g2.setColor(OVAL_BORDER);
g2.setStroke(BORDER_STROKE);
g2.draw(myOval);
}
For example:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
// main JPanel dimensions
private static final int PREF_W = 600;
private static final int PREF_H = 600;
// oval dimensions
private static final double OVAL_X = 100;
private static final double OVAL_Y = OVAL_X;
private static final double OVAL_W = 400;
private static final double OVAL_H = OVAL_W;
// oval colors
private static final Color INACTIVE_COLOR = new Color(0, 0, 0, 0); // clear
private static final Color ACTIVE_COLOR = Color.PINK;
private static final Color OVAL_BORDER = Color.LIGHT_GRAY;
// thickness of mouse border
private static final Stroke BORDER_STROKE = new BasicStroke(4f);
// Oval to draw and boolean to tell if mouse within the oval
private Ellipse2D myOval = new Ellipse2D.Double(OVAL_X, OVAL_Y, OVAL_W, OVAL_H);
private boolean insideOval = false;
public DrawingPanel() {
// add a mouse motion listener to this same drawing JPanel
// and inside of it, check if the mouse point is inside or outside
// of the oval.
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
// true if the mouse point is within the oval. Otherwise false
insideOval = myOval.contains(e.getPoint());
// redraw the JPanel to draw the state of insideOval
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return getPreferredSize();
} else {
return new Dimension(PREF_W, PREF_H);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // does house-keeping drawing
Graphics2D g2 = (Graphics2D)g;
// allow for smooth curves
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// vary the oval fill color depending on the state of the insideOval field
Color c = insideOval ? ACTIVE_COLOR : INACTIVE_COLOR;
g2.setColor(c);
// fill the oval
g2.fill(myOval);
// then draw the oval's border
g2.setColor(OVAL_BORDER);
g2.setStroke(BORDER_STROKE);
g2.draw(myOval);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
DrawingPanel mainPanel = new DrawingPanel();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
I am working on a project, develop a game called
Don't get mad bro.
I have a JPanel with shapes (circles) draw on it and JLabel components that contains images.I need that whenever I click "Throw dice" (which in background return a number between 1 and 6) I should wait for current player to click on one of his pawns, and that pawn should move after n positions, where n is equal with number that dice returned.
My question is, should I create a new thread in which I wait for mouseClick event? And how to get coordinates of mouseClick?
Here is my class that inherits panel and draw circles and add labels.
public class ImagePanel extends JPanel{
private static final long serialVersionUID = 1L;
ImageMatrix imageMatrix;
BufferedImage[] images;
public static JLabel[][] labels;
DrawGameBoard board = new DrawGameBoard();
List<GameFigure> gameCircles;
List<FinishFigure> finishCircles;
int initialHeight = 528;
int initialWidth = 596;
ThreadForPawnsClick labelsClick;
public ImagePanel(){
labels = new JLabel[4][4];
images = new BufferedImage[4];
setBackground(new Color(255,255,153));
gameCircles = new ArrayList<GameFigure>();
finishCircles = new ArrayList<FinishFigure>();
imageMatrix = new ImageMatrix(initialWidth,initialHeight);
try {
images[0] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\red.png"));
images[1] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\green.png"));
images[2] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\blue.png"));
images[3] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\yellow.png"));
} catch (IOException e) {
e.printStackTrace();
}
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
labels[i][j] = new JLabel(new ImageIcon(images[i]));
}
setLayout(null);
board.DrawHomeBoard(imageMatrix, labels);
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
add(labels[i][j]);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
int width = this.getWidth();
int height = this.getHeight();
imageMatrix.update(width, height);
setLayout(null);
gameCircles = board.DrawMainBoard(g, imageMatrix);
//labels = board.DrawHomeBoard(g, imageMatrix, labels);
//board.DrawHomeBoard(imageMatrix, labels);
finishCircles = board.DrawFinishBoard(g, imageMatrix);
/*for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
add(labels[i][j]);
*/
}
}
Also, why my imageMatrix doesn't extend on whole screen, even if I call update matrix in paintComponent()?
My question is, should I create a new thread in which I wait for mouseClick event?
No, absolutely not. You need instead to change the state of the GUI somehow to wait-for-mouse-click mode, and then alter the behavior of the GUI's response to mouse clicks depending on its state. Usually state is represented by instance fields of the class. So when you need to wait, you change one of these state fields, and on mouse click, you check the state of the field and vary what happens depending on that. For instance in a turn based game of chess, one state field could be private boolean blackTurn, and then base what mouse does based on its state.
And how to get coordinates of mouseClick?
In the MouseListener the MouseEvent parameter gives you the x and y position of the mouse relative to the listened to component and to the screen. If your MouseListener is attached to the JLabels, then you can get a reference to the clicked JLabel via the MouseEvent's getSource() method, and then can get the location of the JLabel relative to its container JPanel (if needed) by calling getLocation() on it.
Side note: in a Swing GUI where you're moving around sprites, it's usually better not to put the sprites into JLabels but rather to simply draw them directly in the paintComponent method of a drawing JPanel.
As an example of what I mean, here is a program that draws 4 colored circles, circles that are draggable, but only draggable when the corresponding JRadioButton has been selected with the JRadioButton setting the "state" of the GUI. Here the state is represented by an enum called ColorState that holds 4 colors and corresponding text. Here is this enum:
import java.awt.Color;
public enum ColorState {
RED("Red", Color.RED),
GREEN("Green", Color.GREEN),
BLUE("Blue", Color.BLUE),
ORANGE("Orange", Color.ORANGE);
private String text;
private Color color;
private ColorState(String text, Color color) {
this.text = text;
this.color = color;
}
public String getText() {
return text;
}
public Color getColor() {
return color;
}
}
Then we create a drawing JPanel, one that holds four Ellipse2D Shape objects in a Map,
private Map<ColorState, Shape> colorStateMap = new EnumMap<>(ColorState.class);
Within a for loop, we create the JRadioButtons, give them ActionListeners that set the object's state, and populate the Map with Ellipse2D Shape objects
for (final ColorState state : ColorState.values()) {
// create the JRadioButton
JRadioButton radioButton = new JRadioButton(state.getText());
add(radioButton); // add to GUI
buttonGroup.add(radioButton); // add to ButtonGroup
// give it an ActionListener that changes the object's state
radioButton.addActionListener(e -> {
colorState = state;
});
// create a randomly placed Ellipse2D and place into Map:
double x = Math.random() * (W - CIRCLE_WIDTH);
double y = Math.random() * (H - CIRCLE_WIDTH);
Ellipse2D ellipse = new Ellipse2D.Double(x, y, CIRCLE_WIDTH, CIRCLE_WIDTH);
colorStateMap.put(state, ellipse);
}
We draw the ellipses within paintComponent:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// make for smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through the enum, extracting the ellipse and drawing it
for (ColorState state : ColorState.values()) {
Shape shape = colorStateMap.get(state);
if (shape != null) {
g2.setColor(state.getColor());
g2.fill(shape); // draw the ellipse
}
}
}
Finally in a MouseAdapter (both MouseListener and MouseMotionListener), we listen for mouse presses and register success if the left mouse is clicked and if it is clicked within the appropriate Shape:
private class MyMouse extends MouseAdapter {
private Shape selectedShape = null;
private Point2D offset = null;
#Override
public void mousePressed(MouseEvent e) {
// check that correct button pressed
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
// has our colorState been set yet? If not, exit
if (colorState == null) {
return;
}
// is an appropriate Shape held by the Map? If so, get it
Shape shape = colorStateMap.get(colorState);
if (shape == null) {
return;
}
// does this shape contain the point where the mouse was pressed?
if (!shape.contains(e.getPoint())) {
return;
}
// Get the selected shape, get the mouse point location relative to this shape
selectedShape = shape;
double x = e.getX() - shape.getBounds2D().getX();
double y = e.getY() - shape.getBounds2D().getY();
offset = new Point2D.Double(x, y);
}
#Override
public void mouseDragged(MouseEvent e) {
// drag shape to new location
if (selectedShape != null) {
double x = e.getX() - offset.getX();
double y = e.getY() - offset.getY();
Rectangle2D bounds = selectedShape.getBounds2D();
bounds.setFrame(new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight()));
((Ellipse2D) selectedShape).setFrame(bounds);
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
selectedShape = null;
}
}
Note that the mouse dragging code is thanks to MadProgrammer's answer here. Please up-vote this answer.
The entire class looks like so:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.*;
#SuppressWarnings("serial")
public class StateDependentMouseListener extends JPanel {
private static final int W = 800;
private static final int H = 650;
private static final double CIRCLE_WIDTH = 60.0;
private ButtonGroup buttonGroup = new ButtonGroup();
private ColorState colorState = null;
private Map<ColorState, Shape> colorStateMap = new EnumMap<>(ColorState.class);
public StateDependentMouseListener() {
setPreferredSize(new Dimension(W, H));
for (final ColorState state : ColorState.values()) {
// create the JRadioButton
JRadioButton radioButton = new JRadioButton(state.getText());
add(radioButton); // add to GUI
buttonGroup.add(radioButton); // add to ButtonGroup
// give it an ActionListener that changes the object's state
radioButton.addActionListener(e -> {
colorState = state;
});
// create a randomly placed Ellipse2D and place into Map:
double x = Math.random() * (W - CIRCLE_WIDTH);
double y = Math.random() * (H - CIRCLE_WIDTH);
Ellipse2D ellipse = new Ellipse2D.Double(x, y, CIRCLE_WIDTH, CIRCLE_WIDTH);
colorStateMap.put(state, ellipse);
}
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// make for smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through the enum, extracting the ellipse and drawing it
for (ColorState state : ColorState.values()) {
Shape shape = colorStateMap.get(state);
if (shape != null) {
g2.setColor(state.getColor());
g2.fill(shape); // draw the ellipse
}
}
}
private class MyMouse extends MouseAdapter {
private Shape selectedShape = null;
private Point2D offset = null;
#Override
public void mousePressed(MouseEvent e) {
// check that correct button pressed
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
// has our colorState been set yet? If not, exit
if (colorState == null) {
return;
}
// is an appropriate Shape held by the Map? If so, get it
Shape shape = colorStateMap.get(colorState);
if (shape == null) {
return;
}
// does this shape contain the point where the mouse was pressed?
if (!shape.contains(e.getPoint())) {
return;
}
// Get the selected shape, get the mouse point location relative to this shape
selectedShape = shape;
double x = e.getX() - shape.getBounds2D().getX();
double y = e.getY() - shape.getBounds2D().getY();
offset = new Point2D.Double(x, y);
}
#Override
public void mouseDragged(MouseEvent e) {
// drag shape to new location
if (selectedShape != null) {
double x = e.getX() - offset.getX();
double y = e.getY() - offset.getY();
Rectangle2D bounds = selectedShape.getBounds2D();
bounds.setFrame(new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight()));
((Ellipse2D) selectedShape).setFrame(bounds);
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
selectedShape = null;
}
}
private static void createAndShowGui() {
StateDependentMouseListener mainPanel = new StateDependentMouseListener();
JFrame frame = new JFrame("StateDependentMouseListener");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
I'm trying to draw multiple rectangles on a panel. I created an ArrayList<Shape> and initialized in my constructor. In my paintComponent method, I draw a rectangle and then add it to the ArrayList. But when I do that, the drawing outcome on my panel turns out weird. As I drag to draw my first rectangle, I get this:
Here's part of my code:
public class MyMouseListener extends MouseAdapter {
#Override
public void mousePressed(final MouseEvent theEvent) {
myStartPoint = theEvent.getPoint();
repaint();
}
#Override
public void mouseReleased(final MouseEvent theEvent) {
myEndPoint = theEvent.getPoint();
repaint();
}
}
public class MyMouseMotionHandler extends MouseMotionAdapter {
#Override
public void mouseDragged(final MouseEvent theEvent) {
myEndPoint = theEvent.getPoint();
repaint();
}
}
/**
* Paints some rectangles.
*
* #param theGraphics The graphics context to use for painting.
*/
#Override
public void paintComponent(final Graphics theGraphics) {
super.paintComponent(theGraphics);
final Graphics2D g2d = (Graphics2D) theGraphics;
// for better graphics display
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(new Color(51, 0, 111));
g2d.setStroke(new BasicStroke(3));
final double x = myStartPoint.getX();
final double y = myStartPoint.getY();
final double xEnd = myEndPoint.getX();
final double yEnd = myEndPoint.getY();
if (xEnd> x && yEnd > y) {
final Shape rectangle = new Rectangle2D.
Double(x, y, xEnd - x, yEnd - y);
g2d.draw(rectangle);
myDrawings.add(rectangle);
}
for (Shape s : myDrawings) {
g2d.draw(s);
}
}
Don't do any code logic within paintComponent -- that method is for drawing and drawing only, and that is the source of your bug. Add the rectangle to the ArrayList in the mouse listener, on mouse release.
When I have done a similar project, I usually have one Rectangle field that I use to draw with the mouse listener on mouse drag, and which is draw within paintComponent. Then on mouse release I place that rectangle into the ArrayList, and set the class field as null.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class RectangleDraw extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Color TEMP_RECT_COLOR = Color.LIGHT_GRAY;
private static final Color SHAPE_COLOR = Color.RED;
private Rectangle tempRect = null;
private List<Shape> shapes = new ArrayList<>();
public RectangleDraw() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// draw the temporary rectangle if not null
if (tempRect != null) {
g2.setColor(TEMP_RECT_COLOR);
g2.draw(tempRect);
}
// draw all the rectangles in the list
g2.setColor(SHAPE_COLOR);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
// size the GUI to my specification
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
// My mouse listener and mouse motion listener
private class MyMouse extends MouseAdapter {
private Point p1; // start point
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
// create temporary rectangle
tempRect = createRectangle(e);
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
tempRect = null; // null temp rectangle and
// add rectangle to List
shapes.add(createRectangle(e));
repaint();
}
// create a rectangle from start point and current point
private Rectangle createRectangle(MouseEvent e) {
Point p2 = e.getPoint();
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int w = Math.abs(p1.x - p2.x);
int h = Math.abs(p1.y - p2.y);
Rectangle rect = new Rectangle(x, y, w, h);
return rect;
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Rectangle Draw");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RectangleDraw());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
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);
}
}
}
I draw texts with Graphics.drawString but I want to draw Strings with rectangle background.
Use Graphics.fillRect or Graphics2D.fill before drawing the text.
Here's an example:
import java.awt.*;
import java.awt.geom.Rectangle2D;
import javax.swing.*;
public class FrameTestBase extends JFrame {
public static void main(String args[]) {
FrameTestBase t = new FrameTestBase();
t.add(new JComponent() {
public void paintComponent(Graphics g) {
String str = "hello world!";
Color textColor = Color.WHITE;
Color bgColor = Color.BLACK;
int x = 80;
int y = 50;
FontMetrics fm = g.getFontMetrics();
Rectangle2D rect = fm.getStringBounds(str, g);
g.setColor(bgColor);
g.fillRect(x,
y - fm.getAscent(),
(int) rect.getWidth(),
(int) rect.getHeight());
g.setColor(textColor);
g.drawString(str, x, y);
}
});
t.setDefaultCloseOperation(EXIT_ON_CLOSE);
t.setSize(400, 200);
t.setVisible(true);
}
}
Suggestion:
Use a JLabel
Set its opaque property to true via setOpaque(true);
Set its foreground color via setForeground(myForegroundColor);
Then set its background color via setBackground(myBackgroundColor);