I use NetBeans and the last version of JDK. For some reason there is no Graphics.draw() method, though java.awt.geom.Line2D and java.awt.Graphics2D are imported. How do I draw a Line2D.Double element?
Shape pLine;
private void playerDraw(){
Graphics g2 = getGraphics();
pLine = new Line2D.Double(px, py, Math.cos(angle)*10+px,Math.sin(angle)*10+py);
g2.drawRect(px-5, py-5, 10, 10);
g2.draw(pLine); //this doesn't compile(cannot find symbol)
}
Your main problem is that you're using a Graphics object as if it were a Graphics2D object, but it's not and as the Graphics class Java API entry will show you, the Graphics class does not have a draw method, while Graphics2D does. I think that you're missing a key line, something like:
Graphics g = getGraphics();
Graphics2D g2 = (Graphics2D) g; // the missing line
But having said that, you are using Graphics incorrectly as you should avoid getting it by calling getGraphics() on a Swing component since this gives you an unstable short-lived Graphics object whose use risks causing short-lived images or NullPointerExceptions, but rather you should do your drawing within the JComponent's paintComponent(Graphics g) method.
You missed to declare pLine variable in your Class:
Eg.
public class Example
{
public Line2D.Double pLine;
private void playerDraw(){
Graphics g2 = getGraphics();
pLine = new Line2D.Double(px, py,Math.cos(angle)*10+px,Math.sin(angle)*10+py);
g2.drawRect(px-5, py-5, 10, 10);
g2.draw(pLine); //this doesn't compile(cannot find symbol)
}
}
Related
I have started using AffineTransform to rotate text I'm drawing with Graphics2D and I noticed it would sometimes work fine and other times it wouldn't when I just realized that it works always as expected on my Windows 7 PC but never on my Windows 10 laptop.
I use Java 15.0.1 on both systems.
Here is a small test case to show you my point:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
public class AffineTransformTest extends JPanel {
private static final int SIZE = 40;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
int centerX = getWidth()/2;
int centerY = getHeight()/2;
g2.setColor(Color.BLACK);
g2.drawRect(centerX - SIZE/2, centerY - SIZE/2, SIZE, SIZE);
AffineTransform at = g2.getTransform();
at.setToRotation(Math.toRadians(45),centerX, centerY);
g2.setTransform(at);
g2.setColor(Color.RED);
g2.drawRect(centerX - SIZE/2, centerY - SIZE/2, SIZE, SIZE);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
AffineTransformTest test = new AffineTransformTest();
frame.setContentPane(test);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300,300);
frame.setVisible(true);
}
}
The black rectangle is a regular one centered in the middle of the JPanel.
The red rectangle is drawn after a 45° rotation and is supposed to share the same center as the black one (as shown on the first picture).
My laptop however produces the result shown on the second picture.
Expected result - Windows 7 |
Incorrect result - Windows 10
How can this be?
This is likely because you are violating the contract of the paintComponent() method, where the Javadoc states
If you override this in a subclass you should not make permanent
changes to the passed in Graphics. For example, you should not alter
the clip Rectangle or modify the transform. If you need to do these
operations you may find it easier to create a new Graphics from the
passed in Graphics and manipulate it.
So maybe subtle differences between the Windows 7 and Windows 10 native implementations of the UI is why one breaks and the other doesn't.
To see if this is indeed the cause, try changing the line Graphics2D g2 = (Graphics2D)g; to Graphics2D g2 = (Graphics2D)g.create(); which will make a clone of the Graphics object and leave the original unchanged.
Edit to clarify the correct answer:
The issue was caused by the at.setToRotation call clearing the default scaling transform on the graphics context after drawing the black square and before drawing the rotated red square. The recommended solution is to call the rotate(theta,x,y) form of the method directly on the Graphics2D object which preserves the existing scale transform.
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D)g; //
double r = 100; //the radius of the circle
//draw the circle
Ellipse2D.Double circle = new Ellipse2D.Double(0, 0, 2 * r, 2 * r);
g2.draw(circle);
This is part of a class within my program, my question lies in the
Graphics2D g2 = (Graphics2D)g;
Why must you include the "g" after the (Graphics2D), and what exactly does the "Graphics2D" Within the parenthesis mean, i am learning out of a book and neither of these were ever fully explained.
You are casting Graphics2D to the Graphics context g. Read more about casting here in Inheritance in the Casting section.
What this ultimately does is allot you use the available methods of Graphics2D with the Graphics context of the passed to the paintComponent method. Whitout the casting, you'd only be limited to the methods of the Graphics class
Graphics2D is a subclass of Graphics so by using Graphics2D you gain all the methods of Graphics while taking advantage of the methods in the Graphics2D class.
Side Notes
You shouldn't be override paint. Also if you are, you shouldn't be painting on top level containers like JApplet.
Instead paint on a JPanel or JComponent and override paintComponent instead of paint and call super.paintComponent. Then just add the JPanel to the parent container.
public DrawPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
}
}
See more at Custom Painting and Graphics2D
Yes, you must include the g.
When you enter your paint method you have an object g of type Graphics.
Then you are typecasting your Graphics object, g to a type of Graphics2D which is a type that extends Graphics.
You have to include the g so you have something to typecast. If you don't include object there you will get a compilation error because the statement isn't complete.
The reason you are typecasting g to a Graphics2D object is because you are telling the compiler, "This Graphics object is actually a Graphics2D object." that way you can perform functions that the Graphics2D Object has that the the Graphics object does not.
This stackoverflow answer explains casting variables in Java very well if you have more questions about that. And this stackoverflow answer explains why it is safe to cast from Graphics to Graphics2D
What is difference between Graphics and Graphics2D?
Whether Graphics2D is extend of Graphics?
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawRect(25, 25, 20, 20); //use Graphics to paint rectangle
Graphics2D g2 =(Graphics2D)g;
g2.drawRect(0, 0, 20, 20); // use Graphics2D to paint rectangle
}
Graphics itself is an abstract class, therefore you cant create its instance. It only defines some interface and some functionality, so it can be extended by other class.
So even this Graphics g, which is used as parameter in paintComponent, is not only Graphics. The standard java library has only two extended class : DebugGraphics, Graphics2D, so the Graphics g you are using is Graphics2D instance stored in Graphics g.
If it is not, the line Graphics2D g2 =(Graphics2D)g; would end with an error.
I have coded a simple Java game where there are two rectangles on the screen, one of the rectangles moves and the other stays still, the moving Rectangle moves with keyboard arrow input and can move either up, down, left or right. The problem I am having is drawing my rectangles on the screen, I mean I have the 2 rectangles set up with my variables as shown:
Rectangle rectOne = new Rectangle(shiftX, shiftY,90,90);
Rectangle rectTwo = new Rectangle(500 + buckyPositionX, 330 + buckyPositionY, 210, 150);
I have made a render method to draw the things on the screen which I want shown:
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
}
The problem I am having is showing my rectangles on the screen by writing the code in the render method, I could do the following:
g.fillRect(x, y,90,90);
g.fillRect(500 + buckyPositionX, 330 + buckyPositionY, 210, 150);
Which makes 2 rectangles on the screen but I need the rectangles to be drawn using the Rectangle code written with the variables, I have been told this can be done using Graphics2D but I am wondering if there is a simpler way of just using the graphics function, if not could you please help me set this up?
Thank you in advance.
You can access attributes of the Rectangle instances easily:
g.fillRect(rectOne.getX(), rectOne.getY(), rectOne.getWidth(), rectOne.getHeight());
In any case mind that usually the Graphics object is a Graphics2D instance at runtime so this could work easily too:
Graphics2D g2d = (Graphics2D)g;
g2d.fill(rectOne);
Just use:
g.fillRect(myRect.getX(), myRect.getY(), myRect.getWidth(), myRect.getHeight());
where myRect is the rectangle you want to draw. You could even make a custom method drawRect(Graphics g, Rectangle myRect); if you have lots of rectangles to draw.
Using Graphics2D is not that difficult as well, as the provide Graphics object normally is a Graphics2D object:
Graphics2D g2d = (Graphics2D) g;
g2d.fill(myRect);
I want to translate a rectangle 2D using a double x and double y. It seems that rectangle2D does not support the translate method. What is the appropriate method to use?
If you need it to remain a Rectangle2D, you might have to write your own custom method that just adds to the x and y.
You can also perform arbitrary transformations with an AffineTransform, but this will turn it into a generic Shape (since that transformation might make it no longer rectangular).
AffineTransform at = AffineTransform.getTranslateInstance(tx, ty);
Shape transformed = at.createTransformedShape(rectangle);
You have to cast the old Graphics variable to Graphics2D which has double methods. Mostly double parameters are used.
#Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g.translate(3.0, 4.0);
Double rectangles are not available in Graphics2D (like in drawRect). They are available however for own programming as java.awt.geom.Rectangle2D.Double.