I like working with Processing array functions but when I draw things using this function, I realize it's storing every single drawn shape in the memory, which is causing spikes in CPU. (Especially when it goes up to a few thousands)
How to bake the drawing then remove the array objects on mouserelease? I mean, can Processing behave those objects as a single image after every stroke then I'd clear the array using .remove(0) function?
Here's my code:
ArrayList <Drawing> drawings = new ArrayList <Drawing>();
void setup() {
size(400, 400);
background(255);
colorMode(HSB);
}
void draw() {
background(255);
for (int i=0;i<drawings.size();i++) {
drawings.get(i).display();
}
println(drawings.size());
}
void mouseDragged() {
drawings.add(new Drawing(mouseX, mouseY));
}
class Drawing {
float x, y, r;
color c;
Drawing(float ax, float ay) {
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255, 88);
}
void display() {
noStroke();
fill(c, 100);
ellipse(x,y, r, r);
}
}
If you want to store the objects into the ArrayList only while the mouse is pressed (drawing new objects) and just have all the old objects to be static on the background out of the ArrayList you can do something like this:
ArrayList<Drawing> drawings = new ArrayList();
boolean flag = false;
void setup()
{
size(400, 400);
background(255);
colorMode(HSB);
loadPixels();
}
void draw()
{
updatePixels();
if(flag)
{
for(Drawing drawing : drawings)
{
drawing.display();
}
}
println(drawings.size());
}
void mouseDragged()
{
flag = true;
Drawing drawing = new Drawing(mouseX, mouseY);
drawings.add(drawing);
}
void mouseReleased()
{
flag = false;
loadPixels();
drawings = new ArrayList();
}
class Drawing
{
float x, y, r;
color c;
Drawing(float ax, float ay)
{
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255, 88);
}
public void display()
{
noStroke();
fill(c, 100);
ellipse(x,y, r, r);
}
}
The function loadPixels() stores into the pixels[] array all the pixels of the screen, while updatePixels() draws the pixels in pixels[] on the canvas. This way you can just empty your ArrayList every time the mouse is released and, even though when the ArrayList gets some thousands of elements you still get some CPU spikes, when the mouse is not being dragged or the ArrayList has less than a couple thousands of elements it is less CPU consuming.
If you don't need to access the drawings objects later (say to change properties), you can simply cache the rendering onto a separate PGraphics layer:
PGraphics drawings;
void setup() {
size(400, 400);
colorMode(HSB);
drawings = createGraphics(width, height);
// use drawing commands between beginDraw() / endDraw() calls
drawings.beginDraw();
drawings.background(255);
drawings.colorMode(HSB);
drawings.noStroke();
drawings.endDraw();
}
void draw() {
background(255);
// PGraphics extends PImage so you can render it the same way
image(drawings, 0, 0);
println((int)frameRate);
}
void mouseDragged() {
drawRandomCircle(drawings, mouseX, mouseY);
}
void drawRandomCircle(PGraphics layer, float x, float y){
float diameter = random(2, 20);
layer.beginDraw();
layer.fill(color(random(100, 200), 255, 255, 88));
layer.ellipse(x, y, diameter, diameter);
layer.endDraw();
}
Otherwise you can make use of PShape:
PShape drawings;
void setup() {
size(400, 400, P2D);
smooth();
background(255);
colorMode(HSB);
// create a PShape group to append circles to later
drawings = createShape(GROUP);
}
void draw() {
background(255);
// render PShape
shape(drawings);
println(drawings.getChildCount() + " shapes at ~" + (int)frameRate + "fps");
}
void mouseDragged() {
drawings.addChild(addRandomCircle(mouseX, mouseY));
}
PShape addRandomCircle(float x, float y){
float diameter = random(2, 20);
// create an ellipse PShape with the desired dimensions, position, fill and (no)stroke
PShape circle = createShape(ELLIPSE, x, y, diameter, diameter);
circle.setFill(color(random(100, 200), 255, 255, 88));
circle.setStroke(false);
return circle;
}
As mentioned in my comment check out Processing > Examples > Demos > Performance > StaticParticlesRetained
If you need later access to each added circle/drawing you can iterate over the parent PShape:
// iterate though nested PShapes
for(int i = 0 ; i < drawings.getChildCount(); i++){
// access each PShape
PShape drawing = drawings.getChild(i);
// access PShape properties
println("drawings[" + i + "] has " + drawing.getVertexCount() + " vertices");
}
Should you need extra functionality (like a separate property to animate), you can always extend PShape: re-use what's already there add what you need on top:
PShape drawings;
void setup() {
size(400, 400, P2D);
smooth();
background(255);
colorMode(HSB);
// create a PShape group to append circles to later
drawings = createShape(GROUP);
}
void draw() {
background(255);
// use custom functionality
for(int i = 0 ; i < drawings.getChildCount(); i++){
// cast from PShape superclass to the custom Drawing subclass
Drawing drawing = (Drawing)drawings.getChild(i);
// use the custom functionality
drawing.update(i);
}
// render PShape
shape(drawings);
println(drawings.getChildCount() + " shapes at ~" + (int)frameRate + "fps");
}
void mouseDragged() {
drawings.addChild(new Drawing((PGraphicsOpenGL)g, mouseX, mouseY));
}
class Drawing extends PShapeOpenGL{
float x, y, diameter;
Drawing(PGraphicsOpenGL pg, float x, float y){
// call PShape super constructor setting this as a primitive (e.g. POINT, LINE, RECT, ELLIPSE, etc.)
super(pg, PShape.PRIMITIVE);
setKind(ELLIPSE);
diameter = random(2, 20);
// set (ellipse) shape parameters
setParams(new float[]{x, y, diameter, diameter});
// fill
setFill(color(random(100, 200), 255, 255, 88));
// disable stroke
setStroke(false);
// remember original position
this.x = x;
this.y = y;
}
// a custom functionality on top of PShape
void update(int index){
float offset = map(sin((frameCount + ((index+1) * 10)) * 0.025), -1.0, 1.0, -15, 15);
// reset transformations
this.resetMatrix();
// translate backwards
this.translate(-x, -y);
// translate back + the offset
this.translate(x + offset, y);
}
}
For the full list of functionalities see PShape javadocs
Starting with the simplest thing though. If you want to simply render many shapes without changing them later PGraphics will do the trick
Related
I am currently in the process of coding a kind of drawing tool in Processing. I want to be able to draw a black line with the mouse, but have it fade away again. For this I first thought of working with a black ellipse that fades from black to white. This ellipse is then linked to the mouse pointer via mouseX and mouseY. Because I want each drawn ellipse to fade from black to white individually (to create the effect that the line fades again), I thought of working with objects. This works so far, but the fading does not work yet.
I want the ellipse at the mouse pointer to always be black and then only change to white once the mouse pointer has been moved further or drawn further... just like a fade...
Should I use an ArrayList for this? And say that a new object should be drawn at the MouseX and MouseY position per frame? Do I need PVector for this?
This is what I came up for this so far:
float counter;
PGraphics pg;
Brush myBrush;
void setup() {
size(600, 600);
pg = createGraphics(width, height);
}
void draw() {
//background(255);
color from = color(0);
color to = color(255);
color faded = lerpColor(from, to, counter);
myBrush = new Brush(faded, mouseX, mouseY);
myBrush.display();
}
class Brush {
color tempC;
float xpos;
float ypos;
color c;
Brush(color tempC, float tempXpos, float tempYpos) {
c = tempC;
xpos = tempXpos;
ypos = tempYpos;
}
void display() {
noStroke();
fill(c);
ellipse(xpos, ypos, 50, 50);
counter = counter + 0.01;
}
}
The issue you're struggling with here is that you can only know how to fade the line once the line has been drawn, but you draw it while the user move the mouse.
To deal with this issue, I would suggest to store every information needed to draw the line in an object, and update it as the user is drawing. As you guessed, you could totally use an ArrayList to achieve this.
I modified your code quite heavily to simplify my own life, and I commented the result so it would be easier for you to re-cast it into your own project on your own terms.
I used objects to keep everything tidy. The logic here goes as follow: The Canvas object contains the drawing. It's made of Line objects, which are themselves made of Dots.
Here's the commented code:
Canvas canvas;
void setup() {
size(600, 600);
canvas = new Canvas();
}
void draw() {
// instead of drawing only once, we're going to save every line the user draw in teh canvas object
background(255);
// the canvas object has to calculate stuff, then display itself
canvas.Update();
canvas.Display();
}
// setting up the mousePressed and mouseReleased events so the canvas object "knows"
void mousePressed() {
canvas.mouseDown = true;
}
void mouseReleased() {
canvas.mouseReleased = true;
canvas.mouseDown = false;
}
class Canvas {
boolean mouseDown;
boolean mouseReleased = true;
ArrayList<Line> lines = new ArrayList<Line>(); // every line will be stored in this list
Brush brush; // the brush object can be modified with different sizes or colors
Canvas() {
// here i use a default brush, but you can experiment different colors or sizes
brush = new Brush(color(0, 200, 0), color(0), color(255), 50);
}
void Update() {
brush.highlight = mouseDown; // so the user has visual feedback while drawing
if (mouseDown) {
if (mouseReleased) { // if this is a "new" line, add a line object to store it
lines.add(new Line(brush.colorFrom, brush.colorTo));
mouseReleased = false;
}
// add a dot at the mouse's current position, then update the fading
lines.get(lines.size()-1).Add(new Dot(mouseX, mouseY, brush.diameter, brush.colorFrom));
lines.get(lines.size()-1).ApplyFade();
}
}
void Display() {
// for every Line, draw every Dot... then don't forget to display the brush!
for (Line l : lines) {
for (Dot d : l.dots) {
d.Display();
}
}
brush.Display();
}
}
// A line is a bunch of dots and two colord (for the fade effect)
class Line {
ArrayList<Dot> dots = new ArrayList<Dot>();
color colorFrom, colorTo;
Line(color colorFrom, color colorTo) {
this.colorFrom = colorFrom;
this.colorTo = colorTo;
}
void Add(Dot d) {
dots.add(d);
}
// This method calculate how many dots there are in the line to better distribute the shades of the fade
void ApplyFade() {
for (int i=0; i<dots.size(); i++) {
Dot d = dots.get(i);
d.c = lerpColor(colorFrom, colorTo, (float) i/dots.size());
}
}
}
// a Dot has a size, a position and a color
class Dot {
float xpos;
float ypos;
float diameter;
color c;
Dot(float xpos, float ypos, float diameter, color c) {
this.xpos = xpos;
this.ypos = ypos;
this.diameter = diameter;
this.c = c;
}
void Display() {
noStroke();
fill(c);
ellipse(xpos, ypos, diameter, diameter);
}
}
// this class is overdesigned so in the future you can change the brush's characteristics like the fade'S colors or simply it's size
class Brush {
boolean highlight;
float diameter, xpos, ypos;
color circleColor, colorFrom, colorTo;
Brush(color circleColor, color colorFrom, color colorTo, float diameter) {
this.circleColor = circleColor;
this.colorFrom = colorFrom;
this.colorTo = colorTo;
this.diameter = diameter;
}
void Display() {
stroke(circleColor);
strokeWeight(5);
noFill();
ellipse(mouseX, mouseY, diameter, diameter);
if (highlight) { // if the mouse's button is down, give visual feedback about the brush
stroke(0);
strokeWeight(4);
ellipse(mouseX, mouseY, diameter, diameter);
stroke(255);
strokeWeight(3);
ellipse(mouseX, mouseY, diameter, diameter);
}
}
}
Hope this helps. I'll be around if you have questions about the code. Have fun!
Here is a version with an ArrayList and Object... The problem here is that all ellipse objects fade away at the same time... I would like to achieve that each ellipse is first drawn black and then after time X becomes white... Like a fingerprint on a sensor for example... A lot of pressure: black, little pressure (or no pressure): fade to white... Later on I want to draw everything on a PGraphics layer – therefore there is alyready this variable...
float counter;
PGraphics pg;
ArrayList<PVector> positionsList;
Brush myBrush;
void setup() {
size(600, 600);
positionsList = new ArrayList<PVector>();
pg = createGraphics(width, height);
}
void draw() {
background(255);
color from = color(0);
color to = color(255);
color faded = lerpColor(from, to, counter);
for (PVector p : positionsList) {
myBrush = new Brush(faded, p.x, p.y);
myBrush.display();
}
positionsList.add(new PVector(mouseX, mouseY));
counter = counter + 0.01;
}
class Brush {
color tempC;
float xpos;
float ypos;
color c;
Brush(color tempC, float tempXpos, float tempYpos) {
c = tempC;
xpos = tempXpos;
ypos = tempYpos;
}
void display() {
noStroke();
fill(c);
ellipse(xpos, ypos, 50, 50);
}
}
I am trying to create a round brush with blurred edges in Processing through the following code. The circle shape is drawn pixel by pixel because in the actual version, I try to draw with pixels taken from the PGraphic pg.
PFont font;
PGraphics pg;
int X;
int Y;
int rad = 20;
void setup (){
size(800, 800, P2D);
background(0);
noStroke();
pg = createGraphics(800, 800, JAVA2D);
pg.beginDraw();
pg.fill(255);
pg.noStroke();
pg.textFont(font);
pg.textSize(400);
pg.pushMatrix();
pg.translate(width/2, height/2-140);
pg.textAlign(CENTER, CENTER);
pg.text("b", 0 , 0);
pg.popMatrix();
pg.endDraw();
}
void draw () {
image(pg,0,0);
}
void mousePressed(){
X = mouseX;
Y = mouseY;
}
void mouseDragged(){
for (int x=0; x<rad; x++) {
for (int y=0; y<rad; y++) {
float distance = sqrt(pow(x,2)+pow(y,2));
float alpha = 255-map(distance,0,rad,0,255);
if (sqrt(pow(x,2)+pow(y,2)) < rad){
pg.beginDraw();
pg.set(mouseX+x,mouseY+y,color(255,255,255, alpha));
pg.set(mouseX-x,mouseY+y,color(255,255,255, alpha));
pg.set(mouseX+x,mouseY-y,color(255,255,255, alpha));
pg.set(mouseX-x,mouseY-y,color(255,255,255, alpha));
pg.endDraw();
}
}
}
}
Create a function which draw a single dot to a PGraphics object:
void DrawPen(PGraphics pg, int cptX, int cptY, int r) {
pg.beginDraw();
for (int x = 0; x < r; ++x) {
for (int y = 0; y < r; ++y) {
float distance = sqrt(x*x + y*y);
float alpha = 255-map(distance,0,r,0,255);
if (distance < r) {
pg.set(cptX+x,cptY+y,color(255,255,255, alpha));
pg.set(cptX-x,cptY+y,color(255,255,255, alpha));
pg.set(cptX+x,cptY-y,color(255,255,255, alpha));
pg.set(cptX-x,cptY-y,color(255,255,255, alpha));
}
}
}
pg.endDraw();
}
Draw a dot to a separate PGraphics object in setup
PGraphics pg;
PGraphics pg_pen;
int rad = 20;
void setup (){
size(800, 800, P2D);
pg = createGraphics(800, 800, JAVA2D);
pg.beginDraw();
// [...]
pg.endDraw();
pg_pen = createGraphics(2*rad, 2*rad, JAVA2D);
DrawPen(pg_pen, rad, rad, rad);
}
When the mouse is dragged then blend the pg_pen to the common PGraphics object (pg) at the current mouse position:
void mouseDragged(){
pg.beginDraw();
pg.image(pg_pen, mouseX-rad, mouseY-rad);
pg.endDraw();
}
For the seek of completeness the draw function:
void draw () {
background(0);
image(pg,0,0);
}
[...] and tried to get the color from the white part to draw on the black part.
Add a color parameter to the DrawPen function and clear the pen PGraphics before drawing to it:
void DrawPen(PGraphics pg, int cptX, int cptY, int r, color c) {
pg.beginDraw();
pg.clear();
for (int x = 0; x < r; ++x) {
for (int y = 0; y < r; ++y) {
float distance = sqrt(x*x + y*y);
float alpha = 255-map(distance,0,r,0,255);
if (distance < r) {
color pc = color(red(c),green(c),blue(c), alpha);
pg.set(cptX+x,cptY+y,pc);
pg.set(cptX-x,cptY+y,pc);
pg.set(cptX+x,cptY-y,pc);
pg.set(cptX-x,cptY-y,pc);
}
}
}
pg.endDraw();
}
Get the color in the mouse pressed event call back and change the color of the pen:
void mousePressed() {
color c = pg.get(mouseX, mouseY);
println(c);
DrawPen(pg_pen, rad, rad, rad, c);
}
Note, the color is get from the pg object and not from the screen. If you want to get the color from the screen then it has to be (without .pg):
color c = get(mouseX, mouseY);
Further the color is changed any time when any mouse is pressed (pressed not dragged). Possibly you want to change the color when the right mouse button is pressed and paint when the left mouse button is pressed:
void mousePressed() {
if (mouseButton == RIGHT) {
color c = pg.get(mouseX, mouseY);
println(c);
DrawPen(pg_pen, rad, rad, rad, c);
}
}
add a "background(0);" before "image(pg,0,0);" in your drawing method, that way you reset the background every time, if you don't do that the program will keep drawing every frame images on top of each other's, which will make the low opacity pixel gain opacity slowly every frame until reaching 100%
void draw () {
background(0);
image(pg,0,0);
}
Edit:
After testing your code I noticed there was a problem with the way you were creating those circles, making it super slow to run (every frame you go through that double for loop to draw one circle ) and also gave that weird black edges problem, so here is what I did:
First I used your variable pg and drew one circle on it on the startup, Then I declared another PGraphics 'pg_all', where I drew one pg every call of the mousedrag method, I tested it on multiple backgrounds it seems like working fine, here is the final code, let me know if you didn't understand a part or want to do it differently:
PFont font;
PGraphics pg;
PGraphics pg_all;
int X;
int Y;
int rad = 20;
void setup (){
size(800, 800, P2D);
background(0);
noStroke();
pg_all = createGraphics(800, 800, JAVA2D);
pg_all.beginDraw();
pg_all.endDraw();
pg = createGraphics(800, 800, JAVA2D);
pg.beginDraw();
for (int x=0; x<rad; x++) {
for (int y=0; y<rad; y++) {
float distance = sqrt(pow(x,2)+pow(y,2));
float alpha = 255-map(distance,0,rad,0,255);
if (sqrt(pow(x,2)+pow(y,2)) < rad){
pg.beginDraw();
pg.set(20+x,20+y,color(255,255,255, alpha));
pg.set(20-x,20+y,color(255,255,255, alpha));
pg.set(20+x,20-y,color(255,255,255, alpha));
pg.set(20-x,20-y,color(255,255,255, alpha));
pg.endDraw();
}
}
}
pg.endDraw();
}
void draw () {
background(0);
image(pg_all,0,0);
}
void mouseDragged(){
X = mouseX;
Y = mouseY;
pg_all.beginDraw();
pg_all.image(pg,X-rad,Y-rad);
pg_all.endDraw();
}
So if you run this sketch you'll see a grid of plus signs. I want to rotate each individual but i can't seem to figure it out. I tried translate, pushMatrix/popMatrix. But maybe it's not on the right place. I removed it now, maybe someone can point out how to rotate each individual plus sign around its own axis.
int rib;
void setup() {
size(1200, 800);
rib = 7;
}
void draw() {
background(0);
for (int i = -100; i < width+100; i = i + rib * 10) {
for (int j = -100; j < height+100; j = j + rib * 10) {
noStroke();
fill(255);
plus(i, j);
plus(3*rib+i, 1*rib+j);
plus(6*rib+i, 2*rib+j);
plus(9*rib+i, 3*rib+j);
plus(2*rib+i, 4*rib+j);
plus(5*rib+i, 5*rib+j);
plus(8*rib+i, 6*rib+j);
plus(1*rib+i, 7*rib+j);
plus(4*rib+i, 8*rib+j);
plus(7*rib+i, 9*rib+j);
}
}
}
void plus(int x, int y) {
pushMatrix();
beginShape();
vertex(x+0, y+0);
vertex(x+0, y+-rib);
vertex(x+rib, y+-rib);
vertex(x+rib, y+0);
vertex(x+2*rib, y+0);
vertex(x+2*rib, y+rib);
vertex(x+rib, y+rib);
vertex(x+rib, y+2*rib);
vertex(x+0, y+2*rib);
vertex(x+0, y+rib);
vertex(x+-rib, y+rib);
vertex(x+-rib, y+0);
endShape(CLOSE);
popMatrix();
}
Step 1: Use pushMatrix() to save the state of the current matrix.
You need to do this because you don't want the rotations to accumulate. If you rotate one shape 30 degrees and another one 45 degrees, you don't want the second shape to be rotated (30+45) degrees.
Here is the reference for pushMatrix().
Step 2: Use translate() to move your shape where it needs to be.
Make sure you then draw your shape with that coordinate as the origin! Right now you're drawing the shapes with x,y as the origin, when you need to be using 0,0 as the origin after a translate.
Here is the reference for translate().
Step 3: Use rotate() to rotate your shape around the origin.
Remember, you've now "moved" 0,0 to the x,y you passsed into the translate() function!
Step 4: Draw your shape.
Again, remember to use 0,0 as the origin, not x,y.
Here is the reference for rotate().
Step 5: Call popMatrix() to restore the matrix you had when you called `pushMatrix()'.
This restores the rotation and translation back to normal, so the next translation and rotations don't accumulate.
Here is the reference for popMatrix().
Step 6: Repeat.
Put all of the above into a function and then call it from a for loop to draw more than one shape.
Here is a simplified examples that draws rectangles:
void setup() {
size(500, 500);
}
void draw() {
background(0);
noStroke();
fill(255);
plus(100, 100);
plus(200, 200);
}
void plus(float x, float y) {
pushMatrix();
translate(x, y);
rotate(mouseX);
rect(-20, -40, 40, 80);
popMatrix();
}
Rotation axis is always at origin (0,0). So we gotta translate the origin to where we want the axis of rotation to be. In your case, draw the plus with it's center at (0,0) and use translate to move it to desired position. I made this example using a simpler square, but the idea is the same. (I'm out of time here:)
See if this can help you.
void setup() {
size(1200, 800);
noStroke();
fill(255);
}
void draw() {
background(0);
float a = map(mouseY, 0, height, 30, 270);
for (int i = -100; i < width+100; i+=40) {
for (int j = -100; j < height+100; j+=40) {
plus(i, j, a);
}
}
}
void plus(int x, int y, float a) {
pushMatrix();
translate(x, y);
rotate(radians(a));
beginShape();
vertex(-10, -10);
vertex(10, -10);
vertex(10, 10);
vertex(-10, 10);
endShape(CLOSE);
popMatrix();
}
You might like these tutorials:
http://processing.org/tutorials/transform2d/
https://processing.org/tutorials/pshape/
Hello I would like to prevent graphics drawing and drawing again but I don't know how to do, I just want my panel delete all painted graphics and restart with same code. I tried some methods posted here but no one does the job.
public class Main extends JPanel implements ActionListener {
Timer timer;
private double angle = 444;
private double scale = 1;
private double delta = 0.0001;
RoundRectangle2D.Float r = new RoundRectangle2D.Float();
int counter = 0;
public Main() {
timer = new Timer(55, this);
timer.start();
}
public void paint(Graphics g) {
counter++;
int h = getHeight();
int w = getWidth();
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(new Color(randomNumber(0, 155), randomNumber(0, 255),randomNumber(0, 155), randomNumber(0, 255)));
drawCircles(g2d, getWidth()/2, getHeight()/2, 250);
if(counter > 200){
g2d.clearRect (0, 0, getWidth(), getHeight());
super.paintComponent(g2d);
counter = 0;
}
}
public int randomNumber(int min, int max) {
int c = new Random().nextInt((max - min) + 1);
return c;
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setUndecorated(true);
Dimension dim = new Dimension(Toolkit.getDefaultToolkit()
.getScreenSize().width, Toolkit.getDefaultToolkit()
.getScreenSize().height);
frame.setSize(dim);
frame.setLocation(0, 0);
frame.setBackground(new Color(0, 0, 0, 255));
frame.add(new Main());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
void drawCircles(Graphics graphics, int xMid, int yMid, int radius) {
// end recursion
if(radius < 5)
return;
// Draw circle
// start recursion
//left
drawCircles(graphics, xMid-radius, yMid, radius / 2);
((Graphics2D) graphics).rotate(angle);
graphics.drawOval(xMid - radius, yMid - radius, radius * 2, radius * 2);
//right
drawCircles(graphics, xMid+radius, yMid, radius / 2);
graphics.drawOval(xMid - radius, yMid - radius, radius * 2, radius * 2);
((Graphics2D) graphics).rotate(angle);
((Graphics2D) graphics).rotate(angle);
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
}
public void actionPerformed(ActionEvent e) {
if (scale < 0.01)
delta = -delta;
else if (scale > 0.99)
delta = -delta;
scale += delta;
angle += 0.001;
repaint();
}
}
I am not sure I understand you fully, but you can use a JToggleButton (for example) where is the toggle button is down it prevents drawing. I can see something like this inside your drawCircles() method:
void drawCircles(Graphics graphics, int xMid, int yMid, int radius)
{
if(!toggleBtn.isSelected() // the toggle button is pressed
{
// draw something
}
}
In your example, you are drawing two circles and two ovals. If I understood you correctly, you want to be able to pause in the middle of the method, for example, and only draw the first circle. Then, at some point, you want to continue drawing the two ovals and the remaining circle. Unfortunately, you cannot do that. You cannot stop (or pause) a method in the middle of it.
Methods have to execute to completion (whether to the end, or an exception is thrown). However, you can create some kind of task to draw ONE shape (for example, a circle). If you create multiple tasks, you can draw many circles. To accomplish this, you will need to learn about Concurrency and probably about Java Tasks. You can have these tasks execute in some kind of order and because of concurrency, you could pause and resume these drawing tasks the way I think you would want.
import javax.swing.*;
import java.awt.*;
public class JFrameAnimationTest extends JFrame {
public static void main(String[] args) throws Exception{
AnimationPanel animation = new AnimationPanel();
JFrameAnimationTest frame = new JFrameAnimationTest();
frame.setSize(600, 480);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(animation);
frame.setVisible(true);
for(int i = 0; i < 100; i++) {
animation.incX(1);
//animation.incY(1);
animation.repaint();
Thread.sleep(10);
}
}
}
class AnimationPanel extends JPanel {
int x = 10;
int y = 10;
public AnimationPanel() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawRect(x, y, 20, 20);
g.fillRect(x, y, 20, 20);
}
protected void incX(int X) {
x += X;
}
protected void incY(int Y) {
y += Y;
}
}
So anyways theres my code. It probably looks a bit jumbled as I am not used to stackoverflow just yet so I apologize.
Here's my question: This program makes this small rectangle slowly move to the right; how can I add rotation to the rectangles movement during that time period?
Note: I haven't actually compiled this code, but you get the gist.
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2d = (Graphics2D) g;
// The 20x20 rectangle that you want to draw
Rectangle2D rect = new Rectangle2D.Double( 0, 0, 20, 20 );
// This transform is used to modify the rectangle (an affine
// transform is a way to do operations like translations, rotations,
// scalings, etc...)
AffineTransform transform = new AffineTransform();
// 3rd operation performed: translate the rectangle to the desired
// x and y position
transform.translate( x + 10, y + 10 );
// 2nd operation performed: rotate the rectangle around the origin
transform.rotate( rotation );
// 1st operation performed: translate the rectangle such that it is
// centered on the origin
transform.translate( -10, -10 );
// Apply the affine transform
Shape s = transform.createTransformedShape( rect );
// Fill the shape with the current paint
g2d.fill( s );
// Stroke the edge of the shape with the current paint
g2d.draw( s );
}
Also note that you should really be using something like a javax.swing.Timer when you modify x, y, and rotation and when you call repaint(). That way all of it happens on the event dispatch thread.