What is the simplest way to draw in Java?
import java.awt.*;
import javax.swing.*;
public class Canvas
{
private JFrame frame;
private Graphics2D graphic;
private JPanel canvas;
public Canvas()
{
frame = new JFrame("A title");
canvas = new JPanel();
frame.setContentPane(canvas);
frame.pack();
frame.setVisible(true);
}
public void paint(Graphics g){
BufferedImage offImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Grapics2D g2 = offImg.createGraphics();
g2.setColor(new Color(255,0,0));
g2.fillRect(10,10,200,50);
}
}
This doesn't work and I have no idea how to get anything to appear.
Easiest way:
public class Canvas extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// painting code goes here.
}
}
You simply need to extend JPanel and override the paintComponent method of the panel.
I'd like to reiterate that you should not be overriding the paint method.
Here is a very minimalistic example that works.
public static void main(String[] args) {
JFrame f = new JFrame();
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(0, 0, 100, 100);
}
};
f.add(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
// No. 1
// Create a graphics context on the buffered image
Graphics2D g2d = bimage.createGraphics();
// Draw on the buffered image
g2d.setColor(Color.red);
g2d.fill(new Ellipse2D.Float(0, 0, 200, 100));
g2d.dispose();
// No.2
// In case the buffered image supports transparency
g2d = bimage.createGraphics();
// Transparency is created on all the filled pixels
Color transparent = new Color(0, 0, 0, 0);
g2d.setColor(transparent);
g2d.setComposite(AlphaComposite.Src);
g2d.fill(new Rectangle2D.Float(20, 20, 100, 20));
g2d.dispose();
To make something appear in paint(Graphics g) you need to call the drawing methods (like fillRect) on that Graphics. You are creating a bitmap and then drawing to the bitmap, not the screen.
public void paint(Graphics g){
g.setColor(new Color(255,0,0));
g.fillRect(10,10,200,50);
}
jjnguy already wrote how to do it right ... but here why it does not work in your example:
import java.awt.*;
import javax.swing.*;
public class Canvas
Here you have a class which does not relate in any way to Swing or AWT.
(By the way, you may want to select another name to avoid confusion with java.awt.Canvas.)
{
private JFrame frame;
private Graphics2D graphic;
private JPanel canvas;
public Canvas()
{
frame = new JFrame("A title");
canvas = new JPanel();
frame.setContentPane(canvas);
Here you are creating a new JPanel (for confusion also named canvas), and add it to the frame.
Is is this panel's paint and paintComponent methods which are called when the system shows your frame.
frame.pack();
frame.setVisible(true);
}
public void paint(Graphics g){
BufferedImage offImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Grapics2D g2 = offImg.createGraphics();
g2.setColor(new Color(255,0,0));
g2.fillRect(10,10,200,50);
}
This paint method is never used at all (since it is not part of a component), and if it would be called, then you are only painting to some BufferedImage, not to the screen.
}
Related
I am making a Java GUI and I have searched the internet for 2 hours on how make a gradient for a JPanel. The code below is that I have, but when run the gradient does not show. What is wrong?
I've tried many other posts from similar questions on this throughout the Internet but they don't work. I've tried numerous versions, but I also don't exactly know how to run a class within a class. Can someone help me please?
class TestPanel extends JPanel{
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
int w = getWidth();
int h = getHeight();
Color color1 = Color.BLUE;
Color color2 = Color.GREEN;
GradientPaint gp = new GradientPaint(0, 0, color1, 0, h, color2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
}
} //this is nested within the main class
//some code
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CreateGUI cg = new CreateGUI();
cg.create(); //previous method (not mentioned here)
CreateGUI.TestPanel tp = cg.new TestPanel(); //problem
JPanel panel = new JPanel();
f.add(panel);
f.setSize(800, 600);
f.setLocationRelativeTo(null);
f.getContentPane().setLayout(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
I expect there to be a gradient but there is none; the background of the JPanel is still white
The instance of TestPanel is never added to anything
null layouts will prevent the component from been sized and positioned, so you won't see anything even if your did the previous step
You should, unless you're adding child components to it, provide a sizing hint, so that the layout managers have something to work with.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
class TestPanel extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
int w = getWidth();
int h = getHeight();
Color color1 = Color.BLUE;
Color color2 = Color.GREEN;
GradientPaint gp = new GradientPaint(0, 0, color1, 0, h, color2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
g2d.dispose();
}
}
}
I have this simple code:
class Success extends JFrame {
public JButton button1;
public JButton button2;
public Success() {
JPanel panel = new JPanel();
getContentPane().add(panel);
setSize(600, 800);
button1 = new JButton("press");
button2 = new JButton("this");
button1.setBounds(100, 200, 100, 100);
button2.setBounds(400, 500, 100, 100);
panel.add(button1);
panel.add(button2);
panel.setLayout(null);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawLine(button1.getX(), button1.getY(), button2.getX(), button2.getY());
}
public static void main(String []args) {
Success s = new Success();
s.setVisible(true);
}
}
it works but checkout this image:
I want the accurate position of buttons.
I tried getLocationOnScreen() and getLocation() but they had the same problem.
First of all, you should never override the paint method of a JFrame, but rather the paintComponent method of your content panel.
That being said, SwingUtilities has methods to find the coordinates, given the source (the button in your case) and the destination (the frame in your case) Component objects :
public void paint(final Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
Point p1 = SwingUtilities.convertPoint(button1, 0, 0, this);
Point p2 = SwingUtilities.convertPoint(button2, 0, 0, this);
g2.drawLine(p1.x, p1.y, p2.x, p2.y);
}
Note that you probably encountered the problem of the frame's title bar/border not being taken into account, hence the vertical shift .
i've seen a similar question, but i didn't get a proper solution, so here's my problem:
(Coloring an area of BufferedImage)
i'm creating a BufferedImage, then i grab the graphics from this image, i'll paint a green rectangle on it and let it show within a JPanel... but surprise - it's not green, wo where is my error??
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ViewPortTest {
public static void main(String[] args) {
new ViewPortTest().startUp();
}
private void startUp() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new TestPanel() );
frame.pack();
frame.setVisible(true);
}
private class TestPanel extends JPanel{
private static final long serialVersionUID = 1L;
private int myWidth = 256;
private int myHeight = 156;
private BufferedImage img;
public TestPanel() {
super();
setPreferredSize(new Dimension(myWidth, myHeight) );
img = new BufferedImage(myWidth, myHeight, BufferedImage.TYPE_4BYTE_ABGR);
img.createGraphics();
img.getGraphics().setColor(Color.GREEN);
img.getGraphics().fillRect(0, 0, 256, 256);
img.getGraphics().dispose();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null ){
g.drawImage(img, 0, 0, null);
}
}
}
}
what comes out is this:
so - where is my green rectangle???
The problem is the multiple calls to getGraphics(). It is creating multiple Graphics objects. This is essentially an alias for createGraphics(). See BufferedImage#getGraphics. A simple fix would be to store the Graphics2D object created by calling createGraphics() and make all of your calls on that object:
Graphics2D g = img.createGraphics();
g.setColor(Color.GREEN);
g.fillRect(0, 0, 256, 256);
g.dispose();
Because createGraphics() always returns a new Graphics2D context. So you set the green color on one context, and you fill a rectange using another which does not know about the green color you set on another context.
Try this:
Graphics2d g = img.createGraphics();
g.setColor(Color.GREEN);
g.fillRect(0, 0, 256, 256);
g.dispose();
Simple problem with Graphics instance:
Graphics2D createGraphics = img.createGraphics();
createGraphics.setColor(Color.GREEN);
createGraphics.fillRect(0, 0, 256, 256);
createGraphics.dispose();
It's the original image:
I use java.awt.Graphics.fillRect(int x, int y, int width, int height) to add a coloured rectangle on the image.
Graphics imageGraphics = image.createGraphics();
Color color = new Color(0,0,0,100);
imageGraphics.setColor(color);
imageGraphics.fillRect(0, 0, 800, 600);
So the image has been inverted and looks like this:
After that,I want to clear the black transparent rectangle partly and show the original image.
imageGraphics.clearRect(100,100,100,100);
But the effect is like this:
What my requirement is:
I want to know why it doesn't work and is there any other way to realize it?
Remember, painting is destructive. It might be possible to use AlphaComposite to achieve this result, but a simpler solution might be to simple constructive a compound shape and paint that instead.
The following example creates two Rectangles, one been the area we want to fill and one been the area we want to show, the second is then subtracted from the first (to create the window) and then the result is painted on top of the image
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ShowArea {
public static void main(String[] args) {
new ShowArea();
}
public ShowArea() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
public TestPane() {
try {
img = ImageIO.read(new File("sample.png"));
Rectangle bounds = new Rectangle(0, 0, img.getWidth(), img.getHeight());
Rectangle clip = new Rectangle(150, 10, 100, 100);
Area area = new Area(bounds);
area.subtract(new Area(clip));
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.BLACK);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.fill(area);
g2d.dispose();
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
If I were doing some kind of paint program, I would do this all within the paintComponent method or in some way that it didn't effect the original image, otherwise you've basic destroyed the image until you re-load it
Another solution might be to take a copy of the original area you want to keep and repaint it back on top after, for example...
img = ImageIO.read(new File("sample.png"));
// This is the portion of the image we want to save...
BufferedImage cutout = img.getSubimage(150, 10, 100, 100);
// This is the area we want to paint over...
Rectangle bounds = new Rectangle(0, 0, img.getWidth(), img.getHeight());
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.BLACK);
// Save the current Composite so we can reset it...
Composite comp = g2d.getComposite();
// Apply the composite and fill the area...
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.fill(area);
// Reset the composite
g2d.setComposite(comp);
// Draw the part of the image we saved previously...
g2d.drawImage(cutout, 150, 10, this);
g2d.dispose();
You cant do that the way you're trying to.
It can be done by creating a BufferedImage filled with Color(0,0,0,200), then in that image draw rectangle with color Color(0,0,0,200) and then apply it on image.
Remember, that drawing filledRectange is not a "undo operation"- it is written on pixels and it can't be undone.
EDIT
Icon imageIcon = new javax.swing.ImageIcon("image.jpg");
BufferedImage mask = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
BufferedImage image = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
imageIcon.paintIcon(null, image.getGraphics(), 0, 0);
Graphics maskGraphics = mask.getGraphics();
//drawing grey background
maskGraphics.setColor(new Color(0, 0, 0, 120));
maskGraphics.fillRect(0, 0, mask.getWidth(), mask.getHeight());
//drawing black frame
maskGraphics.setColor(new Color(0, 0, 0, 255));
maskGraphics.drawRect(99, 99, 301, 301);
//drawing original image window
maskGraphics.drawImage(image, 100, 100, 400, 400, 100, 100, 400, 400, null);
//apply mask on image
new ImageIcon(mask).paintIcon(null, image.getGraphics(), 0, 0);
//result presentation
label.setIcon(new ImageIcon(image));
Yes this is easily doable. The problem is that any draw operation is destructive, what you see is what you get, the information that was painted upon is lost.
Something like this where you store a subimage, do your paint operation then draw the subimage back on top.
public class Q23709070 {
public static void main(String[] args) {
JFrame frame = new JFrame();
Panel p = new Panel();
frame.getContentPane().add(p);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
static class Panel extends JPanel {
int w = 400;
int h = 400;
int x = 100;
int y = 100;
BufferedImage img;
BufferedImage subImg;
BufferedImage save;
public Panel() {
try {
img = ImageIO.read(getClass().getResourceAsStream("0qzCf.jpg"));
} catch (IOException e) {
}
subImg = img.getSubimage(x, y, w, h);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Color g2dColor = g2d.getColor();
Color fillColor = new Color(0, 0, 0, 100);
g2d.drawImage(img, 0, 0, null);
g2d.setColor(fillColor);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.drawImage(subImg, x, y, null);
g2d.setColor(g2dColor);
if (save == null) {
save = new BufferedImage(img.getWidth(), img.getHeight(),
img.getType());
this.paint(save.getGraphics());
try {
ImageIO.write(save, "jpg", new File("save.jpg"));
} catch (IOException e) {
}
}
}
#Override
#Transient
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(), img.getHeight());
}
}
}
Rendering
I've done days of searching for a way to draw pixels to a window in java with mouse capture. I'm looking for some framework I can just plug in. It seems like it would be so simple... Any help will be greatly appreciated.
(EDIT)
Here is some non-working code.
public class Base extends JPanel implements MouseMotionListener {
public static void main(String[] args) {
new Base();
}
final static int width = 800;
final static int height = 600;
BufferedImage img;
Base() {
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
JFrame frame = new JFrame();
frame.addMouseMotionListener(this);
frame.add(this);
frame.setSize(width, height);
frame.setEnabled(true);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
Graphics g = img.getGraphics();
g.drawRect(1, 1, width - 2, height - 2);
g.dispose();
repaint();
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, null);
}
}
See comments in the code.
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
public class Base extends JPanel implements MouseMotionListener {
public static void main(String[] args) {
new Base();
}
final static int width = 400;
final static int height = 300;
BufferedImage img;
Base() {
img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB_PRE);
// do in preference to setting the frame size..
setPreferredSize(new Dimension(width, height));
JFrame frame = new JFrame();
this.addMouseMotionListener(this); // INSTEAD OF THE FRAME
frame.add(this);
//frame.setSize(width, height); DO INSTEAD...
frame.pack();
//frame.setEnabled(true); REDUNDANT
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // good call!
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
Graphics g = img.getGraphics();
g.setColor(Color.RED); // SET A COLOR
g.drawRect(1, 1, width - 2, height - 2);
// DO SOMETHING UGLY
g.setColor(Color.blue);
Point p = e.getPoint();
g.fillOval(p.x,p.y,5,5);
g.dispose();
repaint();
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, null);
}
}
Use a local BufferedImage on which you want to draw. Add a MouseMotionListener and implement the mouseDragged(MouseMotionEvent evt) method. In that method draw onto the BufferedImage by doing something like this:
// Assume img is your BufferedImage
Graphics g = img.getGraphics();
g.drawRect(evt.getX()-1, evt.getY()-1, 3, 3);
g.dispose();
// repaint your swing component
repaint();
And in your overrided paintComponent(Graphics g) method, draw like this:
g.drawImage(img, 0, 0, null);
Initialize your BufferedImage like this:
img = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
// Assuming `this` is your swing component