Why can't paintComponent accept a Graphics2D object? - java

public class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g){
Graphics2D gd2 = (Graphics2D) g;
GradientPaint gradient = new GradientPaint(70,70,Color.blue,150,150,Color.red);
}
}
Why is this valid but not this:
public class MyDrawPanel extends JPanel {
public void paintComponent(Graphics2D g){
GradientPaint gradient = new GradientPaint(70,70,Color.blue,150,150,Color.red);
g.setPaint(gradient);
g.fillOval(70,70,100,100);
}
}
First one renders, but the second one renders no graphics other than the frame. I noticed that paintComponent() requires a Graphics object, but if Graphics2D is a subclass of the Graphics object why can I not call a subclass of Graphics?
Is there some concept I am not picking up as to why this is?

It says that you should implement it this way, because Graphics2D is Graphics, while Graphics is not Graphics2D.
If you find casting disturbing, you can always create your own eg. MyJPanel that extends JPanel, define your own method, and subclass it in the future, overriding your defined method.
public class MyJPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
paintComponent((Graphics2D) g);
}
protected void paintComponent(Graphics2D g) {
}
}

Basically, when you override a method, you can be equally or less specific.
Think about this:
JPanel p = new MyPanel();
p.paintComponent(someGraphicsInstance);
A reference to a JPanel is expected to be able to accept a Graphics reference as a parameter to the paintComponent method. Your method, however, violates that requirement as it will not accept a Graphics instance, but only a Graphics2D.
More information about this can be found https://stackoverflow.com/a/9950538/567864

Related

Repaint method with multiple panels in the same class

I'd like to know how you are supposed to override a paint method for each panel in the same class and how to call them separately?
I only know about the repaint() call when you are in a class that extends JPanel (so in only one panel), not when you just make panels.
Thanks in advance.
Typically you create a class that extends JPanel to override the paintComponent method:
public class Test extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// code here
}
public void doStuff() { repaint(); }
}
You might consider creating a nested class like so:
public class Test {
public class MyPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// code here
}
}
JPanel panel = new MyPanel();
panel.repaint();
}
Or you can do this without creating a class that extends JPanel:
JPanel panel1 = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// code here
}
};
panel1.repaint();
I think the normal thing is to extend JPanel for each unique panel you wish to create. In other words, each panel you create is its own class. Then you can overwrite the paint method for each individually.

adding of graphic Class object in netbean JFrame

i am adding graphic class object "g" in JFrame class in Netbeans. but error are occurring as
"non static variable g can not be referenced from a static context"
following are code of graphic class (just drawing a rectangle)
public class grafix extends JComponent {
#Override
public void paintComponent(Graphics g){
Graphics2D g2= (Graphics2D) (Graphics) g;
Rectangle r = new Rectangle(15,10,200,300);
g2.draw(r);
}
}
and
following are object adding line in Main() of JFrame class.
new JFrame().getContentPane().add(g);
object "g" been declared in JFrame class. Since i am using Netbean that why i have to use getContentPane().add() instead of JFrame.add();

Drawing shapes does not work in graphics2D

The below code is to display a triangle in applet.But it does not work for me. If i pass Graphics g instead of Graphics2D g then it works fine.But i want to know what the mistake i am doing while using Graphics g. I am new to java and learning from some online tutorials. So please correct my program and tell me what mistake i am doing.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Vehicle extends JFrame {
final int WIDTH = 900;
int HEIGHT = 650;
public void init() {
setSize(WIDTH, HEIGHT);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics2D g) {
Graphics2D g2 = (Graphics2D) g;
Dimension d = getSize();
System.out.println(d);
int[] yPoints={150,250,250};
int[] xPoints={200,150,250};
g2.setColor(Color.green);
g2.drawPolygon(xPoints, yPoints, 3);
g2.drawRect(100, 100, 100, 100);
g2.setColor(Color.red);
g2.fillPolygon(xPoints, yPoints, 3);
}
public static void main(String[] args) {
Vehicle v= new Vehicle();
v.init();
}
}
The method paint(Graphics g) is defined in java.awt.Component. This is more or less legacy code. However, this API hasn't changed for a long time and is inherited by modern Swing components, such as JFrame.
You can't simply change the method signature (in your case to paint(Graphics2D g)), you have to live with the signature defined by the API.
So, in your case, the paint(Graphics2D g) does not override the API method paint(Graphics g), and thus is not called when updating the JFrame. Nothing is painted.
Change your code like this:
----------------%<----------------------
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics g) { // <-- Change from Graphics2D to Graphics
Graphics2D g2 = (Graphics2D) g;
Dimension d = getSize();
System.out.println(d);
int[] yPoints={150,250,250};
int[] xPoints={200,150,250};
---------------->%----------------------
Take a good look at what your program is doing before looking for assistance. (Not scolding you, just trying to help for the future.)
You have public void paint(Graphics2D g), which, as Petersen stated, is not a method in the JFrame class. A good trick to use to check if your methods in swing will do what tutorials say they will do is to put #Override above the method. If it errors, it means that method is not in JFrame or whatever superclass you have. Otherwise, it is overriding the method.
Additionally, another flag would be the next line: Graphics2D g2 = (Graphics2D) g;
Here you're casting a Graphics2D object as a Graphics2D object... which should never need to happen.. haha
If you are just getting started with swing and Graphics2D I suggest learning some of the Panels systems and other low-level things like drawImage or drawString, if you haven't done so already.
Working with Java2D it often helps to imagine your application as an animation. Imagine that at one point one specific frame(I am talking about animation frames okay) is drawn on the screen. When some event occurs we replace this frame with another frame incorporating the change much like the way cartoons or animation movies are built. How we draw animation frames? How do we switch between frames?
Java API provides a paint(graphics g) method for its components to be drawn. And then to update the same component you really call repaint() which simply calls paint(Graphics g) again and displays any changes on to the screen. This API method has a strict signature that we shall follow. It is paint(Graphics g). But Graphics2D is much like a cool kid on the block that provides more functionality because Graphics was too old(legacy) and not cool anymore. So how do we do this because paint(Graphics g) only accepts Graphics not Graphics2D? Graphics2D is a subclass of Graphics okay.
Protocol is simple,
Use the legacy paint(Graphics g) method of every component.
Once we have used super.paint(Graphics g) (if needed) ,we can typecast the Graphic object that we were using for legacy purposes to Graphics2D to get enhance functionality.(you have done this step right)
Problem with your code:
It is only the signature. Java and the repaint() expect the method to be paint(Graphics g) but you have changed the signature and now the above protocol (or contract) is broken. The idea is to keep the contract(by not changing the signature) and then typecast and override to add extended features. Java is not able to find paint(Graphics g) and so repaint() will not also find paint(Graphics g).

Having images as background of JPanel

I am new in Java and I am currently creating a game with graphics. I have this class that extends from JFrame. In this class, I have many JPanels that needs an image as background. As I know, to be able to paint images in the JPanel, I need to have a separate class that extends from JPanel and that class's paintComponent method will do the work. But I don't want to make separate classes for each JPanel, I have too many of them; and with the fact that I am only concerned with the background. How can I do this? is it with an anonymous inner class? How?
For better understanding I provided some code:
public GUI extends JFrame {
private JPanel x;
...
public GUI() {
x = new JPanel();
// put an image background to x
}
Why not make a single class that takes a Image??
public class ImagePane extends JPanel {
private Image image;
public ImagePane(Image image) {
this.image = image;
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(0, 0) : new Dimension(image.getWidth(this), image.getHeight(this));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
}
}
You would even provide hints about where it should be painted.
This way, you could simply create an instance when ever you needed it
Updated
The other question is, why?
You could just use a JLabel which will paint the icon for you without any additional work...
See How to use labels for more details...
This is actually a bad idea, as JLabel does NOT use it's child components when calculating it's preferred size, it only uses the size of the image and the text properties when determining it's preferred size, this can result in the component been sized incorrectly
You don't have to make another class for it? You could just do:
x = new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
//draw background image
}
};
You can do this in single line:
panelInstance.add(new JLabel(new ImageIcon(ImageIO.read(new File("Image URL")))));
I hope it will work for you.

Drawing multiple Shapes on the same Canvas when pressed a button

I need to draw a square,line,circle when pressed the corespondent button. Also I need to do this using FactoryMethod design pattern.
I simply don't get how to draw on the same canvas, and because I have a class for every shape, how do i get the corresponding paint(Graphics g) method?
This is what I have so far:
public interface Shape
{
public void draw();
}
Square class
public class Square extends Canvas implements Shape
{
Graphics g;
Canvas c;
public Canvas getCanvas()
{
return c;
}
public void setCanvas(Canvas c)
{
this.c=c;
}
#Override
public void draw()
{
g.drawRect(20, 30,100,100);
}
public void paint(Graphics g)
{
g.drawRect(20, 30,100,100);
g.setColor(Color.BLUE);
}
}
Factory
public class ClassFactory extends Canvas{
JButton patrat;
Figura d;
String nameButon;
Graphics g;
Canvas c;
public Canvas getCanvas()
{
return c;
}
public void setCanvas(Canvas c)
{
this.c=c;
}
public ClassFactory()
{
super();
this.setBounds(0,0,500,450);
this.setBackground(Color.CYAN);
JButton square=new JButton("square");
patrat.setBounds(510, 10, 80,25);
JPanel panel=new JPanel();
panel.setLayout(null);
panel.setBounds(0,0,600,500);
panel.setBackground(Color.GRAY);
panel.add(this);
this.addComponentListener(p);
panel.add(square);
JFrame f=new JFrame("Draw");
f.setLayout(null);
f.setBounds(50,50,700,600);
f.getContentPane().setBackground(Color.DARK_GRAY);
f.setResizable(false);
f.add(panel);
f.show();
}
public Shape getFigure()
{
Shape d=null;
if(nameButton.equals("square"))
{
d=new Square();
}
return d;
}
}
Suggestions:
The factory should not create a GUI, should not extend Canvas, or really extend anything, it should not create a JFrame or do anything of the sort. It should concern itself only with creating objects of Shape child classes. The GUI creation code should be elsewhere.
Likely the factory's getFigure(...) method will be the one to produce this. It should likely accept a parameter, perhaps a String or an enum, that tells it what sub-class of Shape to produce.
Shape's draw method should likely accept a Graphics parameter so that its children can use it to draw with.
You shouldn't mix AWT components (i.e., Canvas) and Swing components together unnecessarily. Instead, just draw in a JPanel's paintComponent(Graphics g) method, not in a Canvas's paint(Graphics g) method.
In that JPanel have a Shape variable that is not initialized, perhaps called shape.
Inside of paintComponent(...) check if shape is null. If not, draw it by calling shape.draw(g).
In your JButton ActionListeners, have the Factory create a Shape child class object and assign it to the shape variable
Then call repaint() on the JPanel that does the drawing.

Categories