Can you render components swing through a Graphics object?
I have a structure like this in my class:
public void render(Graphics g) {
//Render stuff
}
Is it possible to create an object swing, and for that object to render i using the Graphics object?
sure, absolutely possible.
public class MyClass extends JComponent {
//...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
render(g);
}
}
I take it, you want to draw, but not to the screen.
One can create a BufferedImage (or read a background image) and create a Graphics2D object with which to draw.
File imgFile = new File("scenery.png");
BufferedImage img = ImageIO.read(imgFile);
Graphics2D g = img.createGraphics();
render(g);
g.dispose();
ImageIO.write(img, "png", imgFile);
Not to forget the g.dispose() to releast native drawing state.
Related
I have been having trouble rotating one of my sprites in a game I'm working on. I have followed a tutorial about rotating images on JPanels about the center of the image (which was very well-done). I even created a simple project that works just fine.
However, when I tried to use the same technique on my game, my sprite will not rotate. I have determined that the problem is drawing the sprite, as I have checked in the paintComponent(Graphics g) method via a println() statement that the rotation value is updated properly and that the repaint() method is being called when appropriate.
Here is the relevant code to the issue (excludes unnecessary methods and such):
Highest-level class:
public abstract class GameObject extends JPanel {
protected BufferedImage image;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw sprite
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(image, 0, 0, null);
// Clean up
g.dispose();
g2.dispose();
}
}
Lowest-level class:
// Entity is a subclass of GameObject.
// It does not override paintComponent.
// All it does is add an update method that is called every game tick.
public abstract class MicroObject extends Entity {
protected Location location; // variable to store position and rotation
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.translate(this.getWidth() / 2, this.getHeight() / 2);
g2.rotate(Math.toRadians(location.getRotation()));
// In the following two lines, image is inherited from GameObject
g2.translate(-image.getWidth(this) / 2, -image.getHeight(this) / 2);
g2.drawImage(image, 0, 0, null);
g2.dispose();
g.dispose();
}
}
I know this isn't necessarily a unique question, but I've looked at all of the "duplicate" threads, and they've all left me with similar answers, but the same problem in the end. I would appreciate it if someone took the time to look at my code and see where I went wrong.
Thank you all!
Don't dispose those Graphics objects! They're re-used by Swing to draw children components & borders.
The reason why it's not working is because GameObject is disposing the graphics object before MicroObject can use it.
Also, there's no reason to draw the image twice. Remove the code in GameObject's paintComponent().
Lastly, just use classes. There's no reason for those to be abstract.
So:
Highest-level class:
public class GameObject extends JPanel {
protected BufferedImage image;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Don't draw sprite. Subclass will do that.
// Don't clean up. Swing does that for us.
}
}
Lowest-level class:
// Entity is a subclass of GameObject.
// It does not override paintComponent.
// All it does is add an update method that is called every game tick.
public class MicroObject extends Entity {
protected Location location; // variable to store position and rotation
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.translate(this.getWidth() / 2, this.getHeight() / 2);
g2.rotate(Math.toRadians(location.getRotation()));
// In the following two lines, image is inherited from GameObject
g2.translate(-image.getWidth(this) / 2, -image.getHeight(this) / 2);
g2.drawImage(image, 0, 0, null);
}
}
I have simple drawing canvas like this:
public class DrawingCanvas extends JPanel
private BufferedImage image;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
image = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D) image.getGraphics();
// draw some items....
g2.dispose();
g.drawImage(image, 0, 0, null);
}
}
I want to ask you, if I can set some render quality?
For example Antialiasing.. I want use BEST render quality.
How ?
Have a look at RenderingHints.
You can set them with calling g2.setRenderingHint(RenderingHints.Key hintKey, Object hintValue).
With this you can alter different settings for the render quality, like (text)anti-aliasing, alpha-interpolation etc.
For anti-aliasing:
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
The other keys and values are pretty self-explanatory.
I've extended the JPanel class to draw a graph. The problem that I've got is that I need a global graphics object in order to call it in multiple methods... As an example, here's what I'm trying to do:
public class Graph extends JPanel {
private Graphics2D g2d;
public void paintComponent(Graphics g){
g2d = (Graphics2D)g;
}
public void drawGridLines(int hor, int vert){
g2d.someLogicToDrawMyGridLines(someparams);
}
}
This returns a null pointer exception - so my question is: how do I create a global graphics object? What's the best practice in this situation?
My suggestion would be this:
public class Graph extends JPanel {
public void paintComponent(Graphics g){
super.paintComponent(g);
g2d = (Graphics2D) g;
drawGridLines(g2d, ......);
}
private void drawGridLines(Graphics2D g2d, int hor, int vert){
g2d.someLogicToDrawMyGridLines(someparams);
}
}
i.e. keep all the uses of your graphics context inside the paintComponent call.
How would I pass in the graphics object externally?
Don't. The graphics context is only valid during the invocation of paintComponent(). Instead, use the MVC pattern, discussed here, to update a model that notifies any listening view to render itself. JFreeChart is a complete example.
I've extended the JPanel class to draw a graph. The problem that I've got is that I need a global graphics object in order to call it in multiple methods... As an example, here's what I'm trying to do:
public class Graph extends JPanel {
private Graphics2D g2d;
public void paintComponent(Graphics g){
g2d = (Graphics2D)g;
}
public void drawGridLines(int hor, int vert){
g2d.someLogicToDrawMyGridLines(someparams);
}
}
This returns a null pointer exception - so my question is: how do I create a global graphics object? What's the best practice in this situation?
My suggestion would be this:
public class Graph extends JPanel {
public void paintComponent(Graphics g){
super.paintComponent(g);
g2d = (Graphics2D) g;
drawGridLines(g2d, ......);
}
private void drawGridLines(Graphics2D g2d, int hor, int vert){
g2d.someLogicToDrawMyGridLines(someparams);
}
}
i.e. keep all the uses of your graphics context inside the paintComponent call.
How would I pass in the graphics object externally?
Don't. The graphics context is only valid during the invocation of paintComponent(). Instead, use the MVC pattern, discussed here, to update a model that notifies any listening view to render itself. JFreeChart is a complete example.
I'm trying to draw objects onto a canvas from an array, but the thing is, I have no clue how to? This must include the position and sizes of the shapes, and there will be more than one type of shape. The code I've got so far(It's inefficient/bad though)
public class MCanvas extends Canvas {
private Object[] world = {};
public void paint(Graphics g){
try{
// How to paint all the shapes from world here?
} catch (NullPointerException e) {
System.out.println(e.toString());
}
}
}
Any ideas? Thanks.
If your using objects that extend from java.awt.Shape, you can translate and draw them by using a Graphics2D context
Since (some whe around Java 1.3/4), the paint engine is guaranteed to use Graphics2D instance.
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
for (Object o : world) {
if (o instanceof Shape) {
Shape shape = (Shape)o;
//if the shape isn't created with
// a location, you can translate them
shape.translate(...,...);
g2d.setColor(....);
g2d.draw(shape);
//g2d.fill(...);
}
}
}
You might like to take a look at 2D Graphics for more details.
Also, use a JPanel instead of Canvas and then override its paintComponent method
Have a look at Custom Painting for more details