Draw line on the desktop with clickable around line - java

I want create a program that draw line on desktop with this property that user can click on desktop icons near the line.
I create sample. I create transparent frame and draw jWindow on this. in MouseReleased event dispose main frame then stay all jwindows that created. My code create many number of jwindow and this is very bad. For draw line 30cm program create over than 400 jwindow and this causes os be very heavy.
Can help me anybody?
(Excuse me for my ugly english)
package PKHMain;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JWindow;
public class FRMMain extends JFrame implements MouseListener, MouseMotionListener {
public FRMMain() {
this.setUndecorated(true);
this.setSize(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.setLayout(null);
this.setBackground(new Color(0, 0, 0, 0));
this.setVisible(true);
addMouseListener(this);
addMouseMotionListener(this);
}
public static void main(String[] args) {
new FRMMain();
}
#Override
public void mousePressed(MouseEvent event) {
}
#Override
public void paint(Graphics g) {
repaint();
}
#Override
public void mouseClicked(MouseEvent event) {
}
#Override
public void mouseEntered(MouseEvent event) {
}
#Override
public void mouseExited(MouseEvent event) {
}
#Override
public void mouseReleased(MouseEvent event) {
this.dispose();
}
#Override
public void mouseDragged(MouseEvent event) {
int x = event.getX();
int y = event.getY();
JWindow frame = new JWindow();
frame.setBackground(new Color(0, 0, 0, 0));
frame.setContentPane(new ShapedPane(x, y));
frame.pack();
frame.setLocation(x, y);
frame.setAlwaysOnTop(true);
frame.setVisible(true);
}
public void mouseMoved(MouseEvent event) {
}
public class ShapedPane extends JPanel {
public int x1;
public int y1;
public ShapedPane(int x, int y) {
setOpaque(false);
setLayout(new GridBagLayout());
x1 = x;
y1 = y;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(5, 5);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hints);
g2.setColor(Color.red);
g2.fill(new Ellipse2D.Double(0, 0, getWidth(), getHeight()));
g2.dispose();
}
}
}

You are touching system specific behavior with your program, e.g. on my machine the program will not receive any mouse event at all as the background color has an alpha value of zero. Setting it to at least one makes it receiving clicks and drags. So this is a way to control the desired click-through behavior but it might be the case that it doesn’t work for you.
Here is the program as it work on my machine (Java 7 and Windows 7):
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
public class FRMMain extends JFrame {
private final List<Shape> list=new ArrayList<>();
private boolean paintPhase=true;
public FRMMain() {
this.setUndecorated(true);
final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.setSize(screenSize.width, screenSize.height);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.setBackground(new Color(0, 0, 0, 1));
this.setOpacity(1f);
this.setAlwaysOnTop(true);
this.setVisible(true);
enableEvents(AWTEvent.MOUSE_EVENT_MASK|AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
#Override
protected void processMouseEvent(MouseEvent e) {
if(paintPhase && e.getID()==MouseEvent.MOUSE_RELEASED) {
paintPhase = false;
// on my machine the following line is enough to enable click-through
setBackground(new Color(0, 0, 0, 0));
// but if this doesn’t work, the following should do:
Area area=new Area();
BasicStroke b=new BasicStroke(2f);
for(Shape s:list) area.add(new Area(b.createStrokedShape(s)));
setShape(area);
}
super.processMouseEvent(e);
}
#Override
protected void processMouseMotionEvent(MouseEvent event)
{
if(paintPhase && event.getID()==MouseEvent.MOUSE_DRAGGED) {
int x = event.getX();
int y = event.getY();
list.add(new Ellipse2D.Float(x, y, 8, 8));
repaint();
}
super.processMouseMotionEvent(event);
}
#Override
public boolean contains(int x, int y) {
return paintPhase;
}
public static void main(String[] args) {
new FRMMain();
}
#Override
public void paint(Graphics g) {
Graphics2D gfx=(Graphics2D)g;
gfx.setColor(Color.RED);
for(Shape s:list) gfx.draw(s);
}
}

Related

Saving a JPanel as an Image (object) and drawing it back onto a JPanel

I've had a look around and tried using other queries, but I just can't seem to get this to work.
I am trying to retain an image from a JPanel drawn via the g.draw/fill methods.
I've attempted to save the drawing in a buffered image, but when I display it in a messageDialog all I get is the background and none of the drawings
These two methods are the important code (from the DrawingPanel class):
public void loadDrawing(BufferedImage bi) {
//opens a message dialog and displays the image parameter
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
System.out.println("w:" + bi.getWidth() + " h:" + bi.getHeight());
}
public BufferedImage getScreenShot() {
BufferedImage image = new BufferedImage(this.getWidth(),
this.getHeight(), BufferedImage.TYPE_INT_RGB);
// call the Panels's paint method, using
// the Graphics object of the image.
this.paint(image.getGraphics());
return image;
}
They get called here:
#Override
public void actionPerformed(ActionEvent ae) {
BufferedImage bi = dp.getScreenShot();
dp.loadDrawing(bi);
}
Here is the whole program, it should run.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class TestClass extends JFrame implements ActionListener {
DrawingPanel dp;
public TestClass() {
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel top = new JPanel();
JButton load = new JButton("Load Image");
load.addActionListener(this);
top.add(load);
dp = new DrawingPanel();
dp.setBackground(Color.CYAN);
add(top, BorderLayout.NORTH);
add(dp, BorderLayout.CENTER);
setVisible(true);
}
public static void main(String[] args) {
new TestClass();
}
#Override
public void actionPerformed(ActionEvent ae) {
BufferedImage bi = dp.getScreenShot();
dp.loadDrawing(bi);
}
private class DrawingPanel extends JPanel implements
MouseListener, MouseMotionListener {
private int xPos, yPos;//mouse positions
private DrawingPanel() {
addMouseListener(this);
addMouseMotionListener(this);
}
#Override
public void mousePressed(MouseEvent me) {
xPos = me.getX();
yPos = me.getY();
}
#Override
public void mouseDragged(MouseEvent me) {
int x = me.getX(), y = me.getY();
Graphics g = getGraphics();
g.setColor(Color.BLACK);
g.drawOval(xPos, yPos, 30, 30);
xPos = x;
yPos = y;
}
public void loadDrawing(BufferedImage bi) {
//opens a message dialog and displays the image parameter
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
System.out.println("w:" + bi.getWidth() + " h:" + bi.getHeight());
}
public BufferedImage getScreenShot() {
BufferedImage image = new BufferedImage(this.getWidth(),
this.getHeight(), BufferedImage.TYPE_INT_RGB);
// call the Panels's paint method, using
// the Graphics object of the image.
this.paint(image.getGraphics());
return image;
}
//unused abstract method
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
#Override
public void mouseMoved(MouseEvent me) {
}
}
}
I need to be able to store the graphics from the panel and retrieve it.
Help would be heavily appreciated.
Every attempt to draw something into the Graphics object that was obtained from a Component by calling getGraphics will fail sooner or later. This Graphics object merely serves as a "path" to the actual screen (that is only valid while the component is actually painted on the screen). It is not a "buffer", and it does not "store" anything that was drawn.
If you want to create a simple painting program, you should draw to a BufferedImage. And when the DrawingPanel is to be painted, you only paint this BufferedImage. The additional advantage here is that when you want to make a screenshot, you basically just have to return a copy of this BufferedImage.
I sketeched the basic approach in your DrawingPanel class, with some in-lined comments. It could be cleaned up and beautified, and there are some aspects to consider (e.g. what should happen when the DrawingPanel is resized?), but it shows how it should work in general:
private class DrawingPanel extends JPanel implements
MouseListener, MouseMotionListener {
// The image that will store what was drawn. In the
// mouseDragged method, the painting operations will
// go directly to this image. When this panel is
// painted, then ONLY this image will be painted.
private BufferedImage bufferedImage;
private int xPos, yPos;//mouse positions
private DrawingPanel() {
addMouseListener(this);
addMouseMotionListener(this);
}
// Make sure that the "bufferedImage" is non-null
// and has the same size as this panel
private void validateImage()
{
if (bufferedImage == null)
{
bufferedImage = new BufferedImage(
getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
g.setColor(getBackground());
g.fillRect(0,0,getWidth(),getHeight());
g.dispose();
}
if (bufferedImage.getWidth() != getWidth() ||
bufferedImage.getHeight() != getHeight())
{
BufferedImage newBufferedImage = new BufferedImage(
getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics g = newBufferedImage.getGraphics();
g.setColor(getBackground());
g.fillRect(0,0,getWidth(),getHeight());
g.drawImage(bufferedImage, 0,0,null);
g.dispose();
bufferedImage = newBufferedImage;
}
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
validateImage();
// Paint the bufferedImage which stores
// what was drawn until now
g.drawImage(bufferedImage, 0, 0, null);
}
#Override
public void mousePressed(MouseEvent me) {
xPos = me.getX();
yPos = me.getY();
}
#Override
public void mouseDragged(MouseEvent me) {
int x = me.getX(), y = me.getY();
validateImage();
// Paint directly into the bufferedImage here
Graphics g = bufferedImage.getGraphics();
g.setColor(Color.BLACK);
g.drawOval(xPos, yPos, 30, 30);
repaint();
xPos = x;
yPos = y;
}
public void loadDrawing(BufferedImage bi) {
//opens a message dialog and displays the image parameter
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
System.out.println("w:" + bi.getWidth() + " h:" + bi.getHeight());
}
public BufferedImage getScreenShot() {
// This basically returns a "copy" of the
// bufferedImage that stores what was drawn
BufferedImage image = new BufferedImage(
getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.drawImage(bufferedImage, 0, 0, null);
g.dispose();
return image;
}
//unused abstract method
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
#Override
public void mouseMoved(MouseEvent me) {
}
}
Your getting your Graphics object by calling getGraphics() on a component, and images drawn with this will not persist. Why not instead draw to a BufferedImage with its Graphics object, and then simply save that BufferedImage. This would simplify things greatly, and your program would work.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class TestClass2 extends JPanel {
private DrawingPanel drawingPanel = new DrawingPanel();
public TestClass2() {
JPanel northPanel = new JPanel();
northPanel.add(new JButton(new GetImageAction("Get Image")));
northPanel.add(new JButton(new ClearImageAction("Clear Image")));
setLayout(new BorderLayout(5, 5));
add(drawingPanel, BorderLayout.CENTER);
add(northPanel, BorderLayout.NORTH);
}
private class GetImageAction extends AbstractAction {
public GetImageAction(String name) {
super(name);
putValue(MNEMONIC_KEY, KeyEvent.VK_G);
}
#Override
public void actionPerformed(ActionEvent evt) {
BufferedImage img = drawingPanel.getMainImage();
ImageIcon icon = new ImageIcon(img);
JOptionPane.showMessageDialog(TestClass2.this, icon);
}
}
private class ClearImageAction extends AbstractAction {
public ClearImageAction(String name) {
super(name);
putValue(MNEMONIC_KEY, KeyEvent.VK_C);
}
#Override
public void actionPerformed(ActionEvent evt) {
drawingPanel.clearImage();
drawingPanel.repaint();
}
}
private static void createAndShowGui() {
TestClass2 mainPanel = new TestClass2();
JFrame frame = new JFrame("TestClass2");
frame.setDefaultCloseOperation(JFrame.EXIT_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();
}
});
}
}
class DrawingPanel extends JPanel {
public static final int BI_WIDTH = 400;
public static final int BI_HEIGHT = BI_WIDTH;
private static final Color BACKGROUND = Color.CYAN;
public static final Color DRAW_COLOR = Color.black;
public static final int OVAL_WIDTH = 30;
private BufferedImage mainImage;
public DrawingPanel() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
clearImage();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (mainImage != null) {
g.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(BI_WIDTH, BI_HEIGHT);
}
public BufferedImage getMainImage() {
return mainImage;
}
public void clearImage() {
mainImage = new BufferedImage(BI_WIDTH, BI_HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g = mainImage.getGraphics();
g.setColor(BACKGROUND);
g.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
g.dispose();
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent mEvt) {
draw(mEvt);
}
#Override
public void mouseDragged(MouseEvent mEvt) {
draw(mEvt);
}
private void draw(MouseEvent mEvt) {
Graphics2D g2 = mainImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(DRAW_COLOR);
g2.drawOval(mEvt.getX() - OVAL_WIDTH / 2, mEvt.getY() - OVAL_WIDTH / 2, OVAL_WIDTH, OVAL_WIDTH);
g2.dispose();
repaint();
}
}
}

Drag JComponent around in absolute position Container

I have set up a quick demo for dragging JComponents around, but the mouse coordinates from e.getPoint() always start at (0, 0) at the beginning of the mouse drag.
App.java
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class App extends JFrame {
private static final long serialVersionUID = 7935470621073141683L;
private static final String TITLE = "Test";
private static AbsolutePanel panel;
private static App frame;
public App() {
this(TITLE);
}
public App(String title) {
super(title);
setSize(800, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
panel = new AbsolutePanel();
frame = new App("Component Test");
frame.setContentPane(panel);
frame.setVisible(true);
doStuff();
}
});
}
public static void doStuff() {
JNode[] nodes = {
new JNode("A", 50, 50, 20),
new JNode("B", 100, 50, 20),
new JNode("C", 50, 100, 20),
new JNode("D", 100, 100, 20),
new JNode("E", 50, 150, 20),
new JNode("F", 100, 150, 20)
};
for (JNode node : nodes) {
panel.addNode(node);
}
}
}
AbsolutePanel.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
public class AbsolutePanel extends JPanel {
private static final long serialVersionUID = -2783388377109130628L;
private List<JNode> nodes;
public AbsolutePanel() {
super(null);
nodes = new ArrayList<JNode>();
}
public List<JNode> getNodes() {
return nodes;
}
public void addNode(JNode node) {
nodes.add(node);
add(node);
Insets insets = this.getInsets();
Dimension size = node.getPreferredSize();
node.setBounds(node.getX() + insets.left, node.getY() + insets.top,
size.width, size.height);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
for (JNode node : getNodes()) {
node.paint(g);
}
}
}
JNode.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
public class JNode extends Draggable {
private static final long serialVersionUID = 4342026645661510597L;
private String label;
public JNode(String label, int x, int y, int size) {
super(x, y, size);
this.label = label;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension size = this.getPreferredSize();
g.setColor(Color.YELLOW);
g.fillOval(getX(), getY(), size.width, size.height);
g.setColor(Color.BLUE);
g.drawOval(getX(), getY(), size.width, size.height);
g.drawString(label, getX() + size.width / 2 - 2, getY() + size.height / 2 + 4);
}
}
Draggable.java
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JComponent;
public class Draggable extends JComponent implements MouseListener, MouseMotionListener {
private static final long serialVersionUID = 8036176852541863898L;
private boolean dragging = false;
public Draggable(int x, int y, int size) {
super();
setPreferredSize(new Dimension(size, size));
setBounds(x, y, size, size);
addMouseListener(this);
addMouseMotionListener(this);
}
#Override
public void mouseDragged(MouseEvent e) {
if (dragging) {
int oldX = this.getX();
int oldY = this.getY();
int newX = e.getPoint().y;
int newY = e.getPoint().x;
System.out.printf("(%03d, %03d) -> (%03d, %03d)\n", oldX, oldY, newX, newY);
setLocation(e.getPoint());
repaint();
}
}
#Override
public void mouseMoved(MouseEvent e) { }
#Override
public void mouseClicked(MouseEvent e) { }
#Override
public void mousePressed(MouseEvent e) {
dragging = true;
}
#Override
public void mouseReleased(MouseEvent e) {
dragging = false;
}
#Override
public void mouseEntered(MouseEvent e) {
setCursor(new Cursor(Cursor.HAND_CURSOR));
}
#Override
public void mouseExited(MouseEvent e) {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
I use the Component Mover to drag components around.
Edit:
I am getting repainting issues.
That is because the fillOval/drawOval methods should actually use a width/height that is 1 less than the size of the component. If you look closely at your painting you will notice the the edge of the node on the right/bottom is not completely round. Using 1 less will cause the painting to occur within the bounds of your component.
g.setColor(Color.YELLOW);
g.fillOval(getX(), getY(), size.width-1, size.height-1);
g.setColor(Color.BLUE);
g.drawOval(getX(), getY(), size.width-1, size.height-1);
Having said that your code is actually more complicated than it needs to be. When I tested your code I got rid of the Draggable class since you no longer need that when you use the ComponentMover. So now your JNode can extend JComponent directly. Since it is a component, you can just let Swing do the painting itself so your AbsolutePanel does not need any custom painting. It just becomes a panel that holds Swing components. Since you are using a null layout you need to set the bounds of each JNode. Also the painting code in JNode will need to change since all the painting is now relative to (0, 0), not getX() and getY().

Multiple problems regarding Java paint program while painting

I have a Java paint program, and I've got two problems to do with it. Both problems are relatively simple, and just regard how the mouse input is handled and how the image uses colors. Here's a photo of the app:
So here's my first problem:
As you can see, by the look of the app, there's a spray of dots on the paint area. Each of those dots is a mouseclick. The program does not recognize when a user is holding down the mouse button, so you have to click individually.
This is obviously counterproductive, user-unfriendly and unacceptable. Now, how I fix this, I'm not sure. I've tried using a permanent while (true) loop, but that does not work. How do I make it so that instead of having to click every time, each time the mouse is held down it sprays out dots?
The second problem is the color of the dots. As you can see, at the bottom, there are color buttons. These function, but there is a problem: Whenever I change the color, all the dots currently on the screen change color. The color is run by a variable called currentColor which is run by the actionListeners controlled by all the color buttons on the bottom panel. How do I make sure that colors already placed on the screen are not affected anymore?
I believe that all the code that can be fixed for these two problems lies in my custom JPanel which is used for the program to paint on. I'll post the entire class below, and if you have any other questions, please let me know.
int xCord, yCord;
public class PaintPanel extends JPanel implements MouseListener {
// default serial whatever...
private static final long serialVersionUID = -6514297510194472060L;
public PaintPanel() {
addMouseListener(this);
}
ArrayList<Point> points = new ArrayList<Point>();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Point point : points) {
g.setColor(currentColor);
g.fillOval(point.x, point.y, 12, 12);
}
repaint();
}
#Override
public void mouseClicked(MouseEvent m) {
}
#Override
public void mouseEntered(MouseEvent m) {
}
#Override
public void mouseExited(MouseEvent m) {
}
#Override
public void mousePressed(MouseEvent m) {
if (paintPanel.contains(m.getPoint())) {
points.add(m.getPoint());
xCord = m.getX();
yCord = m.getY();
System.out.println("x: " + xCord + " y: " + yCord);
}
}
#Override
public void mouseReleased(MouseEvent m) {
}
}
Painting in Swing is destructive.
That is to say, when Swing requests that a repaint occur on a component, the component is expected to clear what ever was previously paint and update itself.
The problem with your color issue is that you only ever have a single color specified.
A possible solution would be to paint to backing buffer (like BufferedImage) instead of relying on paintComponent.
Instead of repainting all the dots each time paintComponent is called, you would simply paint the BufferedImage instead.
As to your issue with the mouse, you need to implement a MouseMotionListener, this will allow you to detect when the mouse is dragged across the surface, painting a trail of dots
Update with very BASIC example
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.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimplePaint04 {
public static void main(String[] args) {
new SimplePaint04();
}
public SimplePaint04() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private PaintPane paintPane;
public TestPane() {
setLayout(new BorderLayout());
add((paintPane = new PaintPane()));
add(new ColorsPane(paintPane), BorderLayout.SOUTH);
}
}
public class ColorsPane extends JPanel {
public ColorsPane(PaintPane paintPane) {
add(new JButton(new ColorAction(paintPane, "Red", Color.RED)));
add(new JButton(new ColorAction(paintPane, "Green", Color.GREEN)));
add(new JButton(new ColorAction(paintPane, "Blue", Color.BLUE)));
}
public class ColorAction extends AbstractAction {
private PaintPane paintPane;
private Color color;
private ColorAction(PaintPane paintPane, String name, Color color) {
putValue(NAME, name);
this.paintPane = paintPane;
this.color = color;
}
#Override
public void actionPerformed(ActionEvent e) {
paintPane.setForeground(color);
}
}
}
public class PaintPane extends JPanel {
private BufferedImage background;
public PaintPane() {
setBackground(Color.WHITE);
setForeground(Color.BLACK);
MouseAdapter handler = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
drawDot(e.getPoint());
}
#Override
public void mouseDragged(MouseEvent e) {
drawDot(e.getPoint());
}
};
addMouseListener(handler);
addMouseMotionListener(handler);
}
protected void drawDot(Point p) {
if (background == null) {
updateBuffer();;
}
if (background != null) {
Graphics2D g2d = background.createGraphics();
g2d.setColor(getForeground());
g2d.fillOval(p.x - 5, p.y - 5, 10, 10);
g2d.dispose();
}
repaint();
}
#Override
public void invalidate() {
super.invalidate();
updateBuffer();
}
protected void updateBuffer() {
if (getWidth() > 0 && getHeight() > 0) {
BufferedImage newBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = newBuffer.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, getWidth(), getHeight());
if (background != null) {
g2d.drawImage(background, 0, 0, this);
}
g2d.dispose();
background = newBuffer;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (background == null) {
updateBuffer();
}
g2d.drawImage(background, 0, 0, this);
g2d.dispose();
}
}
}

draw a circle by passing jpanel component as argument

I am really confused how to draw a circle on the jpanel by passing it as an argument..
public class test extends JPanel{
public test(JPanel jpanelcomponent) {
}
#Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
int width = getWidth()/2;
int height = getHeight()/2;
g.fillOval(5, 5, width, height);
}
}
I think a better design would have you passing the Graphics object obtained from overriding paintComponent(..) of a JPanel to the class which will draw to the graphics object
Here is an example I made:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final DrawingClass dc = new DrawingClass();
JPanel testPanel = new JPanel() {
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
dc.draw(g2d, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
frame.add(testPanel);
frame.pack();
frame.setVisible(true);
}
}
class DrawingClass {
public void draw(Graphics2D g2d, int w, int h) {
g2d.setColor(Color.BLACK);
g2d.fillOval(5, 5, w / 2, h / 2);
}
}
#David's answer is better, but you can try using the decorator pattern like they show here.

Changing JPanel Graphics g color drawing line

i have a program similar to paint. and that i am trying to implement a change pen color however when i change the color, everything currently drawn is changed to the color RED for example in my program,how can i make it such that it will not repaint everything currently drawn to the currently changed color?Below code will compile and run
Class for the JPanel drawing area
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
//refer to http://jkost.ergoway.gr/jnkjavaconnection/freedraw.html for the algorithm.
public class STDrawingArea extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
ArrayList<Rectangle> dPoint = new ArrayList<Rectangle>();
Point point = new Point(-1,-1);
private Color currentColor;
public STDrawingArea()
{
setBorder(BorderFactory.createLineBorder(Color.black));
setBackground(Color.WHITE);
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e)
{
dPoint.add(new Rectangle(point.x,point.y,e.getX(),e.getY()));
point.x = e.getX();
point.y = e.getY();
repaint();
}
});
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e)
{
System.out.println("mousePressed X: "+e.getX()+"mousePressed Y: "+e.getY());
dPoint.add(new Rectangle(e.getX(),e.getY(),-1,-1));
point.x = e.getX();
point.y = e.getY();
}
});
addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent e)
{
System.out.println("mouseReleased X: "+e.getX()+"mouseReleased Y: "+e.getY());
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(700,500);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(getCurrentColor());
for (int i=0; i < dPoint.size(); i++) {
Rectangle r = dPoint.get(i);
if (r.width != -1)
{
g.drawLine(r.x, r.y, r.width, r.height);
}
}
/* Draw current point.*/
g.drawLine(point.x, point.y, point.x, point.y);
}
//set current drawing color
public void changePenColor(Color color)
{
if (color == null)
setCurrentColor(Color.BLACK);
else
setCurrentColor(color);
}
//clear drawings method
public void clearDrawings()
{
if(!(dPoint==null))
{
dPoint.clear();
repaint();
}
}
private void setCurrentColor(Color currentColor) {
this.currentColor = currentColor;
}
private Color getCurrentColor() {
return currentColor;
}
}
Test main class.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class STTestMain extends JFrame {
STDrawingArea drawingArea = new STDrawingArea();
public STTestMain()
{
//JFrame settings
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Spelling Trainer");
setResizable(false);
setVisible(true);
//Panel of buttons
JPanel buttonContainer = new JPanel();
JButton btnPenColor = new JButton("Red Pen");
buttonContainer.add(btnPenColor);
//Drawing Area instantiation
//Adding things to JFrame
getContentPane().add(drawingArea);
getContentPane().add(buttonContainer,BorderLayout.PAGE_END);
pack();
//button listener
btnPenColor.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
drawingArea.changePenColor(Color.RED);
}
});
}
public static void main(String args[])
{
STTestMain test = new STTestMain();
}
}
One way:
Use your ArrayList to draw the current curve as it is being drawn, but
Use a BufferedImage to draw your completed curves
You would do this on mouseReleased and would draw the current curve to the BufferedImage using the current color.
You'll also need to re-initialize your ArrayList of points after drawing to the BufferedImage.
Don't forget to dispose of the BufferedImage's Graphics object after you're done using it.
Draw the BufferedImage in your paintComponent method after super.paintComponent but before drawing your current curve.
This way when you change the color of your drawing, only the current curve is effected.
EDIT
You've mentioned in a comment that you're not familiar with BufferedImage, and are looking for another way. I suppose you could create a class that holds an ArrayList of Points together with a Color, and then on each mouseReleased create an object of this class and add it to an ArrayList in your drawing panel. Then your paintComponent method could iterate through that ArrayList, drawing the list of Points with their associated color, but my gut tells me that you're an intelligent guy and that you'd pick up on how to use a BufferedImage in no time. I really think it's the best solution. And if you try it and it flops, show us your code, and we'll likely be able to help you.
EDIT 2
The BufferedImage constructor will need the image width, height and an image type -- something I'm not 100% familiar with. I usually use BufferedImage.TYPE_INT_RGB for general purpose drawing, and BufferedImage.TYPE_INT_ARGB for general purpose that needs an alpha too. Then you'll extract a Graphics object out of the BufferedImage, say getGraphics() if all you need is a Graphics object and not a Graphics2D object. Then when you initialize the BufferedImage in your constructor, fill it with a Color.white, just as you for your JPanel. Then dispose the Graphics object. Then each time you want to draw, you getGraphics, draw with it, just like you do in the paintComponent method, dispose of the Graphics when done, and finally draw the BufferedImage in the paintComponent via the drawImage method.
EDIT 3
Example program that doesn't do quite what you are trying to do but does illustrate use of a BufferedImage with drawing. This program changes the color each time a new path or curve is drawn.
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.*;
public class STTestSimple {
private static void createAndShowUI() {
STDrawPanel drawPanel = new STDrawPanel();
STMouseAdapter mAdapter = new STMouseAdapter(drawPanel);
drawPanel.addMouseListener(mAdapter);
drawPanel.addMouseMotionListener(mAdapter);
JFrame frame = new JFrame("Drawing");
frame.getContentPane().add(drawPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
#SuppressWarnings("serial")
class STDrawPanel extends JPanel {
private static final int ST_WIDTH = 700;
private static final int ST_HEIGHT = 500;
private static final Color BACKGROUND_COLOR = Color.white;
private static final float STROKE_WIDTH = 6f;
private static final Stroke STROKE = new BasicStroke(STROKE_WIDTH,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
private static final Color[] colors = {Color.black, Color.blue, Color.red,
Color.green, Color.orange, Color.MAGENTA};
private BufferedImage bImage = new BufferedImage(ST_WIDTH, ST_HEIGHT,
BufferedImage.TYPE_INT_RGB);
private Color color = Color.black;
private ArrayList<Point> points = new ArrayList<Point>();
private int colorIndex = 0;
public STDrawPanel() {
Graphics g = bImage.getGraphics();
g.setColor(BACKGROUND_COLOR);
g.fillRect(0, 0, ST_WIDTH, ST_HEIGHT);
g.dispose();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bImage, 0, 0, null);
Graphics2D g2 = (Graphics2D) g;
drawCurve(g2);
}
private void addCurveToBufferedImage() {
Graphics2D g2 = bImage.createGraphics();
drawCurve(g2);
g2.dispose();
}
private void drawCurve(Graphics2D g2) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(STROKE);
g2.setColor(color);
if (points != null && points.size() > 1) {
for (int i = 0; i < points.size() - 1; i++) {
int x1 = points.get(i).x;
int y1 = points.get(i).y;
int x2 = points.get(i + 1).x;
int y2 = points.get(i + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(ST_WIDTH, ST_HEIGHT);
}
public void curveStart(Point point) {
points.clear();
points.add(point);
}
public void curveEnd(Point point) {
points.add(point);
addCurveToBufferedImage();
points.clear();
repaint();
colorIndex++;
colorIndex %= colors.length;
setColor(colors[colorIndex]);
}
public void curveAdd(Point point) {
points.add(point);
repaint();
}
public void setColor(Color color) {
this.color = color;
}
}
class STMouseAdapter extends MouseAdapter {
private STDrawPanel drawPanel;
public STMouseAdapter(STDrawPanel drawPanel) {
this.drawPanel = drawPanel;
}
#Override
public void mousePressed(MouseEvent e) {
drawPanel.curveStart(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
drawPanel.curveEnd(e.getPoint());
}
#Override
public void mouseDragged(MouseEvent e) {
drawPanel.curveAdd(e.getPoint());
}
}
Custom Painting Approaches gives two ideas on how you might do this.
Thanks hovercraft, i've done it looking at your code and fiddling around lol.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class STDrawingArea extends JPanel {
/**
*
*/
private static final int DA_WIDTH = 700;
private static final int DA_HEIGHT = 500;
private static final Color DA_BGCOLOR = Color.WHITE;
private static final long serialVersionUID = 1L;
ArrayList<Point> points = new ArrayList<Point>();
private Color currentColor;
BufferedImage bImage = new BufferedImage(DA_WIDTH, DA_HEIGHT, BufferedImage.TYPE_INT_RGB);
public STDrawingArea()
{
setBorder(BorderFactory.createLineBorder(Color.black));
//Basic Settings for bImage
Graphics g2d = bImage.getGraphics();
g2d.setColor(DA_BGCOLOR);
g2d.fillRect(0, 0, DA_WIDTH, DA_HEIGHT);
g2d.dispose();
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e)
{
points.clear();
points.add(e.getPoint());
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e)
{
points.add(e.getPoint());
repaint();
}
});
addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent e)
{
points.add(e.getPoint());
points.clear();
System.out.println("mouseReleased X: "+e.getX()+"mouseReleased Y: "+e.getY());
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(DA_WIDTH,DA_HEIGHT);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawIntoBufferedImage();
g.drawImage(bImage,0,0,null);
freehandLines(g);
}
public void drawIntoBufferedImage()
{
Graphics g = bImage.getGraphics();
freehandLines(g);
g.dispose();
}
public void freehandLines(Graphics g)
{
if(points != null && points.size() > 1)
{
g.setColor(getCurrentColor());
for(int i = 0; i < points.size()-1;i++)
{
int x1 = points.get(i).x;
int y1 = points.get(i).y;
int x2 = points.get(i+1).x;
int y2 = points.get(i+1).y;
g.drawLine(x1, y1, x2, y2);
}
}
}
//clear drawings method
public void clearDrawings()
{
if(points!=null)
{
points.clear();
Graphics g = bImage.getGraphics();
g.setColor(DA_BGCOLOR);
g.fillRect(0, 0, DA_WIDTH, DA_WIDTH);
g.dispose();
repaint();
}
}
public void setCurrentColor(Color currentColor) {
if(currentColor == null)
{
currentColor = Color.BLACK;
}else{
this.currentColor = currentColor;
}
}
public Color getCurrentColor() {
if (currentColor == null)
return Color.BLACK;
else
return currentColor;
}
}
main class
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class STTestMain extends JFrame {
STDrawingArea drawingArea = new STDrawingArea();
public STTestMain()
{
//JFrame settings
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Spelling Trainer");
setResizable(false);
setVisible(true);
//Panel of buttons
JPanel buttonContainer = new JPanel();
JButton btnRedPen = new JButton("Red Pen");
JButton btnGreenPen = new JButton("Green Pen");
JButton btnClear = new JButton("Clear");
buttonContainer.add(btnRedPen);
buttonContainer.add(btnGreenPen);
buttonContainer.add(btnClear);
//Drawing Area instantiation
//Adding things to JFrame
getContentPane().add(drawingArea);
getContentPane().add(buttonContainer,BorderLayout.PAGE_END);
pack();
//button listener
btnRedPen.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
drawingArea.setCurrentColor(Color.RED);
}
});
btnGreenPen.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
drawingArea.setCurrentColor(Color.GREEN);
}
});
btnClear.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
drawingArea.clearDrawings();
}
});
}
public static void main(String args[])
{
STTestMain test = new STTestMain();
}
}

Categories