How to draw a JPanel on a canvas? - java

is there a possibility to draw a JPanel on a specific location op a Graphics (or Graphics2D) object?
I override the paint method of my canvas, and call panel.paint(g) in there, but it does not work the way I woul hope.
#Override
public void paint(Graphics g){
Dimension size = panel.getPreferredSize();
panel.setBounds(pos.x, pos.y, size.width, size.height);
panel.paint(g);
}
the size object is correctly defined as I would wish, so that's not the problem. Also, the pos contains a correct x and y on the screen.

You should probably be using paintComponent instead of paint, since the latter is the AWT method, and the former is the Swing method.
One nice thing about Swing's paintComponent is that the Graphics passed is actually always going to be a Graphics2D, so you can:
Graphics2D g = (Graphics2D)lg;
Now you can use the getTransform to save the old transform, then modify the transform of the Graphics2D using either setTranform or the scale, translate and rotate methods. Don't forget to restore the old transform, or you'll likely fudge the next thing being drawn by that context.

I'll throw in that, depending on the circumstance, drawing to a BufferedImage might be appropriate. You can get a Graphics context using BufferedImage.getGraphics(). Then you can draw the BufferedImage's context by whatever means suit you.

Related

Paint method casting - performance

I see a lot of people casting the Graphics type to a Graphics2d type inside their Paint method in an effort to have more functionality over the images they draw. Is it not possible cast the graphics type to a graphics2d type outside of the paint function? To me this screams performance issue because every time the paint method is called (i.e every frame) you are needlessly casting to a Graphics2D type every single time.
Also, does Java do any optimization whenever the paint method is called and the same screen is being drawn again? For example if you are only moving one element on the screen then you will generally only need to update that element. It seems java redraws and re-processes the whole screen every time the paint method is called. To me this all seems unnecessarily processing intensive.
Example code:
public void paint(Graphics g) {
AffineTransform transformer = new AffineTransform();
transformer.translate(5,5);
transformer.scale(2,2);
Graphics2D g2d = (Graphics2D)g;
g2d.setTransform(transformer);
// draw to g2d.
}
You state:
To me this screams performance issue because every time the paint method is called (i.e every frame) you are needlessly casting to a Graphics2D type every single time.
There is minimal cost to this, and so I wouldn't worry about it. Instead profile your program and concentrate on the bottle necks that the profiler shows you matter.
Is it not possible cast the graphics type to a graphics2d type outside of the paint function?
No.
Also, does Java do any optimization whenever the paint method is called and the same screen is being drawn again? For example if you are only moving one element on the screen then you will generally only need to update that element. It seems java redraws and re-processes the whole screen every time the paint method is called. To me this all seems unnecessarily processing intensive
I don't think so. What I've done is to 1) create a BufferedImage to display my static images, and then draw directly my dynamic images, and 2) if need be, limit the area being drawn by using the repaint(...) method overload that accepts a Rectangle.

How to prevent JPanel from repainting everything?

Making a paint-like application that works by saving mouse points in an arraylist. My idea is to have a "points" arraylist with all the previously drawn stuff, and a "temp" arraylist to get and modify the current brush stroke the user just entered. This is necessary as the user can change the color and size, so my idea is to modify the current brush stroke based off what buttons have been pressed, then add that brush stroke to the rest of the picture. I searched around StackOverflow and found some code but cant get it to work how I want to (assuming I found the right code).
#Override
public void paintComponent(Graphics g1) {
super.paintComponent(g1);
final Graphics2D g = (Graphics2D)g1.create();
try {
g.setColor(brushColor);
for (Point point : tempArrayList){
g.fillOval(point.x, point.y, brushSize, brushSize);
}
} finally {
g.dispose();
}
The problem is that I need to clear the tempArrayList for the next brush stroke, which I can do when they change the color/size, but then it erases what was previously there. I am starting to think that I don't even need the "points" arraylist as descibed above because I was hoping that the g1 graphic would just save what the g graphic created.
I guess I just need to figure out how to add the g graphic to g1
Painting is controlled by the Swing API, there is a expectation that whenever paintComponent is called, you will repaint the entire state of the component (as part of your component might have been damaged due to some system event), so the short answer is, no, you can't...however....
You Could...
Paint to a BufferedImage instead and paint the BufferedImage when paintComponent is called
You Could...
Establish a series of "paintable" objects which contain information about what is to be painted and how it is to the painted, including the brush stroke, stroke color and fill color.
These would then be added to some kind of List and "painted" when the paintComponent method is called
Check out Custom Painting Approaches for exampled of painting from:
A List of objects
A BufferedImage.
The examples show how to draw Rectangles of different colours.

How to scale only one object on JPanel using affine transform?

I have a Canvas class, which is an extension of JPanel. I need to draw multiple custom shapes on it and be able to resize them. I finished drawing all the elements, I did the logic for selecting those elements and drawing a section rectangle, but I can't resize them. I tried using affine transformation and the scale() method, but when I scale using those methods, it scales all elements on the canvas, not just one. Any idea how could I make it scale only one element, without scaling others?
Assuming your painting your elements within the paintComponent method...
Create a new copy of the Graphics context...
Graphics2D g2d = (Graphics2D)g.create();
Create and apply you affine transformation...
AffineTransform at = anew AffineTransform();
at.translate(...);
at.scale(...);
g2d.setTransform(at);
Paint your element(s) and dispose of the Graphics context you have created...
//... Paint...
g2d.dispose();
Repeat as required.
The other method might be to get the current transformation and re-apply it when your done...
AffineTransform currenrAT = g2d.getTransform();
// Apply new transform and paint...
g2d.setTransform(currentAT);

fillRect or drawImage not activating within update method in java

Hi I've been trying to get rid of my flickering on a JFrame app. Have searched around and seen that setDoubleBuffered(true) can be used for paintComponent of Jpanel, but not paint method of JFrame, nor applets.
Managed to diminish but not eliminate flickering by introducing the instructions this.createbufferstrategy(2) within paint method, and further reduced flickering with the instruction this.setignorerepaint(true) inside paint.
But I finally found an example of code that completely removes flickering and it works by drawing the static elements within the update function.
Tested fillRect within update in an applet and it works, but when copy pasted into a regular java application it does not work there within the jframe's update function.
Here's the code
Graphics graphics;
Image image;
public void update(Graphics g)
{
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
graphics = image.getGraphics(); }
graphics.setColor(Color.blue);
graphics.fillRect(0, 0, this.getWidth(), this.getHeight());
g.drawImage(image, 0, 0, this);//}
With an empty paint function this draws to the screen and fills it with blue in an applet, it also gets rid of flickering. But in a normal application of jframe it does nothing.
What needs to be done to allow either fillRect or drawImage to work from within update in a non applet regular application environment?
BTW, I'm a bit new to this if the graphics object is being modified itself by calling fillRect, how does that modify the image object? Because drawImage is necessary for the screen to turn blue.
PS I've tried not using both createbufferedstrategy and setignorerepaint, and nothing changes.
When using setIgnorePaint(true), its not allowing you to mess with the Graphics.
I'm guessing by the looks of your update(Graphics g) parameter, you call that within your paint method, using the paintMethod's graphic g to paint (inside paint method, you call update(g))
If you ignore paint, its not gonna allow you to use the paintComponent's Graphic parameter.
Post all code that includes graphics (Where you made your strategy, where you're calling this method, ect..)
The flickering is a pretty mainstream issue with the strategy, and I can't promise that I'll be able to fix it (my friend brought the problem up to me a while ago, but i didnt care enough to try and figure it out), but that should at least explain why your graphics aren't rendering

Is this bad practice? Multiple Graphics2D Objects

I've created a JPanel canvas that holds all graphics; namely JLabel. To get animated sprites to work you have to over ride the paintComponent of the extended JLabel class. I've successfully implemented animated sprites this way.
Is it bad practice to have a Graphics2D canvas and then have multiple 'images' in their own Graphics2D?
I don't think it will be too much heavyweight since the Graphics2D of your JPanel should be the same one that is passed to the JLabel but with different bounds and offsets.
What I mean is that Swing doesn't allocate a new graphics context on which you can display for every element inside a hierarchy of objects but it uses the same with different capabilities. This doesn't mean that panel.getGraphics() == label.getGraphics() but neither they are completely different obects.
In any case, if you need to do much animated work I would suggest you to have your own sprite class
class Sprite
{
Point2D position;
Rectangle2D size;
float rotation;
}
and handle everything at the same paintComponent level. Or at least I've always did that way since Java2D is not like CoreAnimation that is made to be used on a per-layer basis for moving/animated content.

Categories

Resources