Drawing an Object Using Getgraphics() Without Extending Jframe

Drawing an object using getGraphics() without extending JFrame

If you want to change the way your component is being drawn (you are adding rectangles), you need to redefine paintComponent() in that component. In your code, you are using getGraphics().

You shouldn't call getGraphics() on a component. Any painting you do (to the Graphics returned) will be temporary and will be lost the next time Swing determines a component needs to be repainted.

Instead, you should override the paintComponent(Graphics) method (of the JComponent or JPanel), and do the painting in this method, using the Graphics object received as argument.

Check this link for further reading.

Below is your code, corrected.

import javax.swing.*;
import java.awt.*;

public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(600, 400);

JPanel panel = new JPanel() {
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, 100, 100);
}
};
frame.add(panel);

// Graphics g = panel.getGraphics();
// g.setColor(Color.BLUE);
// g.fillRect(0, 0, 100, 100);

frame.validate(); // because you added panel after setVisible was called
frame.repaint(); // because you added panel after setVisible was called
}
}

Another version, does the exact same thing, but may be clearer to you:

import javax.swing.*;
import java.awt.*;

public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(600, 400);

JPanel panel = new MyRectangleJPanel(); // changed this line
frame.add(panel);

// Graphics g = panel.getGraphics();
// g.setColor(Color.BLUE);
// g.fillRect(0, 0, 100, 100);

frame.validate(); // because you added panel after setVisible was called
frame.repaint(); // because you added panel after setVisible was called
}
}

/* A JPanel that overrides the paintComponent() method and draws a rectangle */
class MyRectangleJPanel extends JPanel {
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, 100, 100);
}
}

Java JPanel getGraphics()

Here are some very simple examples which show how to paint outside paintComponent.

The drawing actually happens on a java.awt.image.BufferedImage, and we can do that anywhere, as long as we're on the Event Dispatch Thread. (For discussion of multithreading with Swing, see here and here.)

Then, I'm overriding paintComponent, but only to paint the image on to the panel. (I also paint a little swatch in the corner.)

This way the drawing is actually permanent, and Swing is able to repaint the panel if it needs to without causing a problem for us. We could also do something like save the image to a file easily, if we wanted to.

PaintAnyTime screenshot

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;

/**
* Holding left-click draws, and
* right-clicking cycles the color.
*/
class PaintAnyTime {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new PaintAnyTime();
}
});
}

Color[] colors = {Color.red, Color.blue, Color.black};
int currentColor = 0;
BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
Graphics2D imgG2 = img.createGraphics();

JFrame frame = new JFrame("Paint Any Time");
JPanel panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Creating a copy of the Graphics
// so any reconfiguration we do on
// it doesn't interfere with what
// Swing is doing.
Graphics2D g2 = (Graphics2D) g.create();
// Drawing the image.
int w = img.getWidth();
int h = img.getHeight();
g2.drawImage(img, 0, 0, w, h, null);
// Drawing a swatch.
Color color = colors[currentColor];
g2.setColor(color);
g2.fillRect(0, 0, 16, 16);
g2.setColor(Color.black);
g2.drawRect(-1, -1, 17, 17);
// At the end, we dispose the
// Graphics copy we've created
g2.dispose();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(), img.getHeight());
}
};

MouseAdapter drawer = new MouseAdapter() {
boolean rButtonDown;
Point prev;

@Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
prev = e.getPoint();
}
if (SwingUtilities.isRightMouseButton(e) && !rButtonDown) {
// (This just behaves a little better
// than using the mouseClicked event.)
rButtonDown = true;
currentColor = (currentColor + 1) % colors.length;
panel.repaint();
}
}

@Override
public void mouseDragged(MouseEvent e) {
if (prev != null) {
Point next = e.getPoint();
Color color = colors[currentColor];
// We can safely paint to the
// image any time we want to.
imgG2.setColor(color);
imgG2.drawLine(prev.x, prev.y, next.x, next.y);
// We just need to repaint the
// panel to make sure the
// changes are visible
// immediately.
panel.repaint();
prev = next;
}
}

@Override
public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
prev = null;
}
if (SwingUtilities.isRightMouseButton(e)) {
rButtonDown = false;
}
}
};

PaintAnyTime() {
// RenderingHints let you specify
// options such as antialiasing.
imgG2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
imgG2.setStroke(new BasicStroke(3));
//
panel.setBackground(Color.white);
panel.addMouseListener(drawer);
panel.addMouseMotionListener(drawer);
Cursor cursor =
Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
panel.setCursor(cursor);
frame.setContentPane(panel);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

It's also possible to set up a JLabel with an ImageIcon, although personally I don't like this method. I don't think JLabel and ImageIcon are required by their specifications to see changes we make to the image after we've passed it to the constructors.

This way also doesn't let us do stuff like painting the swatch. (For a slightly more complicated paint program, on the level of e.g. MSPaint, we'd want to have a way to select an area and draw a bounding box around it. That's another place we'd want to be able to paint directly on the panel, in addition to drawing to the image.)

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;

/**
* Holding left-click draws, and
* right-clicking cycles the color.
*/
class PaintAnyTime {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new PaintAnyTime();
}
});
}

Color[] colors = {Color.red, Color.blue, Color.black};
int currentColor = 0;
BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
Graphics2D imgG2 = img.createGraphics();

JFrame frame = new JFrame("Paint Any Time");
JLabel label = new JLabel(new ImageIcon(img));

MouseAdapter drawer = new MouseAdapter() {
boolean rButtonDown;
Point prev;

@Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
prev = e.getPoint();
}
if (SwingUtilities.isRightMouseButton(e) && !rButtonDown) {
// (This just behaves a little better
// than using the mouseClicked event.)
rButtonDown = true;
currentColor = (currentColor + 1) % colors.length;
label.repaint();
}
}

@Override
public void mouseDragged(MouseEvent e) {
if (prev != null) {
Point next = e.getPoint();
Color color = colors[currentColor];
// We can safely paint to the
// image any time we want to.
imgG2.setColor(color);
imgG2.drawLine(prev.x, prev.y, next.x, next.y);
// We just need to repaint the
// label to make sure the
// changes are visible
// immediately.
label.repaint();
prev = next;
}
}

@Override
public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
prev = null;
}
if (SwingUtilities.isRightMouseButton(e)) {
rButtonDown = false;
}
}
};

PaintAnyTime() {
// RenderingHints let you specify
// options such as antialiasing.
imgG2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
imgG2.setStroke(new BasicStroke(3));
//
label.setPreferredSize(new Dimension(img.getWidth(), img.getHeight()));
label.setBackground(Color.white);
label.setOpaque(true);
label.addMouseListener(drawer);
label.addMouseMotionListener(drawer);
Cursor cursor =
Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
label.setCursor(cursor);
frame.add(label, BorderLayout.CENTER);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

How can i draw circle in JFrame without overriding paint(...) or paintComponent(...)

You can:

  1. Create a BufferedImage of the size desired
  2. Get its Graphics object via createGraphics() (for a Graphics2D object) or getGraphics() (for a Graphics object)
  3. Draw with the above graphics object, and then .dispose() it
  4. Create an ImageIcon using the above image via new ImageIcon(myImage)
  5. Display the icon in a JLabel via .setIcon(myIcon)

done

Sample Image

e.g.,

import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

import javax.swing.*;

public class SomeDrawingFoo extends JPanel {
private static final int IMG_W = 400;
private static final int IMG_H = IMG_W;
private static final Color COLOR_1 = Color.RED;
private static final Color COLOR_2 = Color.BLUE;
private static final float DELTA = 40f;
private JLabel label = new JLabel();

public SomeDrawingFoo() {

// create image and draw with it
BufferedImage myImage = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = myImage.createGraphics();
Paint gradPaint = new GradientPaint(0, 0, COLOR_1, DELTA, DELTA, COLOR_2, true);
g2.setPaint(gradPaint);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.fillOval(10, 10, IMG_W - 20, IMG_H - 20);
g2.dispose();

// put image into Icon and then into JLabel
Icon myIcon = new ImageIcon(myImage);
label.setIcon(myIcon);
add(label);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(()-> {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SomeDrawingFoo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}

}

Notes:

  • You could also call .getGraphics() on your JPanel or JFrame, but the object obtained would not be stable or long-lasting, and this will lead to images that disappear or that cause a NullPointerException. I most definitely do NOT recommend this
  • Usually the easiest way to do your graphics is the way that you stated you wished not doing -- draw within a JPanel's protected void paintComponent(Graphics g) method.

Java Graphics Not Executing Paint Function Without extends

Is it possible to draw graphics without using extends at all?

Yes, it sure is possible. As mentioned by @HovercraftFullOfEels in a comment:

You can draw on a BufferedImage..

If you display that image in a JLabel (lets call it label) then to get the screen to update after the image has changed, simply call:

label.repaint();

drawing to a JPanel without inheritance

If you are drawing your images at runtime you should use BufferedImage.

Create a BufferedImage, call getGraphics() on it to get its Graphics object, draw to it using the Graphics(2D) api, then call Graphics.dispose() (not strictly necessary but a good habit) and as the previous poster suggested either create an ImageIcon with it and put in a JLabel using setIcon() or subclass JPanel / JComponent and draw it in paintComponent

How to draw graphics outside of the paint() function in a JFrame

Drawing to the screen in Java is (almost) always done in paint(). What you need for your class is:

class DrawingFrame extends JFrame {

private Image bullseye = new Bullseye(20,20); //width,height

public void paint(Graphics g) {
g.drawImage(bullseye,10,20);
g.drawImage(bullseye,20,20);
g.drawImage(bullseye,30,20);
}

}

class Main {
public static void main(String[] args) {
DrawingFrame frame = new DrawingFrame();

// later
frame.setVisible(true);
}
}

If you need to turn on the drawing of bullseyes at a specific time, create a flag on the DrawingFrame object, and set it when you need them. You will need to call repaint() when the flag is set.



Related Topics



Leave a reply



Submit