Drawing shapes does not work in graphics2D - java

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).

Related

Java (re)painting mechanism [duplicate]

In java awt or swing when you want to change painting of some component you usually have to override the method paint(Graphics g) (in awt) or paintComponent(Graphics g) (in swing).
This is usually (maybe allways - I'm not sure) done when you are creating the component for example:
JPanel jPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//... my implementation of paint, some transfromations, rotation, etc
}
};
Imagine that you have container of components which could for example consists of some JLabels, some JTextFields, some image. Which will be all put on one component.
By container I mean you have some list or map with ids or some similar structure in which are all components you will put on one JFrame.
The question is if I can change the painting method after creating with all of the components which are in this list in the moment when all of them are already created. For example I want do the rotation action (rotate), which is defined in Graphisc2D, with all of them.
So basicaly what I want is that I throught the list of componets I have and say:
"All of you (components) which are in the list will be rotated by some angle". Is that possible? If yes how?
Edit:
This is my not correctly working solution:
graphicalDisplayPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
g2d.rotate(Math.PI, anchorx, anchory);
}
#Override
public void paintChildren(Graphics g) {
super.paintChildren(g);
Graphics2D g2d2 = (Graphics2D) g;
g2d2.rotate(Math.PI, anchorx, anchory);
}
};
JFrame jFrame = JFrame();
// ... setting dimension, position, visible etc for JFrame, it works correctly nonrotated
jFrame.setContentPane(graphicalDisplayPanel);
I have not tested this, but it seems like it would work. A JComponent's paint() method calls:
paintComponent(co);
paintBorder(co);
paintChildren(co);
where co is a Graphics object. In theory you create an image, retrieve the graphics object and then pass that into paintChildren(). you will have to call paintComponent() and paintBorder() yourself, if you do this. Then, just rotate the image and draw it into your component. You may have to crop the image or resize your component accordingly for this to work. It might look something like this:
BufferedImage myImage;
#Override
public void paint(Graphics g){
myImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TRANSLUCENT);
//using a transparent BufferedImage might not be efficient in your case
Graphics myGraphics = myImage.getGraphics();
super.paintComponent(g);
super.paintBorder(g);
super.paintChildren(myGraphics);
//rotation code here
// ...
//draw children onto your component
g.drawImage(myImage, 0, 0,getWidth(), getHeight(), null);
}
I hope I didn't make any mistakes, please let me know if this works.
So basicaly what I want is that I throught the list of componets I have and say: "All of you (components) which are in the list will be rotated by some angle".
If you want to rotate panel and therefore all the components on the panel as a single using then you need to do the custom painting in the paintComponent() method.
If you want to rotate, for example, individual images that each have a different angle of rotation then you can again do this in the paintComponent(...) method and change the angle for each component.
Or, in this second case you can use the Rotated Icon class. In this case the Icon is just added to a JLabel. Then you can change the degrees of rotation and repaint the label, so there is no custom painting (except in the Icon itself).

Antialiasing of text in Swing components , using JDK 7

please tell me how to enable antialiasing for text in Swing components (using JDK 7), not overriding method paintComponent() parent class. To read about this topic , which says that for this method is used
putClientProperty(
com.sun.java.swing.SwingUtilities2.aa_text_property_key, Boolean.TRUE);
requires a package com.sun.java.swing.SwingUtilities2, which is absent in the JDK older 5th version. Do not want to include in the project the outdated methods and libraries, could you please tell me what methods are used now for smoothing text of the components(similar putClientProperty()).
PLEASE DON'T WRITE about the use methods
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_On);
//or
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIAsing,
RenderingHints.VALUE_TEXT_ANTIALias_on);
because they do NOT WORK EVEN IF YOU OVERRIDE the paintComponent() parent class, the example below:
JButton button = new JButton("Button X O") {
#Override
public void paintComponent(Graphics g){
Graphics2D g2d = (Graphics2D) g;
//g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
//RenderingHints.VALUE_ANTIALIAS_On);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIASING_ON);
super.paintComponent(g2d);
g2d.dispose();
}
};
It's not Work! Please, help.
Global settings using system properties:
System.setProperty("awt.useSystemAAFontSettings","on");
System.setProperty("swing.aatext", "true");
By the way, the override should work if you override paint(Graphics g) (which then paints the component, border and children) in the root container instead of paintComponent(Graphics g).

Why is paintComponent() run even though no one calls it?

I was wondering if someone could explain how/why paintComponent() is called right after all the statements in main() are run. The reason I am confused is that there is no explicit call to painComponent() but it is run regardless.
// JComponent is a base class for custom components
public class SimpleDraw extends JPanel {
public static void main(String[] args) {
SimpleDraw canvas = new SimpleDraw();
JFrame f = new JFrame("SimpleDraw"); // jframe is the app window
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(400, 400); // window size
f.setContentPane(canvas); // add canvas to jframe
f.setVisible(true); // show the window
}
// custom graphics drawing
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g; // cast to get 2D drawing methods
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, // antialiasing look nicer
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(32)); // 32 pixel thick stroke
g2.setColor(Color.BLUE); // make it blue
g2.drawLine(0, 0, getWidth(), getHeight()); // draw line
g2.setColor(Color.RED);
g2.drawLine(getWidth(), 0, 0, getHeight());
}
}
Here is a decent little write-up on how paintComponent is handled.
Excerpt:
Who calls paintComponent
... This method is called because the user did
something with the user interface that required redrawing, or your
code has explicitly requested that it be redrawn. Called automatically
when it becomes visible When a window becomes visible (uncovered or
deminimized) or is resized, the "system" automatically calls the
paintComponent() method for all areas of the screen that have to be
redrawn. Called indirectly from a user-defined listener via repaint() ...
There's more in the write-up as well as some reference links, which, unfortunatelly, are all broken.
I also found this blog post which discusses painting/drawing in Java from a very basic point of view. Check out the first paragraph:
Why do we put all our graphical drawing code into a paintComponent()
method? It seems odd, since it would seem we should be able to simply
stick some simple graphics commands into our main() method in a Java
application and just get the drawing done. Where does paintComponent
come from? If we never call it in our code, how does it get executed?
In the Java docs you actually have to read up on paint to start getting an idea of what going on. The paintComponent documentation is not very helpful.

How to draw a filled circle in Java?

I have a JPanel with a Grid Layout. In the "cells" of the grid I can put different elements (for example JButtons). There is no problems with that. But now I want to put a filled circle in some of the cells. I also would like to relate an ActionListener with these circles. In more details, if I click the circle it disappears from the current cell and appears in another one. How can I do it in Java? I am using Swing.
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
// Assume x, y, and diameter are instance variables.
Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
g2d.fill(circle);
...
}
Here are some docs about paintComponent (link).
You should override that method in your JPanel and do something similar to the code snippet above.
In your ActionListener you should specify x, y, diameter and call repaint().
/***Your Code***/
public void paintComponent(Graphics g){
/***Your Code***/
g.setColor(Color.RED);
g.fillOval(50,50,20,20);
}
g.fillOval(x-axis,y-axis,width,height);

Java Swing NullPointerException when drawing

I'm using a custom JLayeredPane.
I have several Shapes which needed to be drawn on different layers in the JLayeredPane.
To test this I create a JPanel and ask its graphics. Then I draw a test rectangle on that JPanel (preparing the graphics) and in my paintComponent method from the JLayeredPane I finally draw everything. But this fails (NullPointerException).
public class MyCustomPanel extends JLayeredPane {
// test
JPanel testpane;
Graphics g2;
// test
// constructor
public MyCustomPanel() {
testpane = new JPanel();
this.add(testpane, new Integer(14));
g2 = testpane.getGraphics();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2.drawRect(10, 10, 300, 300);
}
}
// run:
//Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
// at view.MyCustomPanel.paintComponent(MyCustomPanel.java:65)
Why can't I draw on such a JPanel from within my JLayeredPane? I can draw directly on my JLayeredPane from within my paintComponent method but that's on the default Panel from the JLayeredPane. I need to create and draw on several layers which are added in my JLayeredPane.
What am I doing wrong? :s
You should use g2 casting the Graphics that is passed to you:
Graphics2D g2 = (Graphics2D)g;
Why don't you try decoupling things?
class InnerPanel extends JPanel
{
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.drawRect(....);
}
}
class MyLayered extends JLayeredPane()
{
MyLayered()
{
this.add(new InnerPanel(), 14);
}
}
this makes more sense..
Also because you are trying to do something that doesn't agree with Swing behaviour.
Swing will care by itself to call the appropriate paint methods over things that must be displayed, and to go with this protocol you should tell Graphics objects what to draw when Swing asks it to your objects (calling the paint) method, not when you want to do it.
In this way whenever Swing wants to draw your JLayeredPane you just draw things on a Graphic object of other things without considering that Swing will call their appropriate methods when it's the right time to do so.
In conclusion: you can't draw something on a Graphic object when you want it. You can do it just inside methods invoked by Swing, because otherwise Graphics of these objects doesn't mean anything
The variable g2 is probably null because you set it in the constructor, not when drawing. Instead, use the "g" that was passed in.
You can only get a legitimate Graphics from a component that is currently being painted. Otherwise, it's not valid. At the point you're requesting it, the MyCustomPanel() isn't being displayed, and neither is testpane.

Categories