Draw multiple elements to canvas - java

I successfully added an oval shape to the canvas, however now i'd like to add two more rectangles but for some reason they do not get added to the canvas. The oval shape is a ball which moves and rectangle shapes are static elements which are for "background". One rectangle should be as a floor and another one as an obstacle for the moving object, ball.
I tried to visualize it in the image:
This is the code, mBack and mObs are the rectangles i'm trying to add.
AnimatedView animatedView = null;
ShapeDrawable mDrawable = new ShapeDrawable();
ShapeDrawable mBack = new ShapeDrawable();
ShapeDrawable mJump = new ShapeDrawable();
public static int x;
public static int y;
public class AnimatedView extends ImageView {
static final int width = 50;
static final int height = 50;
public AnimatedView(Context context) {
super(context);
// TODO Auto-generated constructor stub
mDrawable = new ShapeDrawable(new OvalShape());
mBack = new ShapeDrawable(new RectShape());
mObs = new ShapeDrawable(new RectShape());
mDrawable.getPaint().setColor(0xffffAC23);
//mDrawable.setBounds(x, y, x + width, y + height);
mDrawable.setBounds(y, x, y + width, x + height);
mBack.setBounds(100, 100, 100, 100);
mObs.setBounds(120,120,120,120);
}
#Override
protected void onDraw(Canvas canvas) {
mDrawable.setBounds(y, x, y + width, x + height);
mBack.draw(canvas);
mDrawable.draw(canvas);
invalidate();
}
}
mDrawable will be added however mBack or mObs not. Adding setBounds to onDraw won't change a thing also.

The way you are setting Bounds is wrong. The definition of the setBounds method is here:
setBounds(int left, int top, int right, int bottom)
for the two rectangles you are setting it as
mBack.setBounds(100, 100, 100, 100);
mObs.setBounds(120,120,120,120);
This means you are left and right corners are same and top and bottom are same so you are not seeing your rectangle.
Set it something like this then you will see your rectangles
mBack.setBounds(100, 100, 300, 400);
And call draw method on both rectangle shapes in onDraw method.

It seems the problem is that for mBack you defined the bounds to zero pixel (start end ends in (100,100)), same for mObs, but for that you didn't call draw either.

Related

How to get an object infront of an image in Java Processing 3.x?

Hi I've had a problem where I'm unable to put the ellipse onto the map. Instead what happens is that the ellipse loads for a second and then the map continues to load after this. I've added the code below to see if anyone can help?
PImage map;
float zoom = 1;
float posX = 0;
float posY = 0;
void setup() {
size (800, 800, P3D);
loadData();
map = loadImage("uk-admin.jpg");
}
void draw () {
background (0);
translate(posX,posY);
scale(zoom);
image(map, 0,0, width, height);
camera(width/2, height/2, (height/2) / tan(PI*30.0 / 180.0),width/2.0, height/2.0 , 0, 0, 1, 0);
}
Table table;
void loadData() {
table = loadTable("data.csv", "header");
for (int i = 0; i < table.getRowCount(); i++) {
TableRow row = table.getRow(i);
String city = row.getString("City");
int year1991 = row.getInt("1991");
int year2001 = row.getInt("2001");
int year2011 = row.getInt("2011");
float lat = row.getFloat("latitude");
float lon = row.getFloat("longitude");
lat = map(lat, 90.0, -90.0, 0, height);
lon = map(lon, -180.0, 180.0, 0, width);
fill(255);
stroke(10);
ellipse(lon, lat, 30, 30);
}}
You need to call loadData() in the draw() loop. What's happening now is that you're drawing the ellipse for the first frame, then you're drawing the image on top of it every frame after that.
In Processing, the setup() block is run once, then the current state of the canvas is displayed, then the draw() block is run, then the canvas displayed, then draw(), then display, and so on. So when you draw an ellipse (or a bunch of ellipses) in setup(), then draw something over that ellipse in draw(), it only shows the ellipse for the first frame.

How to add a shape on button click?

I have the following code, I am trying to add a circle to my frame when the button is clicked, I tried calling circle class from my main function, but do not know how to add a circle after that. please help me!
public static void main(String[] args) {
// Create a frame and put a scribble pane in it
JFrame frame = new JFrame("FrameFormula");
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
final FrameFormula scribblePane = new FrameFormula();
JPanel shapePanel = new JPanel();
JButton horGap = new JButton("Add a circle");
horGap.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
int[] circleValues = generateRandomValues(300, 300, 50, 150);
int x = circleValues[0];
int y = circleValues[1];
int width = circleValues[2];
int height = width;
Circle circle = new Circle(x, y, width, height);
//scribblePane.addCircle(circle);
}
});
shapePanel.add(horGap);
frame.add(shapePanel, BorderLayout.SOUTH);
frame.getContentPane().add(scribblePane, BorderLayout.CENTER);
}
I have created separate classes for creating circle with x and y points.
private static int[] generateRandomValues(int maxX, int maxY,
int minSize, int maxSize) {
Random random = new Random();
int[] values = new int[3];
values[0] = random.nextInt(maxX);
values[1] = random.nextInt(maxY);
values[2] = Math.min(random.nextInt(maxSize) + minSize, maxSize);
return values;
}
static class Circle {
int x, y, width, height;
public Circle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void draw(Graphics g) {
g.drawOval(x, y, width, height);
}
}
it remains for a second and gets removed if something else we do on the panel
Check out Custom Painting Approaches for the two common ways to do custom painting:
Add objects to an ArrayList and then paint all the objects in the list
Paint the objects to a BufferedImage and then paint the BufferedImage
The demo code shows how to randomly add Rectangles using the mouse. Your code would obviously be slightly different because you would add the Rectangles with a button.
So start with the working code to get it working with a button. Then change the code to work for circles instead of rectangles.
What you do is creating a circle but not calling the draw-Method. You would use something like:
Circle circle = new Circle(x, y, width, height);
Graphics g = shapepanel.getGraphics();
circle.draw(g);
But that leads to problems so I would suggest you take a look at this thread: Drawing an object using getGraphics() without extending JFrame
There is explained why and how to draw something consistently in a JPanel.

Drawing strings inscribed in a circle

I am aware of Java's drawString(String str, int x, int y) method; however, sometimes all I want is to label a circle with an appropriate string in the middle of it, given a font size (either in pts or in accordance to the circle's size). Is there an easy way to do it, or does one have to make the math on one's own? And if so, how can the width of a string be calculated, as a function of the font size (int pts)?
Here's an example. The text drawing is a modified version of the answer listed by Software Monkey, to use given coordinates, instead of drawing in the center of a component.
If you wanted to draw a circle that didn't cover the entire component, you would then have to calculate the center of the circle, and pass it into drawCenteredText.
The business with the Random class is there to demonstrate how this method will work with any font size.
public class LabledCircle {
public static void main(String args[]) {
JFrame frame = new JFrame();
// Create and add our demo JPanel
// I'm using an anonymous inner class here for simplicity, the paintComponent() method could be implemented anywhere
frame.add(new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw a circle filling the entire JPanel
g.drawOval(0, 0, getWidth(), getHeight());
Random rad = new Random();// For generating a random font size
// Draw some text in the middle of the circle
// The location passed here is the center of where you want the text drawn
drawCenteredText(g, getWidth() / 2, getHeight() / 2, rad.nextFloat() * 30f, "Hello World!");
}
});
frame.setSize(200, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void drawCenteredText(Graphics g, int x, int y, float size, String text) {
// Create a new font with the desired size
Font newFont = g.getFont().deriveFont(size);
g.setFont(newFont);
// Find the size of string s in font f in the current Graphics context g.
FontMetrics fm = g.getFontMetrics();
java.awt.geom.Rectangle2D rect = fm.getStringBounds(text, g);
int textHeight = (int) (rect.getHeight());
int textWidth = (int) (rect.getWidth());
// Find the top left and right corner
int cornerX = x - (textWidth / 2);
int cornerY = y - (textHeight / 2) + fm.getAscent();
g.drawString(text, cornerX, cornerY); // Draw the string.
}
}

Drawing on Canvas and refreshing

I'm new to Android programming and now I'm trying to make a simple Sea Battle game for one person. Ships are places, player hits the field and see whether the shot hit or not.
Basically, the field looks like this:
The code is:
public void onDraw(Canvas canvas) {
if (getWidth() > getHeight()) {
rebro = getHeight();
} else {
rebro = getWidth(); // the smaller size of screen is "rebro"
}
rebro_piece = rebro / 10; // divide the screen by 10 (to get 10x10 field)
Paint background = new Paint();
background.setColor(getResources().getColor(R.color.game_background));
canvas.drawRect(0, 0, rebro, rebro, background); // draw background
Paint divider = new Paint();
divider.setColor(getResources().getColor(R.color.divider_black));
// drawing divider lines
for (int i=0; i<11; i++) {
canvas.drawLine(0, i*rebro_piece, rebro, i*rebro_piece, divider); // horizontal
canvas.drawLine(i*rebro_piece, 0, i*rebro_piece, rebro, divider); // vertical
}
canvas.drawLine(rebro-1, 0, rebro-1, rebro, divider);
}
That's how I make the "field."
In another class I have a method that collects numbers x and y of a 10×10 array that represents where the ships are placed. For debugging, I need to draw them on my field. Ship coordinates are retrieved in a cycle.
So I wrote a drawShip(int x, int y) method.
On Stack Overflow I've founded a question about "Why I can't paint outside onDraw()?" and I've changed my method to this:
public void drawShip(int x, int y) {
myX = x; //global
myY = y; //global
needToPaintShip = true; //boolean
invalidate(); // refreshing?
needToPaintShip = false;
}
Here needToPaintShip decides whether the redrawing of canvas is needed or not.
Also I've edited the onDraw(Canvas canvas) method:
if(needToPaintShip == true) {
Paint ship = new Paint();
ship.setColor(getResources().getColor(R.color.ship_color));
Log.d(TAG, "onDraw(): rebro_piece = " + rebro_piece + " , myX = "+ myX + " , myY = " + myY); // I only get the last coordinates!
Rect r = new Rect(myX*(rebro_piece),myY*rebro_piece, myX*(rebro_piece+1), myY*(rebro_piece+1));
canvas.drawRect(r, ship);
}
but the result is awful:
Guys, I'm desperate. How can I fix this and make "ships" be drawn on the field?
Why do you set needToPaintShip = false; after calling invalidate()? Don't you need to draw the ship again in subsequent frames?
Also, it seems like this item:
Rect r = new Rect(myX*(rebro_piece),myY*rebro_piece, myX*(rebro_piece+1), myY*(rebro_piece+1));
should probably be:
Rect r = new Rect(myX*(rebro_piece),myY*rebro_piece, (myX+1)*rebro_piece, (myY+1)*rebro_piece));
As for why the ship always appears in the bottom right corner, that depends on what you pass to drawShip(x,y), which isn't shown. Is it possible that you are passing pixel coordinates instead of something in the range [0-10)?

onTouchEvent, status bar and canvas - differences in coordinate systems

I have created a custom View.
Just imagine a Rect drawn at its Canvas
at x = 100, y = 100, width = 100, height = 100
in bright blue (or any color you like)
Now I switch off the statusbar -> the App is running in fullscreen.
Just imagine, I would touch exactly in the middle of the rectangle.
The coordiantes should be 150, 150 -- and as they are supposed to be, they are 150, 150.
But now I activate the statusbar -> the canvas shrinks a bit
-> if you look at the screen, the rect is drawn 150px below the statusbar -- this is what I wanted.
Now I touch again exactly in the middle of the rectangle.
The coordiantes should be 150, 150,
but.. -- Jesus! --
The onTouchEvent coordinates include the statusbar height!
And the Canvas coordinates do not!
So what can I do to get the right touch coordinates?
What methods do you used to get the x and y from MotionEvent? Have you tried getRawX() and getRawY()?
---update--
Sorry I think I've misunderstood something. What methods do you used? getY() or getRawY()?
---update again---
Are you handling onTouchEvent in Activity? Here I write some code for testing:
public class CustomView extends View {
private final Paint p = new Paint();
private final Paint p2 = new Paint();
private float lastRawX = 0, lastRawY = 0;
private float lastX = 0, lastY = 0;
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
p.setColor(0xFFFF0000);
p2.setColor(0xFF00FF00);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
lastX = event.getX();
lastY = event.getY();
lastRawX = event.getRawX();
lastRawY = event.getRawY();
invalidate();
return true;
}
#Override
protected void onDraw(Canvas canvas) {
// make the touch point big enough to be noticed.
canvas.drawCircle(lastX, lastY, 3, p);
canvas.drawCircle(lastRawX, lastRawY, 3, p2);
}
}
A red dot for getY() and a green dot for getRawY(). I've tested it in emulator(which I can use the mouse for simulating "accurate" finger touch) and in real device. In both I can see the red dot is drawn exactly at the place I touched and the green dot is drawn below the red one (exactly the height of the status bar).
But if handling onTouchEvent() in an activity, then getY() and getRawY() returns the same value.

Categories