Clicking and dragging a Path2D line in JPanel - java

So, I am drawing a line using a Path2D and doing this:
Path2D linePath = new Path2D.Double();
linePath.moveTo(startingX, startingY);
linePath.lineTo(endingX, endingY);
repaint();
What I am trying to do is click-and-drag the line around. For right now, I don't want to change the line's structure (length, etc), I just want to move the line around. I know you can use Path2D.contains(e.getPoint) for enclosed shapes, but this doesn't work for lines. Any ideas? Thanks
Full Code
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Panel;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Editor {
public static void main(String[] args) {
new Editor();
}
public Editor() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException
| UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new UMLWindow();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(30, 30, 1000, 700);
frame.getContentPane().setBackground(Color.white);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
});
}
public static class UMLWindow extends JFrame {
Shapes shapeList = new Shapes();
Panel panel;
private static final long serialVersionUID = 1L;
public UMLWindow() {
addMenus();
panel = new Panel();
}
public void addMenus() {
getContentPane().add(shapeList);
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JMenuItem lineMenuItem = new JMenuItem("New Line");
lineMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println("adding line");
shapeList.addLine();
}
});
JMenuBar menubar = new JMenuBar();
menubar.add(lineMenuItem);
setJMenuBar(menubar);
// shapeList.addLine();
}
}
// Shapes class, used to draw the shapes on the panel
// as well as implements the MouseListener for dragging
public static class Shapes extends JPanel {
private static final long serialVersionUID = 1L;
private List<Path2D> lines = new ArrayList<Path2D>();
private Boolean drawing = false;
private Point lineStartingPoint = new Point();
private Point lineEndingPoint = new Point();
private Path2D.Double linePath;
public Shapes() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
public void addLine() {
drawing = true;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(2));
if (drawing) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(2));
g2.drawLine(lineStartingPoint.x, lineStartingPoint.y,
lineEndingPoint.x, lineEndingPoint.y);
}
for (Path2D shape : lines) {
g2.setColor(Color.BLACK);
g2.draw(shape);
}
}
class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (drawing) {
lineStartingPoint = e.getPoint();
lineEndingPoint = lineStartingPoint;
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (drawing) {
lineEndingPoint = e.getPoint();
repaint();
System.out.println(lines.size());
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (drawing) {
drawLine(e);
drawing = false;
}
}
public void drawLine(MouseEvent e) {
drawing = false;
lineEndingPoint = e.getPoint();
linePath = new Path2D.Double();
linePath.moveTo(lineStartingPoint.getX(),
lineStartingPoint.getY());
linePath.lineTo(lineEndingPoint.getX(), lineEndingPoint.getY());
lines.add(linePath);
repaint();
}
}
}
}

You can use BasicStroke
public Shape createStrokedShape(Shape s)
Define thickness of the line, pass your Path2D and obtain kind of outline of your path. Check whether the outline contains mouse position. If it's contains your mouse is over the Path2D and you can drag the Shape.

Related

Drawing multiple graphic2d components into JPanel

I've read a lot of tutorials on drawing Graphics2D components and adding to JPanel/JFrame but I can't find how to add multiple these components into one JPanel simply. My code below adds only 1 component (line) and I can't find why it isn't possible to add more.
What am I doing wrong?
Desired behaviour: there should be 3 red lines.
My whole code:
package Examples;
import java.awt.BasicStroke;
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 javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example1 extends JFrame {
private final JPanel panel;
public Example1() {
// jpanel with graphics
panel = new JPanel();
panel.setPreferredSize(new Dimension(200, 200));
panel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
panel.setBackground(Color.WHITE);
add(panel);
// adding lines to jpanel
AddMyLine(); // 1st: this works well
AddMyLine(); // 2nd: this doesn't work
AddMyLine(); // 3rd: this doesn't work
setLayout(new FlowLayout(FlowLayout.LEFT));
setSize(250, 250);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setLocationRelativeTo(null);
}
// add new line to jpanel
private void AddMyLine() {
MyLine c = new MyLine();
System.out.println(c);
panel.add(c);
}
// line component
private class MyLine extends JComponent {
public MyLine() {
setPreferredSize(new Dimension(200, 200));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.red);
g2d.setStroke(new BasicStroke(1));
int x1 = (int)Math.round(Math.random()*200);
int y1 = (int)Math.round(Math.random()*200);
int x2 = (int)Math.round(Math.random()*200);
int y2 = (int)Math.round(Math.random()*200);
g2d.drawLine(x1,y1,x2,y2);
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example1();
}
});
}
}
Your MyLine class should not be a Swing component and thus should not extend JComponent. Rather it should be a logical entity, and in fact can be something that implements Shape such as a Line2D, or could be your own complete class, but should know how to draw itself, i.e., if it does not implement Shape, then it should have some type of draw(Graphics2D g) method that other classes can call. I think instead you should work on extending your panel's JPanel class, such that you override its paintComponent method, give it a collection to hold any MyLine items added to it, and draw the MyLine items within the paintComponent.
Other options include drawing directly on to a BufferedImage, and then displaying that BufferedImage in your JPanel's paintComponent method. This is great for static images, but not good for images that need to change or move.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class DrawChit extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private List<Shape> shapes = new ArrayList<>();
public DrawChit() {
setBackground(Color.white);
}
public void addShape(Shape shape) {
shapes.add(shape);
repaint();
}
#Override // make it bigger
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
private static void createAndShowGui() {
DrawChit drawChit = new DrawChit();
drawChit.addShape(new Line2D.Double(10, 10, 100, 100));
drawChit.addShape(new Ellipse2D.Double(120, 120, 200, 200));
JFrame frame = new JFrame("DrawChit");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(drawChit);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Or an example using my own MyDrawable class, which produces a GUI that looks like this:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class DrawChit extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private List<MyDrawable> drawables = new ArrayList<>();
public DrawChit() {
setBackground(Color.white);
}
public void addMyDrawable(MyDrawable myDrawable) {
drawables.add(myDrawable);
repaint();
}
#Override
// make it bigger
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (MyDrawable myDrawable : drawables) {
myDrawable.draw(g2);
}
}
public void clearAll() {
drawables.clear();
repaint();
}
private static void createAndShowGui() {
final List<MyDrawable> myDrawables = new ArrayList<>();
myDrawables.add(new MyDrawable(new Line2D.Double(100, 40, 400, 400),
Color.red, new BasicStroke(40)));
myDrawables.add(new MyDrawable(new Ellipse2D.Double(50, 10, 400, 400),
Color.blue, new BasicStroke(18)));
myDrawables.add(new MyDrawable(new Rectangle2D.Double(40, 200, 300, 300),
Color.cyan, new BasicStroke(25)));
myDrawables.add(new MyDrawable(new RoundRectangle2D.Double(75, 75, 490, 450, 40, 40),
Color.green, new BasicStroke(12)));
final DrawChit drawChit = new DrawChit();
JFrame frame = new JFrame("DrawChit");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(drawChit);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener() {
private int drawCount = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (drawCount >= myDrawables.size()) {
drawCount = 0;
drawChit.clearAll();
} else {
drawChit.addMyDrawable(myDrawables.get(drawCount));
drawCount++;
}
}
}).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class MyDrawable {
private Shape shape;
private Color color;
private Stroke stroke;
public MyDrawable(Shape shape, Color color, Stroke stroke) {
this.shape = shape;
this.color = color;
this.stroke = stroke;
}
public Shape getShape() {
return shape;
}
public Color getColor() {
return color;
}
public Stroke getStroke() {
return stroke;
}
public void draw(Graphics2D g2) {
Color oldColor = g2.getColor();
Stroke oldStroke = g2.getStroke();
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(shape);
g2.setColor(oldColor);
g2.setStroke(oldStroke);
}
public void fill(Graphics2D g2) {
Color oldColor = g2.getColor();
Stroke oldStroke = g2.getStroke();
g2.setColor(color);
g2.setStroke(stroke);
g2.fill(shape);
g2.setColor(oldColor);
g2.setStroke(oldStroke);
}
}
You shouldn't be drawing lines by adding components. Components are things like panels, buttons etc.
See this tutorial on how to draw with Graphics2D: https://docs.oracle.com/javase/tutorial/2d/geometry/primitives.html
Your code adds three components but the panel is not big enough to show the other two components
panel.setPreferredSize(new Dimension(200, 600));
setSize(250, 800);

Robot.createScreenCapture() doesn't seem to match painting operations

I am trying to make a portion of my screen appear blurry. I grab pixel colors out of a BufferedImage where I saved a capture of the screen and draw the pixels again as bigger squares. But this only works when the paint method is called the first time, after that the affected pixels always stay the same even when the content of the screen updates. So it seems that even though the canvas is refreshed at the beginning of the paint method, the robot still sees the screen as it was previously...
#Override public void paintComponent(Graphics g) {
super.paintComponent(g);
screen = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
int gap = 10; int width = 1920;
for (int r = 120; r <= 420; r += gap) {
for (int c = 500; c <= width - 500; c += gap) {
g.setColor(new Color(screen.getRGB(c, r)));
g.fillRect(c, r, gap, gap);
}
}
}
I tried clearing the painted area using clearRect() and sleeping the Thread at different positions, but it didn't work. Where do I need to put the createScreenCapture() so the painting actually updates?
This is the whole class:
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Transparent extends JPanel implements Runnable {
private JFrame frame;
private Robot robot;
private BufferedImage screen;
public static void main(String[] args) {
new Transparent();
}
public Transparent() {
try {
robot = new Robot();
} catch (AWTException ex) {
ex.printStackTrace();
}
frame = new JFrame();
init();
frame.add(this);
frame.setUndecorated(true);
frame.setBackground(new Color(0, true));
frame.setAlwaysOnTop(true);
frame.setSize(1920, 1080);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
new Thread(this).start();
}
public void init() {
setBackground(new Color(0, true));
setOpaque(false);
}
#Override public void paintComponent(Graphics g) {
super.paintComponent(g);
screen = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
int gap = 5; int width = 1920;
for (int r = 120; r <= 420; r += gap) {
for (int c = 500; c <= width - 500; c += gap) {
g.setColor(new Color(screen.getRGB(c, r)));
g.fillRect(c, r, gap, gap);
}
}
}
#Override public void run() {
while (true) {
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
A number of things pop out at me...
You seem to be capturing the who screen, but are't taking into account were the window may actually be positioned and what area it might be covering
When you capture the screen, you component is going to be on it...
Now, this is a very simple example. I demonstrates how to convert the area of your panel to the screen coordinates and capture only that area. It does this by first hiding the window and then taking a snap shot of it before re-showing the window and painting the resulting snap-shot...
import com.jhlabs.image.GaussianFilter;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Transparency;
import java.awt.Window;
import java.awt.event.HierarchyBoundsAdapter;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
try {
JPanel outter = new JPanel(new BorderLayout());
outter.setBorder(new EmptyBorder(20, 20, 20, 20));
outter.add(new TestPane());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(outter);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (AWTException | HeadlessException exp) {
exp.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
private Robot bot;
private BufferedImage snapShot;
private Point lastSnapShot;
public TestPane() throws AWTException {
bot = new Robot();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void updateSnapshot() {
Rectangle bounds = getBounds();
Point p = new Point(0, 0);
SwingUtilities.convertPointToScreen(p, this);
bounds.setLocation(p);
if (lastSnapShot == null || !lastSnapShot.equals(p)) {
lastSnapShot = p;
Window window = SwingUtilities.getWindowAncestor(this);
window.addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
if (!window.isVisible()) {
e.getComponent().removeHierarchyListener(this);
snapShot = bot.createScreenCapture(bounds);
snapShot = generateBlur(snapShot, 10);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
window.setVisible(true);
}
});
}
}
});
window.setVisible(false);
}
}
public BufferedImage generateBlur(BufferedImage imgSource, int size) {
GaussianFilter filter = new GaussianFilter(size);
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight, Transparency.OPAQUE);
Graphics2D g2 = imgBlur.createGraphics();
g2.drawImage(imgSource, 0, 0, null);
g2.dispose();
imgBlur = filter.filter(imgBlur, null);
return imgBlur;
}
public BufferedImage createCompatibleImage(int width, int height, int transparency) {
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage image = gc.createCompatibleImage(width, height, transparency);
image.coerceData(true);
return image;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (snapShot == null) {
updateSnapshot();
}
int x = 0;
int y = 0;
g2d.drawImage(snapShot, 0, 0, this);
g2d.dispose();
}
}
}
This example takes advantage of JH Lab's Filters, cause I'm to lazy to create my own...

Dragging-and-dropping to move a JTextArea around on JPanel

I want to be able to click on a JTextArea and drag it around my JPanel. I'm not sure the method on doing so. What I'm trying to do is change the x,y coordinates of the JTextArea as it is dragged, I'm not dragging a JTextArea above or below another. Just around on the screen, similar to moving Text Boxes in a program like Microsoft PowerPoint
The only method I can think of is using a MouseListener but I'm wondering if there is an easier way to implement it other than detecting a hover/press/drag on the JTextArea. Any ideas on how I can start?
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class UMLEditor {
public static void main(String[] args) {
JFrame frame = new UMLWindow();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(30, 30, 1000, 700);
frame.getContentPane().setBackground(Color.white);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class UMLWindow extends JFrame {
Canvas canvas = new Canvas();
private static final long serialVersionUID = 1L;
public UMLWindow() {
addMenus();
}
public void addMenus() {
getContentPane().add(canvas);
JMenuBar menubar = new JMenuBar();
JMenuItem newTextBox = new JMenuItem("New Text Box");
newTextBox.setMnemonic(KeyEvent.VK_E);
newTextBox.setToolTipText("Exit application");
newTextBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
canvas.addTextBox();
}
});
menubar.add(newTextBox);
setJMenuBar(menubar);
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
class Canvas extends JPanel {
JTextArea commentTextArea = new JTextArea(10, 10);
public Canvas() {
this.setOpaque(true);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
public void addTextBox() {
commentTextArea.setLineWrap(true);
commentTextArea.setWrapStyleWord(true);
commentTextArea.setVisible(true);
commentTextArea.setLocation(0, 0);
this.add(commentTextArea);
commentTextArea.setBounds(0, 0, 100, 100);
revalidate();
repaint();
}
class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
}
}
}
You don't really want to try and "drag" on JTextComponents, they already have functionality enabled which allows the user to click and drag to highlight text, you really don't want to be competing within this.
Instead, you want to define a "hot zone" area around the component which would allow you "highlight" the component in some and allow the user to drag the component via it.
For example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class DragMe {
public static void main(String[] args) {
new DragMe();
}
public DragMe() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JTextArea ta = new JTextArea(10, 20);
ta.setText("Bananas in pajamas");
JScrollPane sp = new JScrollPane(ta);
DragProxyPane proxy = new DragProxyPane(sp);
proxy.setSize(proxy.getPreferredSize());
proxy.setLocation(100 - proxy.getWidth() / 2, 100 - proxy.getHeight()/ 2);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
});
frame.add(proxy);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class DragProxyPane extends JPanel {
public static final int BUFFER_ZONE = 10;
private boolean mouseInHouse;
private JComponent component;
private List<HotZone> hotZones;
public DragProxyPane(JComponent comp) {
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
mouseInHouse = true;
repaint();
}
#Override
public void mouseExited(MouseEvent e) {
mouseInHouse = false;
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
Cursor cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
for (HotZone hz : hotZones) {
if (hz.getBounds(getSize()).contains(e.getPoint())) {
cursor = hz.getCursor();
break;
}
}
setCursor(cursor);
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
setOpaque(false);
setLayout(new BorderLayout());
add(comp);
setBorder(new EmptyBorder(BUFFER_ZONE, BUFFER_ZONE, BUFFER_ZONE, BUFFER_ZONE));
hotZones = new ArrayList<>(8);
// Top left, middle, right
hotZones.add(new HotZone(0f, 0f, Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)));
hotZones.add(new HotZone(0.5f, 0f, Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)));
hotZones.add(new HotZone(1f, 0f, Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)));
// Left, right
hotZones.add(new HotZone(0f, 0.5f, Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)));
hotZones.add(new HotZone(1f, 0.5f, Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)));
// Bottom left, middle, right
hotZones.add(new HotZone(0f, 1f, Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR)));
hotZones.add(new HotZone(0.5f, 1f, Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)));
hotZones.add(new HotZone(1f, 1f, Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (mouseInHouse) {
g2d.setColor(Color.BLACK);
for (HotZone hotZone : hotZones) {
g2d.draw(hotZone.getBounds(getSize()));
}
}
g2d.dispose();
}
public class HotZone {
private float x, y;
private Cursor cursor;
public HotZone(float x, float y, Cursor cursor) {
this.x = x;
this.y = y;
this.cursor = cursor;
}
public Cursor getCursor() {
return cursor;
}
public Rectangle getBounds(Dimension size) {
return getBounds(size.width - 1, size.height - 1);
}
public Rectangle getBounds(int width, int height) {
int halfBuffer = BUFFER_ZONE / 2;
float xPos = (width * x) - halfBuffer;
float yPos = (height * y) - halfBuffer;
xPos = Math.min(Math.max(0, xPos), width - BUFFER_ZONE);
yPos = Math.min(Math.max(0, yPos), height - BUFFER_ZONE);
return new Rectangle(Math.round(xPos), Math.round(yPos), BUFFER_ZONE, BUFFER_ZONE);
}
}
}
}
This sets up a simple proxy component which acts as the hot zone manager, detecting the mouse coming into or out of it and updating the cursor based on its location within in it, but it does not disrupt the normal operations of the component.
Now, this example doesn't drag, sorry, you have plenty of other examples which should be able to get you over the line, but, you could simply add a MouseListener/MouseMoitionListener to the proxy to detect when the user drags, but you will need to add some more functionality to it to determine what that drag actually means (resize or move) ;)

Issue with addMouseMotionListener getting wrong coordinates

I borrowed the class below to make a selection area tool for a project. But it has a issue when I try to make a selection when the content is not aligned at top-left, it get my mouse coordinates related to the ScrollPane, but draws over the image - See this SS for better understanding:
sscce:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
/** Getting a Rectangle of interest on the screen.
Requires the MotivatedEndUser API - sold separately. */
public class ScreenCaptureRectangle {
Rectangle captureRect;
ScreenCaptureRectangle(final BufferedImage screen) {
final BufferedImage screenCopy = new BufferedImage(screen.getWidth(), screen.getHeight(), screen.getType());
final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
JScrollPane screenScroll = new JScrollPane(screenLabel);
screenScroll.setPreferredSize(new Dimension((int)(screen.getWidth()*2), (int)(screen.getHeight()*2)));
JPanel panel = new JPanel(new BorderLayout());
panel.add(screenScroll, BorderLayout.CENTER);
final JLabel selectionLabel = new JLabel("Drag a rectangle in the screen shot!");
panel.add(selectionLabel, BorderLayout.SOUTH);
repaint(screen, screenCopy);
screenLabel.repaint();
screenLabel.addMouseMotionListener(new MouseMotionAdapter() {
Point start = new Point();
#Override
public void mouseMoved(MouseEvent me) {
start = me.getPoint();
repaint(screen, screenCopy);
selectionLabel.setText("Start Point: " + start);
screenLabel.repaint();
}
#Override
public void mouseDragged(MouseEvent me) {
Point end = me.getPoint();
captureRect = new Rectangle(start, new Dimension(end.x-start.x, end.y-start.y));
repaint(screen, screenCopy);
screenLabel.repaint();
selectionLabel.setText("Rectangle: " + captureRect);
}
});
JOptionPane.showMessageDialog(null, panel);
System.out.println("Rectangle of interest: " + captureRect);
}
public void repaint(BufferedImage orig, BufferedImage copy) {
Graphics2D g = copy.createGraphics();
g.drawImage(orig,0,0, null);
if (captureRect!=null) {
g.setColor(Color.RED);
g.draw(captureRect);
g.setColor(new Color(255,255,255,150));
g.fill(captureRect);
}
g.dispose();
}
public static void main(String[] args) throws Exception {
Robot robot = new Robot();
final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
final BufferedImage screen = robot.createScreenCapture(new Rectangle(300,0,300,300));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ScreenCaptureRectangle(screen);
}
});
}
}
I think you have problems because you are attempting to center the image in the panel.
The easiest solution is to make sure the image is painted from the top/left of the panel:
final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
screenLabel.setHorizontalAlignment(JLabel.LEFT);
screenLabel.setVerticalAlignment(JLabel.TOP);
Basically, what's happening, is you are drawing directly to the image surface (which is held by the JLabel), so while, you drag at 2x2x36x36 on the screen, this then draws on the rectangle RELATIVE to the image itself
So even though the image is centered within the context of the JLabel, you are still rendering to the local context of the image (0x0), hence the disconnection between the two.
Depending on what it is you want to achieve, you change the way the painting works and take more direct control, for example...
import java.awt.AWTException;
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.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawimgExample {
public static void main(String[] args) {
try {
Robot robot = new Robot();
final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
final BufferedImage screen = robot.createScreenCapture(new Rectangle(300, 0, 300, 300));
new DrawimgExample(screen);
} catch (AWTException exp) {
exp.printStackTrace();
}
}
public DrawimgExample(final BufferedImage screen) {
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 DrawingPane(screen));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawingPane extends JPanel {
private BufferedImage img;
private Rectangle drawRect;
public DrawingPane(BufferedImage img) {
this.img = img;
MouseAdapter mouseHandler = new MouseAdapter() {
private Point startPoint;
#Override
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
Point endPoint = e.getPoint();
int startX = Math.min(startPoint.x, endPoint.x);
int startY = Math.min(startPoint.y, endPoint.y);
int width = Math.max(startPoint.x, endPoint.x) - startX;
int height = Math.max(startPoint.y, endPoint.y) - startY;
drawRect = new Rectangle(
startX,
startY,
width,
height
);
repaint();
}
};
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
}
#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);
if (drawRect != null) {
g2d.setColor(Color.RED);
g2d.draw(drawRect);
g2d.setColor(new Color(255, 255, 255, 150));
g2d.fill(drawRect);
}
g2d.dispose();
}
}
}
Having said that, where possible, you should avoid painting images directly, as JLabel already does a good job, but sometimes, if it doesn't meet your needs, you might need to take more direct control

Deleting images from JFrame

I created one JFrame. and set layout shown in below code
this.setLayout(new GridLayout());
JPanel panel=new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(new PicturePanel1());
JTabbedPane jtp=new JTabbedPane();
jtp.addTab("show Images", panel);
jtp.addTab("Compare Image", new JButton());
this.add(jtp);
I created another class that draws Images from particular location.
protected void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g2 = (Graphics2D) g;
int k = 20,y=10;
for (int j = 0; j <= listOfFiles.length - 1; j++) {
g2.drawImage(b[j], k, y, 100, 100, null);
// add(new javax.swing.JCheckBox());
k = k + 120;
if(k>=960)
{
k=20;
y=y+120;
}
}
Its working fine. I want to delete Images when user clicks on particular Image.
This is my output window. I want to delete Image from list.
Here is an example I made (bored and tired of studying :)). It is by no means the best just a quick thing to show you an example, click the image you want to delete and then press the delete button or DEL to remove and image from the panel:
When app starts up (orange just shows focused label for hovering):
Image to delete is selected by clicking on the Label (Border becomes green highlighted and will remain this way until another label is clicked):
After delete button or key is pressed:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class JavaApplication5 {
public static void main(String[] args) {
createAndShowJFrame();
}
public static void createAndShowJFrame() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = createJFrame();
frame.setVisible(true);
}
});
}
private static JFrame createJFrame() {
JFrame frame = new JFrame();
//frame.setResizable(false);//make it un-resizeable
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Test");
ArrayList<BufferedImage> images = null;
try {
images = getImagesArrayList();
} catch (Exception ex) {
ex.printStackTrace();
}
final ImageViewPanel imageViewPanel = new ImageViewPanel(images);
JScrollPane jsp = new JScrollPane(imageViewPanel);
jsp.setPreferredSize(new Dimension(400, 400));
frame.add(jsp);
JPanel controlPanel = new JPanel();
JButton addLabelButton = new JButton("Delete Selected Image");
addLabelButton.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
imageViewPanel.removeFocusedImageLabel();
}
});
controlPanel.add(addLabelButton);
frame.add(controlPanel, BorderLayout.SOUTH);
frame.pack();
return frame;
}
private static ArrayList<BufferedImage> getImagesArrayList() throws Exception {
ArrayList<BufferedImage> images = new ArrayList<>();
images.add(resize(ImageIO.read(new URL("http://icons.iconarchive.com/icons/deleket/sleek-xp-software/256/Yahoo-Messenger-icon.png")), 100, 100));
images.add(resize(ImageIO.read(new URL("https://upload.wikimedia.org/wikipedia/commons/6/64/Gnu_meditate_levitate.png")), 100, 100));
return images;
}
public static BufferedImage resize(BufferedImage image, int width, int height) {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(image, 0, 0, width, height, null);
g2d.dispose();
return bi;
}
}
class ImageViewPanel extends JPanel {
JLabel NO_IMAGES = new JLabel("No Images");
ArrayList<BufferedImage> images;
ArrayList<MyLabel> imageLabels;
public ImageViewPanel(ArrayList<BufferedImage> images) {
this.images = images;
imageLabels = new ArrayList<>();
for (BufferedImage bi : images) {
imageLabels.add(new MyLabel(new ImageIcon(bi), this));
}
layoutLabels();
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0, true), "Delete pressed");
getActionMap().put("Delete pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
removeFocusedImageLabel();
}
});
}
void removeFocusedImageLabel() {
if (focusedLabel == null) {
return;
}
imageLabels.remove(focusedLabel);
remove(focusedLabel);
layoutLabels();
}
private void layoutLabels() {
if (imageLabels.isEmpty()) {
add(NO_IMAGES);
} else {
remove(NO_IMAGES);
for (JLabel il : imageLabels) {
add(il);
}
}
revalidate();
repaint();
}
private MyLabel focusedLabel;
void setFocusedLabel(MyLabel labelToFocus) {
if (focusedLabel != null) {
focusedLabel.setBorder(null);
focusedLabel.setClicked(false);
}
focusedLabel = labelToFocus;
focusedLabel.setBorder(new LineBorder(Color.GREEN));
}
}
class MyLabel extends JLabel {
private final ImageViewPanel imageViewPanel;
private boolean clicked = false;
public MyLabel(Icon image, ImageViewPanel imageViewPanel) {
super(image);
this.imageViewPanel = imageViewPanel;
initLabel();
}
public MyLabel(String text, ImageViewPanel imageViewPanel) {
super(text);
this.imageViewPanel = imageViewPanel;
initLabel();
}
private void initLabel() {
setFocusable(true);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
clicked = true;
imageViewPanel.setFocusedLabel(MyLabel.this);
}
#Override
public void mouseEntered(MouseEvent me) {
super.mouseEntered(me);
if (clicked) {
return;
}
setBorder(new LineBorder(Color.ORANGE));
//call for focus mouse is over this component
requestFocusInWindow();
}
});
addFocusListener(new FocusAdapter() {
#Override
public void focusLost(FocusEvent e) {
super.focusLost(e);
if (clicked) {
return;
}
setBorder(null);
}
});
}
public void setClicked(boolean clicked) {
this.clicked = clicked;
}
public boolean isClicked() {
return clicked;
}
}
simply find the location (x, and y) and the size(width, and height) of image, then with the Graphics object (g2) fill a rectangle over the image drawn, like this
g2.setColor(this.getBackground());//set the color you want to clear the bound this point to JFrame/JPanel
g2.fillRect(x, y, width, height);
where x and y where is the location that images is located, and width and height are size of the picture

Categories

Resources