I thought the create() function of graphics object creates a new copy of the current graphics object
this was my code
Graphics temp;
temp = g.create();
temp.drawString("hello world",100,100);
g.fillRect(200,200,50,50);
Now my understanding was that since temp is now a copy of the g, any change on temp would not be reflected on g. So my output should have been just a rectangle due to the fillRect function. But I am getting both the string and the rectangle on my paint output. Why is this happening and how to stop it?
I am a beginner in java, but, after looking into your code i see that you have put
g.create();
(i'm not very sure but) this could possibly mean that everything declare with g. would be affected. I suggest doing so:
Graphics2D g2d = (Graphics2D) g;
Graphics temp;
temp = g2d.create();
temp.drawString("hello world",100,100);
g.fillRect(200,200,50,50);
hope it worked
Can't you just make a class for the object, for example TextString and Box, and make them have a paint method like so:
public void paint(Graphics g){
g.setColor(Color.RED);
g.fillRect(50, 50, 100, 100);
}
And then wherever you are drawing the objects, call
box.paint(g); or whatever you called your object.
This way you can change the properties of the objects and draw them independently anytime you want without affecting the other objects.
Graphics.create gives you a full or specified section of the Graphics object that generated it - it is not a new Graphics object.
If you wish to draw to a graphics object (and reuse said object) I would suggest using the BufferedImage derivative, OffscreenImage and, from there, draw to the OffscreenImage.getGraphics
Related
I am currently programming a game which includes lots of graphical elements. Currently the code looks like this:
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(ImageLoader.gui_iconbar, xToRel(480), yToRel(810), xToRel(960), yToRel(270), null);
g.drawImage(ClientVariables.getSplashart(Main.selectedCharacter, 0), xToRel(495), yToRel(825), xToRel(135), yToRel(240), null);
//... (don't get confused with xToRel, it just makes changes to the drawing position if you move the camera)
}
The problem is: there are TONS of these g.draw(whatever); lines. I want to split them in multiple classes but just making 4 classes and copy paste gameFrame.add(GraphicclassXY); doesn't work, logically. Does anyone know how to fix this issue? (It's not a problem if the solution includes making changes from jlabel to canvas for example)
Create logical non-component classes (that don't extend JLabel, JPanel, JFrame, JComponent or other Swing component), give them a public void draw(Graphics g) method, give the class that does the drawing instances of your logical classes, perhaps within some sort of collection, and iterate through the collection and call draw on your instances within the paintComponent method.
It is possible to draw from one Graphics2D to another Graphics2D?
Let me explain.
I have printing issues, when i display a JTextArea or JTextPanel in screen, internaly its used sun.java2d.SunGraphics2D, but when im printing its used sun.print.PeekGraphics and sun.awt.windows.WPathGraphics.
The problem is with some kind of Fonts, like Arial. In some sizes lines are cut.
I have tryed a lot of ways to render the text in printing, Graphics2D.drawString, SwingUtilities2.drawString, TextLayout.drawString, but in some cases lines are still cut, or lines are not cut but some kind of justification makes disapear white spaces.
So my idea is try to render components with sun.java2d.SunGraphics2D and "copy" the surface to the printer via sun.print.PeekGraphics or sun.awt.windows.WPathGraphics.
Thanks in advance.
Yes its possible, thats how double buffering is achieved in a lot of Java Games. What you need is the Graphics2D's drawImage() method which takes in another Graphics2D object to draw in. E.g. from a small game of mine:
private Main(){
...
/* Create the backbuffer as a BufferedImage object */
this.doubleBuffer = new BufferedImage(this.WIDTH, this.HEIGHT, BufferedImage.TYPE_INT_RGB);
/* create a Graphics 2D object to draw INTO this backbuffer */
this.doubleBufferG2D = (Graphics2D) doubleBuffer.createGraphics();
...
}
Somewhere else:
/*Now lets draw the backbuffer INTO the screen */
g2d.drawImage(doubleBuffer, null , 0, 0);
Edit: heh I realized its not exactly as above...lemme think on it.
Edit2: Alright the above can still be used a sample, but the sequence of steps to draw from one Graphics2D to another should be as such:
1. From a Graphics2D object to an Image/BufferedImage object using drawGraphics().
2. From the Image/BufferedImage above, extract its member Graphics2D object by using itscreateGraphics().
Looks like you can do one of two things:
create a Graphics2D on an image, do your rendering, then draw the image into another Graphics2D
or create Graphics2D from original Graphics2D using Graphics.create() methods and then do you rendering.
I have a simple question to ask.
Is it possible to do an affine transform outside the paint/paintComponent context?
For instance, let's say i want to create a Shape made of a GeneralPath and then rotate it 45°.
Is it possible to create that object and then rotate it always in the class constructor instead of creating the object and then rotate it in the paint/paintComponent method?
Thank you very much.
UPDATE
Thank you very much for the info guys.
So today i have made a simple test as you suggested and it works.
This is with the Affine transform inside the paintComponent method, commented:
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(new Color(230, 230, 230));
g2.fill(enne.getNuvola());//enne.getNuvola(): code from an omitted class. returns a Shape of a cloud
g2.setColor(new Color(20, 20, 20));
/*
AffineTransform t = AffineTransform.getTranslateInstance(400,400);
g2.transform(t);
*/
g2.fill(rock.getRocket());
}//paintComponent
and this is the affine transform inside the class constructor of a GeneralPath
public class Rocket {
GeneralPath rocket;
public Rocket(){
rocket = new GeneralPath();
rocket.moveTo(10,10);
rocket.lineTo(15,15);
rocket.lineTo(15,50);
rocket.lineTo(5,50);
rocket.lineTo(5,15);
rocket.lineTo(10,10);
rocket.closePath();
AffineTransform t = AffineTransform.getTranslateInstance(400,400);
rocket.transform(t);
}//Rocket Costruttore
public GeneralPath getRocket(){
return this.rocket;
}
}//Rocket
But now i have another question:
Do i have to protect the current state of the current trasform also in the Rocket class like it is suggested to do for the paintComponent method in the java transforming tutorial?
Use the getTransform method to get the current transform.
Use transform, translate, scale, shear, or rotate to concatenate a transform.
Perform the rendering.
Restore the original transform using the setTransform method.
Again, thank you very much for your answers
No, the transform should be reset only to restore the state of the Graphics object, because that Graphics object could be reused by the system for other drawings. If you do the transform without a Graphics object, you don't need to worry about that.
Note for the future that you should not ask new questions by editing old questions, because this is confusing. You should post a completely new question (possibly linking your old question).
Are there any in-built methods in the Java API which would allow me to resize a polygon?
Would it be quite a simple task to write my own method, or are there any others already made?
No, nothing built in, altho, when you draw the polygon, you can draw the polygon with a transformation matrix applied which could scale the polygon for you. (or rotate, skew, etc, etc).
see
Graphics2D.setTransform(transform);
Lets assume you are drawing the polygon in a JPanel, and you have overridden the paintComponent method of JPanel. Cast the Graphics object to a Graphics2D object, and use transforms to scale it as appropriate:
public void paintComponent(Graphic g) {
Graphics2D g2d = (Graphics2D) g;
AffineTransform saveTransform = g2d.getTransform();
try {
AffineTransform scaleMatrix = new AffineTransform();
scaleMatrix.scale(1.5, 1.5);
//or whatever you want
g2d.setTransform(scaleMatrix);
g2d.drawPolygon(myPolygon);
} finally {
g2d.setTransform(saveTransform);
}
}
Chances are you can set up the transformation matrix elsewhere (once) instead of each time in the paintComponent method, but i did here to show how to do it.
Also note, that this will move the polygon, you would probably want apply this to the transform:
add a translate to move the polygon to the origin
add a scale
add a translate to move the polygon back to the original position
in this way, the object doesn't move it just scales.
Yes, AffineTransform.createTransformedShape(Shape) will create a transformed copy of any Shape (which may be a Polygon or Path2D.)
I want to copy part of one image into another smaller one: in other words, copy a subrectangle.
I have a Graphics2D object for the source, I can make one for the target, and I know about targetGraphics2D.drawImage(Image img,....) , but how do I get that img from the sourceGraphics2D?
Answer (per aioobe): The source needs to be an Image rather than a Graphics2D.
Image.subImage() is the method for getting the relevant part of the source.
As Aioobe said, you're not going to get the image from the Graphics2D alone. But if your sourceGraphics2D is coming from a Swing component you could try invoking its paint methods with your own Graphics2D instance. From there you can copy the interesting sub-region.
This is kind of a hack but it should work assuming you're using Swing objects.
class CopySwingPaintingSubRegion extends TheSourceType
{
private BufferedImage bufImg;
public CopySwingPaintingSubRegion()
{
bufImg = new BufferedImage(...);
//Draw the original image into our bufImg for copying
super.paintComponent(bufImg.createGraphics());
}
public BufferedImage getSubImage(int x, int y, int w, int h)
{
return bufImg.getSubImage(x,y,w,h);
}
}
Short answer: Yes, you can
A Graphics2D object that has been created on a buffered Image knows the image but isn't willing to hand it back to you. If you don't mind using reflection, you can steal it back (reflection). The following code demonstrates the approach:
public class Graphics2DReflector {
public static void main(String[] args) {
// prepare the Graphics2D - note, we don't keep a ref to the image!
final Graphics2D g2d =
new BufferedImage(100,100,BufferedImage.TYPE_INT_RGB).createGraphics();
g2d.drawString("Reflected", 10, 50);
JFrame frame = new JFrame("Reflected Image");
// one Panel to show the image only known by g2d
frame.getContentPane().add(new Panel() {
#Overwrite
public void paint(Graphics g) {
try {
SurfaceData data = ((SunGraphics2D) g2d).surfaceData;
Field bufImg = BufImgSurfaceData.class.getDeclaredField("bufImg");
bufImg.setAccessible(true);
BufferedImage image = (BufferedImage) bufImg.get(data);
g.drawImage(image,0,0,null);
} catch (Exception oops) {
oops.printStackTrace();
}
}
});
frame.setSize(200,200);
frame.setVisible();
}
}
Note: this depends on some Sun/Oracle classes and may not work with all Java VMs. At least it shows an approach and you may have to inspect the actual classes to get the fields.
If I understand it right, W3Schools has code to get part of an image to put on a canvas. If you need it as another image you could get it from that canvas.
I have one PNG image 20 tall by 200 wide that has 10 "cells or frames" - I use for animation and use the method below:
context.drawImage( img, sx, sy, swidth, sheight, x, y, width, height );
First, some notes regarding Andreas_D answer below:
His code relies on sun.java2d.SunGraphics2D which is an internal and undocumented OpenJDK class. This means that, while it might compile and run on your computer, it might will probably break if you distribute the code to other people. For a detailed discussion, see the official statement regarding this.
The code relies on reflection to pry the internal class open which is a code smell in it self.
All in all, his approach is an example of exceptionally bad practice (both when it comes to programming style and when it comes to helping fellow programmers to use the API correctly)
how do I get that img from the sourceGraphics2D?
I suspect you misunderstood the responsibility of the Graphics2D class.
You use the Graphics2D class to draw on something. It is capable of drawing on a BufferedImage (if you got the graphics object from a buffered image), the screen (if you got it as an argument to your paintComponent method) or even a printer. So in other words, given a Graphics2D objects, there might not even exist an image!
So, as you probably understand, the Graphics2D API does not provide methods for getting hold of the underlying image. (Such method wouldn't make sense, the graphics object might be passing on lines and text being drawn to a printer!)
To get hold of a subimage you need to get hold of the underlying image which the given graphics object draws upon.