Ok so this is a shape drawn with a random color, however I'd like that shape to stay that color while being repainted. Right now with this draw method it just draws a new random color every repaint() so it looks like a rainbow shape. How would I make it grab a random color then stick with that for that particular shape?
public void draw(Graphics g) {
g.setColor(new Color(randomNum.nextInt(256), randomNum.nextInt(256), randomNum.nextInt(256)));
g.fillOval((int)getX(),(int)getY(), getRadius(), getRadius());
}
By saving the color you're drawing.
So you'll only randomly generate it once, and then keep using that color to redraw each time.
Either generate it before the draw like Color c = new Color(randomNum.nextInt(256), randomNum.nextInt(256), randomNum.nextInt(256)); or only generate the variable and test if it has been initialized in your draw method. If it hasn't (the first time running your code), you generate a random color, if it has been initialized, you just skip generating the color and go straight to your g.fillOval
You keep a list of shapes. every shape has his color and radius.
when repaint, you draw every shape in the list.
static class OvalShape {Color color; int radius;}
List<OvalShape> shapeList = new ArrayList<>();
public void draw(Graphics g) {
for(Shape s : shapeList) {
g.setColor(s.color);
g.fillOval((int)getX(),(int)getY(), s.radius, s.radius);
}
}
Related
I've been working on a simple paint program and I have recently run into a snag when redrawing shapes in my paint component.
#Override
public void paintComponent(final Graphics theGraphics) {
super.paintComponent(theGraphics);
final Graphics2D g2d = (Graphics2D) theGraphics;
if (!preDrawnShapes.isEmpty() && !preDrawnShapeThickness.isEmpty()) {
for (int i = 0; i < preDrawnShapes.size(); i++) {
g2d.setStroke(new BasicStroke(preDrawnShapeThickness.get(i)));
g2d.draw(preDrawnShapes.get(i));
}
}
g2d.setStroke(new BasicStroke(currentThickness));
if (myShape != null) {
g2d.draw(myShape);
preDrawnShapeThickness.add(currentThickness);
}
}
This paintComponenent is supposed to first redraw the shapes previously drawn before before then drawing the new shape created from user input.
For some reason, the shape thickness when drawing the new shape is set to the current thickness but any shape that I drew before had a default thickness of 1.
preDrawnShapes is a Shapes ArrayList and preDrawnShapeThickiness is a Float Arraylist.
Am I missing something here?
UPDATE: I've discovered that PreDrawnShapeThickness stores only Floats of zero. I am unsure why.
There are two common ways to do incremental painting:
Keep a List of Objects that you want to paint. Then the paintComponent() method iterates through the List and paints each object. So in your case the custom object would contain the Shape you want to paint and an int value for the thickness of the shape.
Just paint each Object directly to a BufferedImage. Then you can just use a JLabel to display the BufferedImage as an Icon, or do custom painting to paint the BufferedImage.
Check out Custom Painting Approaches for examples of both approaches.
In this program I am doing, I need to be able to fill shapes with random colors. I am confused on how to actually fill in the shape. I am able to generate a random color. I have looked around online and found some sources talk about implementing the Paint interface and use the method setPaint() on the shape you are wishing to draw and then invoke the fill method. I tried this but was unsuccessful. Maybe I just had it wrong. Here is what I had.
Random rand = new Random();
float r = rand.nextFloat();
float g = rand.nextFloat();
float b = rand.nextFloat();
Color randomColor = new Color (r, g, b);
This was in a constructor of a superclass where I actually have randomColor as an attribute of the class. So to access that element in the subclass, I provide a basic getter that just returns the Color.
In the subclass I have this:
Rectangle2D.Double rectangle = new Rectangle2D.Double(getX(), getY(), getWidth(), height);
rectangle.setPaint(getColor());
rectangle.fill();
g2.draw(rectangle);
The error I am getting is something about typecasting rectangle but any typecast I try it's not working. I'm not exactly sure how to fix this issue. Any ideas? Or is there an easier/better way to fill a shape with a random color? Thanks.
You should be calling the methods you are calling on the rectangle on the Graphics2D
Rectangle2D.Double rectangle = new Rectangle2D.Double(getX(), getY(), getWidth(), height);
g2.setPaint(getColor());
g2.fill(rectangle);
g2.draw(rectangle);
I need to be able to fill shapes with random colors
Then you should create a class (ColoredShape) that contains two properties:
Shape
Color
Then you can create an ArrayList to hold instances of this class.
ArrayList<ColoredShape> shapes = new ArrayList<ColoredShape>();
shapes.add( new ColoredShape(aShape, generateRandomColor());
shapes.add( new ColoredShape(anotherShape, generateRandomColor());
Then in the paintComponent() method of your panel you iterate through the ArrayList and paint all the shapes:
for (ColoredShape shape: shapes)
{
g2.setColor(shape.getColor());
g2.draw(shape.getShape());
}
For a working example of this approach check out the DrawOnComponent example found in Custom Painting Approaches.
I'm coding a GUI that will be doing some graphics translations/rotations, etc.
My problem is that when I try to translate my graphics,
(a) The entire screen translates instead of my one little painted area
(b) The old paint stays there, leaving a big paint blob instead of a translated image
(c) If I use the clearRect method to allow me to avoid (b), the entire screen goes white and (a) is still a problem
my DrawPanel class (I called it "LaunchTubeImage" for whatever reason)
private class LaunchTubeImage extends JPanel {
private Color colour;
public LaunchTubeImage(Color color) {
super();
this.colour = color;
}
public void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D)g;
double theta = (double)angle.getValue();
theta = Math.toRadians(theta);
gg.rotate(theta,tubeImage.getSize().width/2 + 10,
tubeImage.getSize().height - 50);
g.setColor(colour);
g.clearRect(0,0,getWidth(),getHeight());
g.fillRect(tubeImage.getSize().width/2,
tubeImage.getSize().height - 100 , 10, 50);
}
}
where this is called in my code
tubeImage = new LaunchTubeImage(Color.MAGENTA);
angle.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent e) {
tubeImage.repaint();
}
});
Case 1: Comment out clearRect in that 1st block of code I posted
http://i58.tinypic.com/2d1l5w2_th.png
Black background as desired. Not rotated yet. Looks good so far.
http://oi60.tinypic.com/1zw1sm.jpg
Rotated it with my JSpinner... you see that the previous location was not removed (and note how my buttons randomly doubled and put themselves at the top of the screen).
Case 2: Keeping in the clearRect method
oi57.tinypic.com/2s84307.jpg
Layout is fine so far, but I wanted the background to be black
oi57.tinypic.com/4rde8x.jpg
Yay! It rotated. But note the weird behavior of that random "15" that appeared in my top right corner
oi58.tinypic.com/vymljm.jpg
And finally... when I resize the window you see that my entire screen was rotated - not just the pink image I wanted to rotate
Tips/fixes/advice? Thanks!! I hope I've provided enough information
(P.s. if you insist on us asking clear/useful questions.... then DON'T limit the number of images you can post... :/ )
The first line of an overridden paintComponent method should usually be super.paintComponent(g). On a JPanel, this will cause the drawing area to be cleared with the background color. If you want to clear the background with a different color, you can do this by manually filling a rectangle (clearRect is discouraged, see the JavaDoc), but of course, this has to be done before applying any transform.
So your method should probably look like this:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(colour);
g.fillRect(0,0,getWidth(),getHeight());
Graphics2D gg = (Graphics2D)g;
double theta = (double)angle.getValue();
theta = Math.toRadians(theta);
gg.rotate(theta,tubeImage.getSize().width/2 + 10,tubeImage.getSize().height - 50);
gg.fillRect(tubeImage.getSize().width/2,tubeImage.getSize().height - 100 , 10, 50);
}
i have created a simple program in Java for painting Graphic primitives (Lines,Rectangles,Ellipses,etc.).The shapes are drawn on the screen with dragging the mouse and stored into an array of Shapes,so i have added a slider for getting the stroke size (from 1 to 20 with 1 being default value) dynamically,but it updates all the shapes that are previously drawn as well.
//NOTE1: Graphics2D graph; is defined in the class extending JFrame
//NOTE2: strokeSize value is dynamically changing with the slider
public void paint(Graphics g)
{
graph = (Graphics2D)g;
graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
graph.setStroke(new BasicStroke(strokeSize));
for (Shape currentShape : shapes)
{
graph.setPaint(strokeCounter.next());
graph.draw(currentShape);
graph.setPaint(fillCounter.next());
graph.fill(currentShape);
}
//What follows are If statements for choosing a shape
//and actual methods for drawing them...
So my question is:How to update the strokeSize,but only for shapes currently being drawn?
Store the stroke size along with the shape. Set the stroke size before issuing the draw command.
Add graph.setStroke(new BasicStroke(currentShape.getStrokeSize())); before graph.draw(currentShape);
You'll need to add a property called StrokeSize to your Shape class.
Okay, so I have a GameField class, and a GameObject class and a Panel class.
The GameObject class describes an object, which has an x and y position, width and height, and x and y direction (in which it is currently moving). The GameField class has a few different instances of these objects, some stored by themselves, and some stored in primitive arrays.
The Panel class is supposed to display these objects on the screen. I used JPanel for this.
However, when it comes to actually displaying them on the screen, I'm a bit lost. I need to implement a function called paintComponent(Graphics graphics), which takes in a Graphics object.
To start, I want to display all the objects on the screen, and set their colour. Their size, position, etc. are handled elsewhere. How can I use these attributes to set the actual objects to have a size, position and direction?
I may need to override the paintComponent function to display all the objects in GameField.
If you could help me out with some code, that'd be great.
I'm not quite clear on what you mean by "their size, position, etc. are handled elsewhere". For now, let's assume that you have approximately the following structure (fields and other methods ommitted for clarity) :
class GameObject {
java.awt.Color getColor() { ... }
java.awt.Point getPosition() { ... }
java.awt.Point getDirection() { ... }
java.awt.Dimension getSize { ... }
}
class GameField {
List<GameObject> getGameObjects() { ... }
}
class Panel extends JPanel {
private GameField getGameField() { ... }
#Override
public void paintComponent(Graphics g) {
// this is where the GameObjects must be painted
}
}
The paintComponent method is responsible for the screen representation of the Panel class. If you override it, you have just won that responsibility from it. Luckily, drawing is - if tedious - rather simple. You asked about that Graphics parameter. Very simply put, it is set for you by the magic of Java and gives you a toolbox to use for drawing.
First, you will want to have a clean slate whenever the panel is repainted. You cannot delete anything once it is painted, but you can easily paint the entire panel in a background color of your choice.
g.setColor(Color.white); // everything that is now painted will be white
g.fillRect(0, 0, getWidth(), getHeight()); // fills the entire area with the set color
Now, for each GameObject you have, let's place rectangle in the objects' defined color and size on the screen, with it's center on the object's position.
for (GameObject object : getGameField().getGameObjects()) {
g.setColor(object.getColor());
g.fillRect(object.getPosition().x - (object.getSize().x / 2), object.getPosition().y - object.getSize().y / 2, object.getSize().x, object.getSize().y);
}
The fillRect method requires the first two arguments to be the top-left corner of the rectangle. So to have it centered on the object's position, we subtract half the size from the position for the x and y values respectively. Now you have, for every GameObject, a rectangle of the right diameter in the object's color at the right position.
You should read up on the javadoc on java.awt.Graphics to find out how to draw other stuff, maybe image sprites or lines for the direction or something. It is cumbersome but doable.