I making a Java Applet that save on an image what user paint in a JPanel. When i save on the output image i have only the background of the JPanel, lines has drawed by user disappear. Any tips to fix it? In this code line has drawed by the program, but the bug remains.
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
public class MarkPen extends Applet implements ActionListener, AdjustmentListener, MouseListener, MouseMotionListener {
private int x = 0;
private int y = 0;
private int prevx = 0;
private int prevy = 0;
private JPanel drawPanel = new JPanel();
private JButton saveButton = new JButton("SaveImage");
public void init()
{
setLayout(new BorderLayout());
drawPanel.setBackground(Color.red);
drawPanel.addMouseMotionListener(this);
drawPanel.addMouseListener(this);
drawPanel.add(new Comp());
drawPanel.setDoubleBuffered(true);
add(drawPanel, "Center");
saveButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
BufferedImage image = new BufferedImage(drawPanel.getWidth(), drawPanel.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = image.createGraphics();
drawPanel.paint(graphics2D);
try{
ImageIO.write(image,"jpeg", new File("C:/.../Example.jpeg"));
}
catch(Exception ex){
ex.printStackTrace();
}
}
});
add(saveButton, "South");
}
public void setGraphicalDefaults(MouseEvent e){}
public class Comp extends JComponent{
public void paintComponent(Graphics g) {
g = drawPanel.getGraphics();
g.setColor(Color.black);
g.drawLine(0,0,100,100);
}
}
public void mouseDragged(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void actionPerformed(ActionEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseMoved(MouseEvent e){}
public void mouseClicked(MouseEvent e){}
public void adjustmentValueChanged(AdjustmentEvent arg0){}
}
Thanks to yours help i solved it, i post the working code below.
WORKING CODE:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JApplet;
import javax.swing.SwingUtilities;
public class MarkPen extends JApplet {
private static final long serialVersionUID = 1L;
public static class DrawPanel extends JPanel {
private static final long serialVersionUID = 1L;
private List<Point> points = new ArrayList<Point>();
public DrawPanel() {
setBackground(Color.WHITE);
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
points.add(e.getPoint());
repaint();
}
});
addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent e){
Point p = null;
points.add(p);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
protected void paintComponent(java.awt.Graphics g) {
super.paintComponent(g);
Point p1 = null;
Point p2 = null;
g.setColor(Color.black);
for (Point p : points) {
p2 = p1;
p1 = p;
if (p1 != null && p2 != null) {
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
}
}
protected void initUI() {
setLayout(new BorderLayout());
JButton saveButton = new JButton("SaveImage");
JButton clearButton = new JButton("Clear");
final DrawPanel drawPanel = new DrawPanel();
JPanel buttonsPanel = new JPanel();
buttonsPanel.setLayout(new BorderLayout());
setSize(1000, 305);
add(drawPanel, "Center");
saveButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
BufferedImage image = new BufferedImage(drawPanel.getWidth(), drawPanel.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = image.createGraphics();
drawPanel.paint(graphics2D);
try{
ImageIO.write(image,"png", new File("C:/.../Desktop/Example.png"));
}
catch(Exception ex){
ex.printStackTrace();
}
}
});
clearButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
drawPanel.points.clear();
repaint();
}
});
buttonsPanel.add(clearButton, BorderLayout.WEST);
buttonsPanel.add(saveButton, BorderLayout.EAST);
add(buttonsPanel, BorderLayout.SOUTH);
validate();
}
#Override
public void init() {
super.init();
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
initUI();
}
});
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
your issue is by usage of drawPanel.getGraphics();,
this methods can creates temparary object for Save JPanel into Image, not for displaying an Image in JPanel
override getPreferredSize in public class Comp extends JComponent{
drawImage inside paintComponent
use super.paintComponent in the case that you want to replace current painting
for example
class Comp extends JComponent {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bi, 0, 0, this);
}
}
it's first time i use BufferedImage and i have problem to understand how it works
See Custom Painting Approaches. The DrawOnImage example is the one that uses a BufferedImage, although it doesn't hurt to understand the other example as well.
Related
I was at first looking for a library to make a "mousewritten" or "handwritten" signature for java. I did not found any so I'm just trying to let the user draw in a canvas on a JPanel and then he can choose to save it, repaint it or cancel the signature. The problem I have is when I'm trying to save the drawed stuff in the canvas I get an empty .jpeg
My code so far:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.colorchooser.*;
import javax.swing.event.*;
import java.awt.geom.Line2D;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
public class AES_Encryption extends JFrame implements ActionListener{
public BufferedImage image = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
//JPanel canvas = new JPanel();
JPanel buttonPanel = new JPanel();
Point lastPos = null;
Point startPos = null;
Point finishPos = null;
Graphics g;
JButton save = new JButton("Save");
JButton cancel = new JButton("Cancel");
JButton clear = new JButton("Clear");
JPanel canvas = new JPanel();
int changer = 1;
String path="";
public AES_Encryption () {
setLocation(100,100);
setSize(600,500);
setTitle("ENCODE SECTION");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canvas.setBackground(Color.WHITE);
clear.addActionListener(this);
clear.setActionCommand("clear");
save.addActionListener(this);
save.setActionCommand("Save");
cancel.addActionListener(this);
cancel.setActionCommand("Cancel");
//add buttons here
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
buttonPanel.add(Box.createHorizontalGlue());
buttonPanel.add(save);
buttonPanel.add(Box.createRigidArea(new Dimension(10, 0)));
buttonPanel.add(clear);
buttonPanel.add(Box.createRigidArea(new Dimension(10, 0)));
buttonPanel.add(cancel);
//set the look
getContentPane().add(canvas, BorderLayout.CENTER);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
setVisible(true);
g = canvas.getGraphics();
g.setColor(Color.BLACK);
canvas.addMouseMotionListener(new MouseMotionListener () {
public void mouseDragged (MouseEvent m) {
Point p = m.getPoint() ;
if (changer==1){
g.drawLine(lastPos.x, lastPos.y, p.x, p.y) ;
}
lastPos = p ;
}
public void mouseMoved (MouseEvent m) {}
});
canvas.addMouseListener(new MouseListener () {
public void mouseClicked(MouseEvent e) {startPos = e.getPoint();}
public void mousePressed(MouseEvent e) {lastPos = e.getPoint();}
public void mouseReleased(MouseEvent e) {
lastPos = null;
finishPos = e.getPoint();
startPos = null;}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
});
}
public void actionPerformed(ActionEvent e) {
if("clear".equals(e.getActionCommand())) {
repaint();
}
if("Save".equals(e.getActionCommand())) {
captureCanvasImage myCanvas = new captureCanvasImage();
myCanvas.capture();
}
if("Cancel".equals(e.getActionCommand())) {
dispose();
}}
class captureCanvasImage {
public void capture(){
BufferedImage imagebuf=null;
try {
imagebuf = new Robot().createScreenCapture(canvas.bounds());
} catch (AWTException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Graphics2D graphics2D = imagebuf.createGraphics();
canvas.paint(graphics2D);
try {
ImageIO.write(imagebuf,"jpeg", new File("save1.jpeg"));
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("error");
}
}
}
/*
#Override
public void invalidate() {
super.invalidate();
this.paint(this.getGraphics());
}
*/
public static void main (String [] args) {
AES_Encryption p = new AES_Encryption();
p.setVisible(true);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
p.setLocation(dim.width/2-p.getSize().width/2, dim.height/2-p.getSize().height/2);
}
}
When you create the coordinates of the line, save them in a list.
List<Point> points = new ArrayList<>(); // instance field.
canvas.addMouseMotionListener(new MouseMotionListener () {
public void mouseDragged (MouseEvent m) {
Point p = m.getPoint() ;
if (changer==1){
g.drawLine(lastPos.x, lastPos.y, p.x, p.y) ;
points.add(lastPos);// add it here.
}
lastPos = p ;
}
public void mouseMoved (MouseEvent m) {}
});
This was an example. You need to determine where to place the points.add() code. Check out the painting examples here
EDITED:
Here is an example of how to draw in a window. Do not be using graphics context outside of a painting environment like paint or paintComponent (exceptions to this are buffered images,etc which do not paint within the EDT).
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ExampleDrawDemo extends JPanel {
int WIDTH = 600;
int HEIGHT = 500;
JFrame frame = new JFrame();
List<Line> lines;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new ExampleDrawDemo().start());
}
public void start() {
Random r = new Random();
Color[] color = {
Color.RED, Color.BLUE, Color.GREEN, Color.MAGENTA, Color.ORANGE,
Color.CYAN
};
// generate some lines.
lines = IntStream.range(0, 100).mapToObj(
i -> new Line(r, color[r.nextInt(color.length)])).collect(
Collectors.toList());
setPreferredSize(new Dimension(600, 500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// smooth lines
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// line thickness
g2d.setStroke(new BasicStroke(2));
for (Line line : lines) {
g2d.setColor(line.color);
g2d.drawLine(line.start.x, line.start.y, line.end.x, line.end.y);
}
g2d.dispose();
}
class Line {
Point start;
Point end;
Color color;
public Line(Random r, Color color) {
this.color = color;
start = new Point(r.nextInt(WIDTH), r.nextInt(HEIGHT));
end = new Point(r.nextInt(WIDTH), r.nextInt(HEIGHT));
}
}
}
The intention of my code is to create a rectangle when the button is clicked. The button works fine but the rectangle itself is not showing up on the screen, and there are no errors. Thank you for helping btw.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tester {
static JButton button;
static JFrame frame;
static JPanel panel;
static Rectangle rec;
static void init(){
button = new JButton();
frame = new JFrame();
panel = new JPanel();
rec = new Rectangle(30,30,30,30);
button.setVisible(true);
panel.add(button);
frame.add(panel);
frame.setVisible(true);
panel.setVisible(true);
frame.setSize(200, 200);
button.setBackground(Color.GREEN);
button.setBounds(30, 30, 20, 20);
}
public static void main(String[] args) {
init();
ActionListener listener = new RectangleMover();
button.addActionListener(listener);
}
static class RectangleMover implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
RectanglePainter r = new RectanglePainter();
r.add(rec);
}
}
static class RectanglePainter extends JPanel{
void add(Rectangle r){
rec = r;
repaint();
}
protected void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
Random r = new Random();
int i =r.nextInt(2);
if (i==1)
g2.setColor(Color.BLUE);
else
g2.setColor(Color.RED);
g2.fill(rec);
g2.draw(rec);
}
}
}
Your generally approach is slightly skewed, rather than using another JComponent to "act" as the shape, you should be using it to paint all the shapes through it's paintComponent method
From my "red rectangle" period...
import java.awt.BorderLayout;
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.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Tester {
public static void main(String[] args) {
new Tester();
}
public Tester() {
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 JPanel panel;
private JButton button;
private JLabel label;
private ShapePane shapePane;
public TestPane() {
setLayout(new BorderLayout());
button = new JButton("Rectangle");
panel = new JPanel();
label = new JLabel();
button.setVisible(true);
panel.add(button);
panel.add(label);
shapePane = new ShapePane();
add(shapePane);
add(panel, BorderLayout.SOUTH);
class ClickListener implements ActionListener {
private int X = 20;
private int Y = 20;
#Override
public void actionPerformed(ActionEvent arg0) {
int width = shapePane.getWidth();
int height = shapePane.getHeight();
int x = (int)(Math.random() * (width - 20)) + 10;
int y = (int)(Math.random() * (height - 20)) + 10;
int w = (int)(Math.random() * (width - x));
int h = (int)(Math.random() * (height - y));
shapePane.add(new Rectangle(x, y, w, h));
}
}
ActionListener listener = new ClickListener();
button.addActionListener(listener);
}
}
public class ShapePane extends JPanel {
private List<Shape> shapes;
public ShapePane() {
shapes = new ArrayList<>(25);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void add(Rectangle rectangle) {
shapes.add(rectangle);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
}
}
As to answer your basic question, you could have tried calling revalidate and repaint, but because of the BorderLayout I doubt it would have worked as you would have basically been trying to replace the panel with your ShapeChanger component, and there are better ways to do that
I need to create a program that allows the user to select a color from a list of checkboxes, red and blue, and then a shape from a
list of radio buttons, square or circle. When the “Draw” button is pressed the selected
shape and color are drawn. If both red and blue are chosen, the shape is drawn in purple.
should look like the following picture:
This is about as far i've gotten, stumped as to how to create the circle and print it when that option is chosen. Also how do I reorganize the labels and buttons?
any help is appreciated
import java.awt.GridBagLayout;
import java.io.PrintWriter;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Shapes
{
public static JFrame window = new JFrame("Shapes");
public static JPanel panel = new JPanel(new GridBagLayout());
public static void main(String[] args)
{
window.setBounds(0, 0,300, 300);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.add(panel);
MApp m = new MApp();
m.setBounds(100,100,100,100);
window.add(m);
Draw d = new Draw(panel) ;
d.setBounds(0, 0, window.getWidth(), 90);
window.add(d);
window.setVisible(true);
}
}
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.JPanel;
public class MApp extends JPanel implements MouseListener
{
private boolean clicked;
private Rectangle r;
public MApp()
{
clicked = false;
r = new Rectangle(15, 15, 50, 50);
addMouseListener(this);
}
public void paintComponent(Graphics g)
{
if(clicked)
{
g.setColor(Color.BLUE);
}
else
{
g.setColor(Color.RED);
}
g.fillRect((int)r.getX(), (int)r.getY(),
(int)r.getWidth(), (int)r.getHeight());
}
public void mouseClicked (MouseEvent e)
{
Point p = new Point(e.getX(),e.getY());
if(r.contains(p))
{
clicked = !clicked;
}
repaint();
}
public void Circle()
{
g.fillOval(0, 0, s, s);
}
public void mousePressed (MouseEvent evnt) {}
public void mouseReleased (MouseEvent evnt) {}
public void mouseEntered (MouseEvent evnt) {}
public void mouseExited (MouseEvent evnt) {}
}
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
public class Draw extends JPanel implements ActionListener
{
JTextField tfInfo;
JLabel lblColor, lblShapes;
JCheckBox cbRed, cbBlue;
ButtonGroup shapes;
JRadioButton rbCircle, rbSquare;
JButton btnSubmit;
public Draw(JPanel panel)
{
GridBagConstraints c = new GridBagConstraints();
tfInfo = new JTextField("Color", 15);
tfInfo = new JTextField("Shapes", 50);
lblColor = new JLabel("Colors:");
cbRed = new JCheckBox("Red");
cbBlue = new JCheckBox("Blue");
lblShapes = new JLabel("Shapes:");
shapes = new ButtonGroup();
rbCircle = new JRadioButton("Circle");
rbSquare = new JRadioButton("Square");
btnSubmit = new JButton("Draw");
btnSubmit.addActionListener(this);
this.setBackground(Color.WHITE);
add(lblColor);
add(cbRed);
add(cbBlue);
add(lblShapes);
add(rbCircle);
add(rbSquare);
add(btnSubmit);
shapes.add(rbCircle);
shapes.add(rbSquare);
}
public void actionPerformed(ActionEvent a)
{
if(a.getSource() == btnSubmit)
{
if(cbRed.isSelected()&&cbBlue.isSelected())
{
if(rbCircle.isSelected())
{
}
else if(rbSquare.isSelected())
{
}
}
else if(cbRed.isSelected())
{
if(rbCircle.isSelected())
{
}
else if(rbSquare.isSelected())
{
}
}
else if(cbBlue.isSelected())
{
if(rbCircle.isSelected())
{
}
}
else if(rbSquare.isSelected())
{
}
}
repaint();
}
}
Start by separating your "management" code from you "painting" code
You should have a single class that only handles the painting of the shape, nothing else, it just does what it's told.
You should then have a second class which takes input from the user and when they press the Draw button, it tells the "paint" class what it should be paint, for example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawStuff extends JFrame {
public static void main(String[] args) {
new DrawStuff();
}
public DrawStuff() {
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 ControlPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ControlPane extends JPanel {
private JRadioButton circle;
private JRadioButton square;
private DrawPane drawPane;
public ControlPane() {
setLayout(new GridBagLayout());
ButtonGroup bg = new ButtonGroup();
circle = new JRadioButton("Circle");
square = new JRadioButton("Square");
bg.add(circle);
bg.add(square);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
JPanel shape = new JPanel();
shape.add(circle);
shape.add(square);
add(shape, gbc);
JButton draw = new JButton("Draw");
draw.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (circle.isSelected()) {
drawPane.setDrawableShape(DrawableShape.CIRCLE);
} else if (square.isSelected()) {
drawPane.setDrawableShape(DrawableShape.SQUARE);
}
}
});
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(draw, gbc);
drawPane = new DrawPane();
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = gbc.BOTH;
add(drawPane, gbc);
}
}
public enum DrawableShape {
CIRCLE,
SQUARE
}
public class DrawPane extends JPanel {
private DrawableShape drawableShape;
public DrawPane() {
}
public void setDrawableShape(DrawableShape drawableShape) {
this.drawableShape = drawableShape;
repaint();
}
public DrawableShape getDrawableShape() {
return drawableShape;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
DrawableShape shape = getDrawableShape();
if (shape != null) {
int width = getWidth() - 20;
int height = getHeight() - 20;
int size = Math.min(width, height);
int x = (getWidth() - size) / 2;
int y = (getHeight() - size) / 2;
if (shape == DrawableShape.CIRCLE) {
g2d.fillOval(x, y, size, size);
} else if (shape == DrawableShape.SQUARE) {
g2d.fillRect(x, y, size, size);
}
}
g2d.dispose();
}
}
}
I'll leave you to add in the color management.
Have a closer look at:
How to Use Buttons, Check Boxes, and Radio Buttons
How to Write an Action Listeners
Painting in AWT and Swing
Performing Custom Painting
2D Graphics
for more details
I'm not sure why when I press w my rectangle doesn't adjust accordingly. Do I have my focus set up right, or do I need to request it from a separate class? Should I be doing this in my drawingComponent class or in my "core" class?
package scratch;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.*;
public class drawingComponent extends JComponent implements KeyListener {
Rectangle hello = new Rectangle(300, 100, 50, 50);
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setColor(new Color(255,25,0));
g2.setFont(new Font("monospace", Font.BOLD+Font.ITALIC, 30));
g2.drawString("nothing yet",300,320);
g2.fill(hello);
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W){
hello.setLocation(hello.x-50, hello.y);
repaint();
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
I have solved the problem by adding the following to my drawingComponent class.
setFocusable(true);
requestFocus();
addKeyListener(this);
You want to use Key Bindings, not a KeyListener for several reasons, but one being that you don't have to worry so much about focus with Key Bindings. Also, you'll want to in the future post a minimal example program that we can test, run and modify, something like this:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class DrawingComponent extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 600;
private static final Color RECT_COLOR = new Color(255,25,0);
private Rectangle rect = new Rectangle(300, 100, 50, 50);
public DrawingComponent() {
setUpKeyBindings();
}
private void setUpKeyBindings() {
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
KeyStroke wStroke = KeyStroke.getKeyStroke(KeyEvent.VK_W, 0);
inputMap.put(wStroke, wStroke.toString());
actionMap.put(wStroke.toString(), new WAction());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(RECT_COLOR);
g2.fill(rect);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class WAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
rect.setLocation(rect.x-50, rect.y);
repaint();
}
}
private static void createAndShowGui() {
DrawingComponent mainPanel = new DrawingComponent();
JFrame frame = new JFrame("DrawingComponent");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Also, call the super's paintComponent method in your override, else your JPanel won't erase the old images.
I'm trying to print a string that the user can enter to a textbox, to a JFrame.
My problem is that the paintComponent method is never being called. Why?
PNGCreatorWindow Class:
public class PNGCreatorWindow {
private JFrame frame;
private JTextField txtText;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
PNGCreatorWindow window = new PNGCreatorWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public PNGCreatorWindow() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 678, 502);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
txtText = new JTextField();
txtText.setBounds(121, 13, 216, 22);
frame.getContentPane().add(txtText);
txtText.setColumns(10);
JButton btnGenerate = new JButton("Generate");
btnGenerate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
btnGenerate.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
GeneratePNGImage();
}
});
btnGenerate.setBounds(436, 6, 183, 36);
frame.getContentPane().add(btnGenerate);
JPanel panel = new JPanel();
panel.setBounds(107, 151, 338, 160);
frame.getContentPane().add(panel);
}
protected void GeneratePNGImage() {
PNGImage img = new PNGImage(txtText.getText());
frame.getContentPane().add(img);
frame.getContentPane().validate();
frame.getContentPane().setVisible(true);
frame.repaint();
}
}
PNGImage Class:
public class PNGImage extends JComponent {
private String text;
public PNGImage(String text){
this.text = text;
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.red);
g2.drawString(this.text, 100,100);
g2.fillRect(50, 50, 1000, 1000);
}
}
I made a few changes to your code to get it to draw the text on the JPanel.
I put the JTextField and the JButton inside of a control panel (JPanel) and set a layout manager (FlowLayout) for the control panel. You should always use a layout manager for laying out Swing components.
I defined the image panel (PNGImage) as part of the laying out of the Swing components. First, you lay all of the Swing components out. Then, you change their state.
I removed the mouse adapter and just used an action listener on the JButton. The action listener works with the mouse.
In the PNGImage class, I added a setter, so I could pass the text to the class later, after the user typed the text in the JTextField.
I added a call to setPreferredSize so that I could set the size of the drawing canvas. I removed all other sizing, and used the pack method of JFrame to make the JFrame the appropriate size to hold the Swing components.
I added a null test to paintComponent, so that the text would only be drawn when there was some text to draw.
Here's the code. I put all the code in one module to make it easier to paste.
package com.ggl.testing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class PNGCreatorWindow {
private JFrame frame;
private JTextField txtText;
private PNGImage imagePanel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
new PNGCreatorWindow();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public PNGCreatorWindow() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new FlowLayout());
txtText = new JTextField(10);
controlPanel.add(txtText);
JButton btnGenerate = new JButton("Generate");
btnGenerate.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
generatePNGImage();
}
});
controlPanel.add(btnGenerate);
imagePanel = new PNGImage();
frame.getContentPane().add(controlPanel, BorderLayout.NORTH);
frame.getContentPane().add(imagePanel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
protected void generatePNGImage() {
imagePanel.setText(txtText.getText());
imagePanel.repaint();
}
public class PNGImage extends JPanel {
private static final long serialVersionUID = 602718701626241645L;
private String text;
public PNGImage() {
setPreferredSize(new Dimension(400, 300));
}
public void setText(String text) {
this.text = text;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (this.text != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.drawString(this.text, 100, 100);
}
}
}
}
Edited to add an action listener that saves the contents of a JPanel as a .png file:
package com.ggl.crossword.controller;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import com.ggl.crossword.view.CrosswordFrame;
public class CreateImageActionListener implements ActionListener {
private CrosswordFrame frame;
private JPanel panel;
public CreateImageActionListener(CrosswordFrame frame,
JPanel panel) {
this.frame = frame;
this.panel = panel;
}
#Override
public void actionPerformed(ActionEvent event) {
writeImage();
}
public void writeImage() {
FileFilter filter =
new FileNameExtensionFilter("PNG file", "png");
JFileChooser fc = new JFileChooser();
fc.setFileFilter(filter);
int returnValue = fc.showSaveDialog(frame.getFrame());
if (returnValue == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
if (!file.getAbsolutePath().endsWith(".png")) {
file = new File(file.getAbsolutePath() + ".png");
}
RenderedImage image = createImage(panel);
try {
ImageIO.write(image, "png", file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private BufferedImage createImage(JPanel panel) {
int w = panel.getWidth();
int h = panel.getHeight();
BufferedImage bi = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
panel.paint(g);
g.dispose();
return bi;
}
}