I'm trying to create a bar chart with g.fillRect(x, y, width, height). However, when I set the height negative so it should draw upwards, it doesn't draw the rectangle.
g.fillRect(x, y, 100, -h);
The value of int h is described in a sinus function and I want it to move accordingly however I get this weird output that it only draws the top- and the bottom-most pixels.
Use
g.fillRect(x, y - h, 100, h);
instead.
Related
I'm pretty new to Affine Transformations and am finding a few things quite frustrating..
I've been working on a personal project that draws a laser (think Star Wars) on the screen. I use the RadialGradientPaint class to draw the glow for the laser, and then use scale and rotate Affine Transformations to change the oval's shape and turn the laser in a specific direction.
When I try to rotate the graphic (without the scale), it appears to shrink it, and I'm not sure why this is. I've tried looking this up to no avail. Perhaps I misinterpreted the Java Doc on this class. Why is this?
I'm also curious as to how I can get the transformed object to move to the same location as an un-transformed graphic. Both graphics move to different places even with the same coordinates. I know this might be due to an Affine Transformation shifting the whole graph, and that I might have to translate the transformed graphic to get it to the same exact place as the un-transformed graphic, but I'm not sure how to approach this.
Here is the portion of my code that draws the laser:
public void render(Graphics g) {
// If the graphic is visible on the frame, draw it
if(onScreen()) {
Graphics2D g2d = (Graphics2D) g;
// Preserves the original presets of the program's graphics
AffineTransform ogTransform = g2d.getTransform();
Shape ogClip = g2d.getClip();
Point2D center = new Point2D.Float(x, y);
float[] dist = {0.3f, 0.9f};
Color[] colors = {new Color(1.0f, 1.0f, 1.0f, 0.9f), new Color(0.0f, 1.0f, 0.0f, 0.1f)};
g2d.setPaint(new RadialGradientPaint(center, radius, dist, colors));
AffineTransform scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY);
AffineTransform rotationTransform = AffineTransform.getRotateInstance(angle, x + width/2f, y + height/2f);
// Transforms the shape to look more like a laser
rotationTransform.concatenate(scaleTransform);
g2d.setTransform(rotationTransform);
// Draws a "cut-out" of the rectangle
g2d.setClip(new Ellipse2D.Double(x - radius, y - radius, radius * 2, radius * 2));
g2d.fillRect(x - radius, y - radius, radius * 2, radius * 2);
// Default transformation and clip are set
g2d.setTransform(ogTransform);
g2d.setClip(ogClip);
// Outlines where the transformed graphic should be
g.setColor(Color.orange);
g.drawRect(x - 10, y - 10, 20, 20);
}
}
Any help is appreciated!
I am trying to plot a graph using the java 2d graphics library and I thought I had it. I want to plot in the coordinate system where 0,0 is in the center of the panel on the left edge. I used the following code and it seemed to give me the result I needed.
private void doDraw(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
AffineTransform saveAT = g2d.getTransform();
// get the height of the panel
int height = getHeight();
// Find the middle of the panel
double yTrans = ((double)height)/2.0;
AffineTransform tform = AffineTransform.getTranslateInstance( 0.0, yTrans);
g2d.setTransform(tform);
//draw the line for the x-axis.
g2d.drawLine(0, 0, 100, 0);
//restore the old transform
g2d.setTransform(saveAT);
}
This plotted the origin centered in the window.
The problem shows itself when I added a menu. Then the origin was offset in the y direction about twice the size of the menu higher then it should be. Do I need to account for the size of the menu and other containers that I add to the panel?
private void doDraw(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
int height = getHeight();
double yTrans = ((double)height)/2.0;
AffineTransform tform = AffineTransform.getTranslateInstance( 0.0, yTrans);
g2d.transform(tform);
//draw the line for the x-axis.
g2d.drawLine(0, 0, 100, 0);
}
works, thank you for your help
You might try the approach outlined here. Override paintComponent() to obtain a graphics context relative to the enclosing panel, rather than the enclosing frame.
To center the origin at the left edge, use
g2d.translate(0, h / 2);
To get upright, cartesian coordinates, use
g2d.scale(1, -1);
I'm quite new to graphics in java and I'm trying to create a shape that clips to the bottom of another shape. Here is an example of what I'm trying to achieve:
Where the white line at the base of the shape is the sort of clipped within the round edges.
The current way I am doing this is like so:
g2.setColor(gray);
Shape shape = getShape(); //round rectangle
g2.fill(shape);
Rectangle rect = new Rectangle(shape.getBounds().x, shape.getBounds().y, width, height - 3);
Area area = new Area(shape);
area.subtract(new Area(rect));
g2.setColor(white);
g2.fill(area);
I'm still experimenting with the clip methods but I can't seem to get it right. Is this current method ok (performance wise, since the component repaints quite often) or is there a more efficient way?
I think your original idea about using the clip methods was the right way to do it. This works for me:
static void drawShapes(Graphics2D g, int width, int height,
Shape clipShape) {
g.setPaint(Color.BLACK);
g.fillRect(0, 0, width, height);
g.clip(clipShape);
int centerX = width / 2;
g.setPaint(new GradientPaint(
centerX, 0, Color.WHITE,
centerX, height, new Color(255, 204, 0)));
g.fillRect(0, 0, width, height);
g.setPaint(Color.WHITE);
int whiteRectHeight = height * 4 / 5;
g.fillRect(0, whiteRectHeight,
width, height - whiteRectHeight);
}
Is this current method ok (performance wise, since the component repaints quite often) ..
Subtracting shapes is how I'd go about it. The objects could be a few instances or (possibly) a single instance that is transformed as needed.
A text demo., using scaling & fading.
Here's one with simple lines (..and dots, ..and it is animated).
Of course, if the image is purely additive, use a BufferedImage as the canvas & display it in a JLabel/ImageIcon combo. As in both of those examples.
I want to draw a figure using float or double values, to be precise.
I use:
g.drawOval(0, 0, 10, 10);
to draw a circle, but I only can use integer values.
Is there any statement that use float/double values that do the same?
Here is a picture: Problem
The circles have to be centered, and I can't. Any solution?
Code:
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JPanel;
public class Bulls_EYE extends JPanel
{
int red, green, blue;
int height, width;
int heightOval = 475, widthOval = 475;
Random rValue = new Random();
public void paint (Graphics g)
{
super.paint(g);
for (int idx = 0; idx < 100; idx++)
{
g.setColor(new Color(red = 1 + rValue.nextInt(255), green = 1 + rValue.nextInt(255), blue = 1 + rValue.nextInt(255)));
g.fillOval(width+2*idx, height+2*idx, widthOval-5*idx, heightOval-5*idx);
}
}
}
I think it's an interesting question but needs more context. Drawing primitives are usually expressed in pixel coordinates so fractions of a pixel do not make much sense.
If you want precision like a CAD application note that what is displayed on the screen is only an approximation of the underlying model due to the limitations of the display.
You can represent your models precisely in memory (with limitations in floating point representation) and draw the approximation on the screen.
Update
Based on your last update:
We know from the JavaDoc that fillOval takes as parameters (x, y, w, h) where x, y are the upper left coordinates, and w, h are the width and height.
If for each concentric circle you move the upper left coordinates inward, in this case by 2 px, to keep them centered, you must also reduce the width and height by twice that amount. Change the following line:
g.fillOval(width+2*idx, height+2*idx, widthOval-5*idx, heightOval-5*idx);
To
int dx, dy, dw, dh;
dx = 2*idx;
dy = 2*idx;
dw = 2*dx; // note this is 4*idx not 5*idx like you have currently
dh = 2*dy;
g.fillOval(width+dx, height+dy, widthOval-dw, heightOval-dh);
Note that your width and height variables being used in the first and second parameters really doesn't have anything to do with width and height but instead are providing a beginning offset from the origin where the oval is drawn.
There is no reason you should do this, because when drawing an oval with the given coordinates, they are referred to pixels on the screen. Since you can't draw between pixels, 1 is the smallest unit you can use. If you want to round the values before drawing, you can use
g.drawOval(Math.round(a),Math.round(b),Math.round(x),Math.round(y)
which will round the float a, b, x and y before drawing the oval. The only reason I can see is that you calculate the coordinates and the result is a float, then you need to round it like above.
You can use the Arc2D class for drawing circles with float/double precision, since it is a Shape and the Graphics2D class can draw shapes.
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Shape circle = new Arc2D.Double(
// Same values as used in the fillOval function,
// but with double precision.
x, y, width, height,
// Draw a full circle (yes, in degrees).
0, 360,
// Connect the endpoint with the startpoint.
Arc2D.CORD
);
// Paint the circle.
g2d.fill(circle);
}
In a similar way, you can draw rectangles by using the Rectangle2D class.
Also, please use the paintComponent function instead of the paint function, as explained here.
I'm working on a custom Swing Component for my application, and I started drawing things with the public void paintComponent(Graphics g). Everything works fine except for the fact that I can't draw any rectangles. I think the problem is with the getX() and getY() part, but I don't know that for sure. Here's my code:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (mouseEntered) {
g.setColor(HIGHLIGHTED_COLOR);
} else {
g.setColor(BACKGROUND_COLOR);
}
g.fillRect(getX(), getY(), getWidth(), getHeight());
//Draw rest of stuff (works fine)
The API says that it is supposed to be used like this: g.fillRect(x, y, width, height), and that's what I'm doing.
The rest of the drawing works perfectly, but I can't figure out why this isn't drawing. Any suggestions?
I'm not exactly sure how your Component is defined, but the default value for a Component's getX() method is the X coordinate of the Component's upper left hand corner (relative to the root Component).
When you are drawing in a Component's paintComponent(Graphics) method in Swing, the origin of the Graphics context that you are drawing to is typically located at the top-left of the Component itself, not the root Component.
So by doing this call:
g.fillRect(getX(), getY(), getWidth(), getHeight());
You are likely drawing the rectangle outside of the clip bounds of the Component!
(e.g. if the Component is located at 100, 100 and it has a width of 20 and height of 20, the rectangle you are drawing, in absolute coordinates, is at (200, 200) to (220, 220))
If you want to draw a rectangle that encompasses the entire component, you may want to try something more like this:
g.fillRect(0, 0, getWidth(), getHeight());
This will draw from the origin (again, likely the top-left hand corner of the Component) down to the width and height of the component.
(Using previous example: Component is at 100, 100, and width/height of 20, the rectangle this would draw is at (100, 100) to (120, 120))
Hope this helps =)