Graphics G in another method - java

I have a canvas and I want to draw a rectangle based on a JButton click.
So in other words
private void jb_drawActionPerformed(ActionEvent evt) {
// draw a rectangle method
}
Basically, how do I encorporate the pain(Graphics g) thingamagic in that method? or should I make the rectangle an object and call a "render" method from that object? If so, can someone link a tut?
private void jb_drawActionPerformed(ActionEvent evt) {
myrectange.render(x,y); // ????
}

General Comments and Recommendations
One way: Draw in a BufferedImage getting your Graphics object from the BufferedImage, and then draw the BufferedImage in the JComponent's (JPanel's?) paintComponent method.
If you do it this way, you will use the Graphics object directly obtained from the BufferedImage to do your drawing.
Don't forget to dispose of this Graphics object when done with it.
The actual drawing though is done in the JPanel's paintComponent(...) method (see below).
Another way: change a class field, and have the JPanel's paintComponent method use that field when painting. For instance, if you want to paint multiple Rectangles, create an ArrayList<Rectangle> add to it in your ActionListener, call repaint() and have the paintComponent(...) method iterate through the List, drawing rectangles held by it.
Note that the paintComponent(...) method is never called directly but rather you suggest to the JVM that it call it by calling repaint().
Never dispose of a Graphics object that was given to you by the JVM, for instance the one passed into the paintComponent(Graphics g) parameter.
Links
Basic Tutorial: Lesson: Performing Custom Painting
More advanced concepts: Painting in AWT and Swing

Related

Can't understand JPanel setBackground method behavior

JPanel.setBackground method does nothing (although opaque attribute is true) if super.paintComponent father method isn't being called.
I have read a lot of similar questions here about this issue, and in each one of them I've only found solutions without explanation that helped me to understand why setBackground method when written before adding the JPanel to JFrame changes the JPanel background color, while when the setBackground is written inside paintComponent nothing is changed (only when calling father's paintComponent method as already mentioned).
Is it somehow related to Graphics object?
I have tried to change JPanel's opaque attribute to true and using setBackground(COLOR.BLACK) in paintComponent() method I had overriden in a class that extends JPanel
paintComponent(Graphics g)
{
this.setOpaque(true);
this.setBackground(COLOR.BLACK);
}
I expect that the JPanel background color will be black
Instead, background color is the default one
Well, first of all if you're using paintComponent(Graphics g) method, the first line you need to have inside is: super.paintComponent(g) otherwise you're breaking the paint-chain.
This will allow the parent component to draw the default component, before any customizations you do to it. If you don't do it, well, is like having a drawing in a piece of paper, imagine a circle, then cutting that circle and then trying to paint the outside.
Here's a more in-depth answer to How does super.paintComponent(g) works
However I wouldn't write
this.setOpaque(true);
this.setBackground(COLOR.BLACK);
inside the paintComponent(...) method, as it gets called several times and you can't control when it will ever get called. I would put those lines in a constructor, unless you want to change it later in your program while it's being painted depending on the state of your program or a gradient maybe.
For this part:
why setBackground method when written before adding the JPanel to JFrame changes the JPanel background color
Honestly, I don't understand what you mean.
Why do you say that if i won't call super.paintComponent(),it will break the chain? It's still drawing all the shapes and lines i want using graphics object.
From the docs:
The JPanel has a UI delegate which performs the background painting for itself. You call it by using super.paintComponent(g) and we pass the Graphics component to prevent irrevocable changes such as Graphics.translate
Your JPanel knows how to paint its children, but requires some help to paint itself, and this help comes from its parent.
When I mentioned "break the paint chain" I didn't mean nothing would paint, but that you would get strange behaviors such as the one of the JPanel's background disappearing or not being set.
In addition,something weird happens if the argument i'm sending to setBackground method is a random color(using Random object). JPanel changing color very quickly although i'm not doing anything(not minimizing,not resizing,etc).Can you consider why?
As I said before, the paintComponent gets called several times and you don't have control over when it will be called, even moving your mouse or something else will trigger the panel to repaint.

Passing a JPanel to a method to draw rectangles

I have a class with a draw method that accepts a JPanel as an argument.
The first line in the draw method is:
Graphics g = p.getGraphics();
Where (p is the the jPanel passed as an argument to the draw(Jpanel P) method).
I want to draw different rectangles in different colors (based on conditional statements). So i use the
g.setColor(Color.RED) // or another color
Then i draw the rectangle using
g.fillrect(x,y,xsize,ysize).
When i do
System.out.println("color is " + g.getColor().toString());
I see the colors changing, but i don't see the rectangles appearing on the JPanel. This JPanel is an object inside my class that extends from JFrame. What do i need to do to see the rectangles on my JPanel?
You should not paint by obtaining the Graphics object from the JPanel. What you should do is to subclass JPanel and override paintComponent, check this.
The reason why is because the Graphics instance is created everytime your Panel is painted, and you have no control about it, because its parent (the JFrame) may decide when to do so. So you should never make any assumption about the Graphics instance, and you must include your painting logic in the paintComponent method.
The reason why you are not seeing your rectangles is because you are painting them with either an old Graphics instance, or because in the next rePaint they are getting erased because is not the order it is supposed to be (those calls must be in the paintComponent method).
JPanel doesn't know that its canvas is updated, so you see nothing on the screen. The proper way is to override JPanel's method onPaintComponent and draw inside this method. This way, after you call JPanel.repaint() you'll see the stuff you've drawn.

Which statement clears the previous Graphics and draw a new One in Java?

This is The Code :
public void paint(Graphics g) {
g.fillOval(x, y, 25, 25);
repaint();
}
This will create an output like This where if i move the pointer it doesn't clear the previous Graphics and creates a Path .
Output of Above Code
And by adding the super statement like this it Doesn't show the Path but only the Current location of the Oval Graphic.
public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 25, 25);
repaint();
}
The output is This
I just want to the Mechanism and The Reason Behind This.
Sorry, but there is so much wrong with your code, that we have to fix it:
First off, don't override a JComponent's (or JFrame's) paint method but rather override the JComponent's or JPanel's paintComponent. This way you avoid mistakingly messing up painting of borders or child components, both of which paint is responsible for. Also since paintComponent has automatic double buffering, your animation will be much smoother.
Next, you almost always do want to call the super's painting method, which for paintComponent is super.paintComponent(g) as this will continue to propagate the painting chain, whereas by not calling this you break this chain. Calling the super's method will call the component's housekeeping painting including the overpainting of "dirty" pixels which is why the trails are removed. This is likely the answer that you're looking for.
Most important never call repaint() from within any painting method. Doing this results in a poor-man's animation that is completely uncontrollable, and puts too much responsibility on the painting method which should focus on its sole job -- to paint the component. Use a game loop such as a Swing Timer instead.
Most important -- read the tutorials as most of this is already explained there:
Lesson: Performing Custom Painting: introductory tutorial to Swing graphics
Painting in AWT and Swing: advanced tutorial on Swing graphics
Straight from the docs
public void paint(Graphics g)
Paints the container. This forwards the paint to any lightweight
components that are children of this container. If this method is
reimplemented, super.paint(g) should be called so that lightweight
components are properly rendered. If a child component is entirely
clipped by the current clipping setting in g, paint() will not be
forwarded to that child.
As he said that super.paint() cleans the dirty pixels. This says it all .!! :)

Graphics2D using constructor

I want to draw a straight line in JFrame using Line2D.Double, also I want do it with constructor (not through method). How I must declare variable g like in example on docs.oracle.com?
public void paint (Graphics g) {
Graphics2D g2 = (Graphics2D) g;
...
}
Painting is always done in a method. In particular custom painting in Swing is done in the paintComponent() method of a Swing component like JComponent or JPanel.
Read the Swing tutorial on Custom Painting for a better explanation and examples.
1) I want to draw a straight line in JFrame using Line2D.Double, that not possible you have to put there JLabel, JPanel or plain JComponent, example here
2) if you want to paint directly to the JFrame, then you have to (use method paint()) to the GlassPane or RootPane
3) for Swing is there method painComponent(as mentioned both posters), not paint
The drawing/painting occurs event driven. That is when a part of the JFrame has to be (re-)drawn paint and paintComponent will be called.
You can merely add a component to the content pane of the JFrame in the constructor. That would then draw the line by overriding paintComponent.
You could create a JPanel, which has a:
List<Shape> shapes;
shapes.add(new Line2D.Double(...));
and then in paintComponent draw all shapes. But that is overdone.
You mean how to get a Graphics2D object from with a constructor? That is not the way to do it, Graphics2D is an interface and the implementation classes are not in the API. However, you can get a graphics object from any component with
(Graphics2D)component.getGraphics()

How to make canvas with Swing?

I'm trying to make a paint editor with Java in which I have a toolbar with the objects that I would like to paste in the canvas. I'm using Swing components to make the GUI, but when I looked for the way of making the canvas, I only found the class canvas from AWT.
Is there any way to make something similar to canvas with Swing? (for example, JPanel?) I have read that using the class canvas from AWT with a GUI made with swing won't work correctly, is that true?
In order to make a custom 'Canvas' in swing you usually write a subclass of a JPanel. Then, you must overwrite the protected paintComponent(Graphics g) method of JPanel.
In the paint method, you can call methods on the Graphics object to actually draw on the JPanel.
As always, the Java Tutorials have a great reference on this to get you started.
You'll probably want to make a subclass of JPanel and implement your own way of painting components you want to draw onto the panel.
The basic approach will probably be along the line of assigning a MouseListener to the subclass of JPanel, then implement painting functionality.
The basic idea may be something along the line of:
class MyCanvas extends JPanel implements MouseListener
{
Image img; // Contains the image to draw on MyCanvas
public MyCanvas()
{
// Initialize img here.
this.addMouseListener(this);
}
public void paintComponent(Graphics g)
{
// Draws the image to the canvas
g.drawImage(img, 0, 0, null);
}
public void mouseClicked(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
Graphics g = img.getGraphics();
g.fillOval(x, y, 3, 3);
g.dispose();
}
// ... other MouseListener methods ... //
}
The above example is incomplete (and not tested -- it definitely won't compile), but it gives an idea about how to implement a MyCanvas class in which a user can click on and draw circles.
The img object is used to hold the image of the canvas. The paintComponent method is used to paint the img object to the canvas. In the mouseClicked method, the Graphics object associated with img is retrieved in order to fillOval onto the image.
Since one the requirements is to paste images onto the canvas, it may be a good idea to hold some Images that you want to paste into the canvas. Perhaps something along the line of:
Image[] myImages; // Used to store images to paint to screen.
Then, in the routine to paint the image onto img stored in MyCanvas:
g.drawImage(myImage[INDEX_OF_DESIRED_IMAGE], 0, 0, null);
By using the drawImage method of the Graphics object, other Images can be drawn onto Images.
As for the question on AWT and Swing, yes, it is true that you do not want to mix components from the AWT and Swing, as they differ in the way they render GUI components. AWT is based on heavyweight components, meaning they native windowing for painting the GUI, while Swing is based on lightweight components, meaning the GUI is drawn by Java itself without using native components.
A good guide on the difference of AWT and Swing is provided in Painting in AWT and Swing article from Sun.
Simply subclass JComponent.
JPanel is an inappropriate class. It is often suggested as it appears to have setOpaque(true) invoked on it automatically. It's actually the PL&F which does that, and whether or not it actually happens is implementation and vendor dependent.
Canvas is a heavyweight component. That is to say that it is controlled by the underlying windowing system. The result is that it will typically be drawn over the top of Swing components, without respect to z-order or clipping (putting it in a scroll pane will give odd behaviour).
You might want to look at the Minueto API. It is a very simple to use graphics api, and you can combine the Java event listening with it to provide your drawing capability.
http://minueto.cs.mcgill.ca/

Categories

Resources