I would like to draw rectangle, line etc. on canvas with GraphicsContext.
Rectangle rect = new Rectangle(20,20,10,10);
rect.setId("myRect");
gc.draw(rect);
Is there something like this in JavaFX? Or is there a way to access drawn canvas objects?
From what I know you can't draw Rectangles directly on a canvas - Rectangle is a JavaFX node, but the Canvas API is much lower level and only takes very basic drawing commands. For example, for drawing your rectangle, it would be:
GraphicsContext gc = theCanvas.getGraphicsContext2D();
gc.fillRect(20,20,10,10);
This however doesn't let you manipulate the rectangle any further. what I do is create a custom class DrawableRectangle (for example) with a method draw:
public class DrawableRectangle extends Rectangle {
Canvas theCanvas;
public DrawableRectangle(Rectangle r, Canvas c){
super(r.getX(),r.getY(),r.getWidth(),r.getHeight());
this.theCanvas = c;
}
public DrawableRectangle(int x, int y, int w, int h, Canvas c){
super(x,y,w,h);
this.theCanvas = c;
}
public void draw(){
GraphicsContext gc = theCanvas.getGraphicsContext2D();
gc.setFill(Paint.valueOf("black"));
gc.fillRect(getX(),getY(),getWidth(),getHeight());
}
}
Which you can then use like this:
GraphicsContext gc = theCanvas.getGraphicsContext2D();
DrawableRectangle rect = new DrawableRectangle(10,10,20,20, theCanvas);
// Draw it:
rect.draw();
// You can then manipulate it:
rect.setY(40);
rect.setHeight(60);
// You need to draw it again to see the changes:
// First clear the canvas:
gc.clearRect(0,0,theCanvas.getWidth(),theCanvas.getHeight());
// Then draw it:
rect.draw();
(I can't guarantee this is the best method, but it worked well for me. If you want to draw different shapes this way you should make an interface Drawable to abstract it.)
Related
When creating a Circle object with JavaFX and is using Graphic Context to stroke the Oval I want it to expand outside of the first created oval. So it will be larger than the last one and go around the first if that makes sense to you.
Here is a picture of what it is now:
Here is a picture of what I would like it to do. As well as the fillOval method too:
Canvas canvas = new Canvas(400, 200);
GraphicsContext gc;
gc = canvas.getGraphicsContext2D();
gc.setLineWidth(1);
Circle c = new Circle();
canvas.setOnMousePressed(e ->
{
c.setCenterX(e.getX());
c.setCenterY(e.getY());
});
canvas.setOnMouseDragged(e ->
{
c.setRadius((Math.abs(e.getX() - c.getCenterX()) + Math.abs(e.getY() - c.getCenterY())) / 2);
gc.strokeOval(c.getCenterX(), c.getCenterY(), c.getRadius(), c.getRadius());
}
});
For some reason it begins at the left corner. I cant understand why it does that. It doesnt make any sense to me.
It seems to me your assumption on how strokeOval is defined is wrong.
public void strokeOval​(double x, double y, double w, double h)
The parameters define a bounding rectangle and not, as you assume, a center and a radius. Just have a look at the documentation for more details.
I am currently building an app using Processing.
I have a shape in which I was able to select its sub elements and manipulate its color and stroke... but I am not being able to resize every single element of the file.
Basically, what I want is to resize the whole thing like in:
shape(shape, mouseX, mouseY, 600, 600);//parameters: shape, x-coor, y-coor, new width, new height;
and, to change the color of each element (just like the line above).
The code:
PShape shape;
int noOfChilds;
/***************************************************************************/
void setup()
{
size(1000, 600);
shape = loadShape("a.svg");
noOfChilds = shape.getChildCount();
print(noOfChilds);
shapeMode(CENTER);
}
/***************************************************************************/
void draw()
{
background(100);
shape.enableStyle();
stroke(255);
shape(shape, mouseX, mouseY, 600, 600);
//
shape.disableStyle();
for(int i = 0; i < noOfChilds; i++)
{
pushMatrix();
translate(300, 300);
PShape ps = shape.getChild(i);
fill(random(255),random(255),random(255));
shape(ps, 0, 0);//shape(ps, 0, 0, anyValue, anyValue); seems to fail :'(
popMatrix();
}
}
/***************************************************************************/
You can use the PShape#scale() function to scale individual PShape instances.
From the reference:
PShape s;
void setup() {
s = loadShape("bot.svg");
}
void draw() {
background(204);
shape(s);
}
void mousePressed() {
// Shrink the shape 90% each time the mouse is pressed
s.scale(0.9);
}
Increases or decreases the size of a shape by expanding and
contracting vertices. Shapes always scale from the relative origin of
their bounding box. Scale values are specified as decimal percentages.
For example, the method call scale(2.0) increases the dimension of a
shape by 200%. Subsequent calls to the method multiply the effect. For
example, calling scale(2.0) and then scale(1.5) is the same as
scale(3.0). This transformation is applied directly to the shape; it's
not refreshed each time draw() is run.
You could also use the more general scale() function. More info can be found in the reference.
Note that you might also have to adjust where you draw your shapes, potentially using the translate() function.
How can I get the width and height of a single frame when using LibGdx Animation?
tallAnim = new Animation(1/10f, atlas.findRegion("runner1"), atlas.findRegion("runner2"), atlas.findRegion("runner3"), atlas.findRegion("runner4"));
shortAnim = new Animation(1/10f, atlas.findRegion("short_runner1"), atlas.findRegion("short_runner2"), atlas.findRegion("short_runner3"), atlas.findRegion("short_runner4"));
animation = tallAnim;
I switch between these two animations and when I check for collision I need to know if the exact width/height of the current animation frame.
How I'd normally handle this:
public Rectangle getBounds(){
return new Rectangle(positionX, positionY, sprite.getWidth(), sprite.getHeight());
}
The method atlas.findRegion("path/goes/here") returns a TextureRegion. A TextureRegion has a region.getTexture() method. A Texture has a tex.getWidth() and a tex.getHeight() method. Assuming these frames are the same width, you should be able to just say something like atlas.findRegion("path/goes/here").getTexture().getWidth() and atlas.findRegion("path/goes/here").getTexture().getHeight(). Otherwise you'll need some way to keep track of what frame your on and get the width and height depending on the current frame.
Your method, I'm guessing, should now look something like:
public Rectangle getBounds() {
return new Rectangle(posX, posY, atlas.findRegion("path/goes/here").getTexture().getWidth(), atlas.findRegion("path/goes/here").getTexture().getHeight())
}
I'll provide some links to each of the classes, so you can look through yourself and see what other methods they have.
TextureAtlas documentation: http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/TextureAtlas.html
TextureRegion documentation: http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/TextureRegion.html
Texture documentation: http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/Texture.html
I'm trying to make a tower of hanoi solver which simply solves the hanoi without any mouse events. The problem is when I move the rectangle the original remains, even after I repaint. I've searched the net and tried changing the code around but nonthing worked. I am using a JFrame with a JPanel inside of it if that changes anything.
I have my disk class here which is just a rectangle with colour.
class Disk extends Rectangle {
Color diskColour;
public Disk(int a, int b, int c, int d, Color colour) {
x = a;
y = b;
width = c;
height = d;
diskColour = colour;
}
public Color getColour() {
return diskColour;
}
public void paintSquare(Graphics g) {
repaint();
g.setColor(diskColour);
g.fillRect(x, y, width, height);
repaint();
}
}
Here is my code where I actually call the paintSquare method:
public void simpleMoveDisk(Disk[] disks, int n, Graphics g) {
disks[n].setLocation(30,25);
disks[n].paintSquare(g);
repaint();
}
The paintSquare method paints the disk, while the setLocation method changes its coordinates.
When this runs the rectangle occurs in the new location, however the old one still remains. Any help is appreciated, thanks in advance.
You are calling repaint() in several places and you shouldn't be.
Have your the top level class that is doing the painting, call the paintSquare method and any other method that is needed. Those methods should not be calling repaint().
Also your simple move disk is really strange in the fact that it passes an array of Disks, an index, and a graphics object. Instead make it just take in a Disk. Just pass it the one out of the array that is needed to be updated. Then let whatever class that calls simpleMoveDisk, separately make a call to repaint instead of trying to paint and update the model in the same method.
I'm new to graphics programming. I'm trying to create a program that allows you to draw directed graphs. For a start I have managed to draw a set of rectangles (representing the nodes) and have made pan and zoom capabilities by overriding the paint method in Java.
This all seems to work reasonably well while there aren't too many nodes. My problem is when it comes to trying to draw a dot grid. I used a simple bit of test code at first that overlayed a dot grid using two nested for loops:
int iPanX = (int) panX;
int iPanY = (int) panY;
int a = this.figure.getWidth() - iPanX;
int b = this.figure.getHeight() - (int) iPanY;
for (int i = -iPanX; i < a; i += 10) {
for (int j = -iPanY; j < b; j += 10) {
g.drawLine(i, j, i, j);
}
}
This allows me to pan the grid but not zoom. However, the performance when panning is terrible! I've done a lot of searching but I feel that I must be missing something obvious because I can't find anything on the subject.
Any help or pointers would be greatly appreciated.
--Stephen
Use a BufferedImage for the dot grid. Initialize it once and later only paint the image instead of drawing the grid over and over.
private init(){
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
// then draw your grid into g
}
public void paint(Graphics g) {
g.drawImage(image, 0, 0, null);
// then draw the graphs
}
And zooming is easily achieved using this:
g.drawImage(image, 0, 0, null); // so you paint the grid at a 1:1 resolution
Graphics2D g2 = (Graphics2D) g;
g2.scale(zoom, zoom);
// then draw the rest into g2 instead of g
Drawing into the zoomed Graphics will lead to proportionally larger line width, etc.
I think re-drawing all your dots every time the mouse moves is going to give you performance problems. Perhaps you should look into taking a snapshot of the view as a bitmap and panning that around, redrawing the view 'properly' when the user releases the mouse button?