Java drawing a line between the centre of components - java

I am trying to have a line drawn between the centre of two JLabels when the user clicks on one label, drags and releases on top of another. Which should work no matter what size the window is.
But the lines are not centre, how can I fix it?
The following example is working, but the lines seem to be offset by the boundaries of the JFrame, so they are not centre.
I do not want to try to remove the JFrame border from the point calculation, since the real interface is more complex than the example given, and has many more components included in the JFrame.
I thought the point calculation would be relative to the JPanel I am using so I would not run into the JFrame boundary issues, but this does not seem to be the case.
Thank you in advance for any help.
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class test extends JFrame implements MouseListener {
private static JPanel panel = new JPanel();
private static test window = new test();
public test() {
panel.setLayout(new GridLayout(2, 2));
JLabel l1 = new JLabel();
JLabel l2 = new JLabel();
JLabel l3 = new JLabel();
JLabel l4 = new JLabel();
l1.setOpaque(true);
l2.setOpaque(true);
l3.setOpaque(true);
l4.setOpaque(true);
l1.setBackground(Color.RED);
l2.setBackground(Color.BLUE);
l3.setBackground(Color.GREEN);
l4.setBackground(Color.ORANGE);
l1.setName("l1");
l2.setName("l2");
l3.setName("l3");
l4.setName("l4");
panel.add(l1);
panel.add(l2);
panel.add(l3);
panel.add(l4);
panel.addMouseListener(this);
this.add(panel);
}
public static void drawArcs(int x1, int y1, int x2, int y2) {
Graphics g = window.getGraphics();
Graphics2D g2 = (Graphics2D) g;
g2.drawLine(x1, y1, x2, y2);
}
private static int x1 = 0;
private static int y1 = 0;
public void mousePressed(MouseEvent e) {
Component square1 = panel.getComponentAt(new Point(e.getX(), e.getY()));
System.out.println( square1.getName() );
x1 = square1.getX() + square1.getWidth() / 2;
y1 = square1.getY() + square1.getHeight() / 2;
}
public void mouseReleased(MouseEvent e) {
Component square2 = panel.getComponentAt(new Point(e.getX(), e.getY()));
System.out.println( square2.getName() );
int x2 = square2.getX() + square2.getWidth() / 2;
int y2 = square2.getY() + square2.getHeight() / 2;
drawArcs(x1, y1, x2, y2);
}
#Override
public void mouseClicked(MouseEvent arg0) {}
#Override
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
public static void main(String[] args) {
window.setVisible(true);
window.setSize(400, 400);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

So, the basic problem is, the location of your components are relative to panel, which is offset by the frame's decorations, but you are using the frame's existing Graphics context to paint the line, so the lines are misaligned.
Apart from NOT using getGraphics, EVER, you could achieve the expected results by using the frame's glassPane, for example
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test extends JFrame implements MouseListener {
private JPanel panel = new JPanel();
public Test() {
ConnectTheDots dots = new ConnectTheDots();
setGlassPane(dots);
dots.setVisible(true);
panel.setLayout(new GridLayout(2, 2));
panel.add(createLabel(Color.RED));
panel.add(createLabel(Color.BLUE));
panel.add(createLabel(Color.GREEN));
panel.add(createLabel(Color.ORANGE));
panel.addMouseListener(this);
this.add(panel);
}
private Component pressComponent;
private Component releaseComponent;
public void mousePressed(MouseEvent e) {
pressComponent = panel.getComponentAt(new Point(e.getX(), e.getY()));
}
public void mouseReleased(MouseEvent e) {
releaseComponent = panel.getComponentAt(new Point(e.getX(), e.getY()));
joinTheDots();
}
#Override
public void mouseClicked(MouseEvent arg0) {
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
protected void joinTheDots() {
Rectangle bounds = pressComponent.getBounds();
Point startPoint = centerOf(bounds);
bounds = releaseComponent.getBounds();
Point endPoint = centerOf(bounds);
((ConnectTheDots) getGlassPane()).drawLine(startPoint, endPoint);
}
protected Point centerOf(Rectangle bounds) {
return new Point(
bounds.x + (bounds.width / 2),
bounds.y + (bounds.height / 2));
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Test frame = new Test();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected JLabel createLabel(Color background) {
JLabel label = new JLabel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
};
label.setOpaque(true);
label.setBackground(background);
return label;
}
public class ConnectTheDots extends JPanel {
private Point startPoint;
private Point endPoint;
public ConnectTheDots() {
setOpaque(false);
}
public void drawLine(Point startPoint, Point endPoint) {
this.startPoint = startPoint;
this.endPoint = endPoint;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (startPoint != null && endPoint != null) {
Graphics2D g2d = (Graphics2D) g.create();
Line2D line = new Line2D.Double(startPoint, endPoint);
g2d.setColor(Color.BLACK);
g2d.draw(line);
g2d.dispose();
}
}
}
}
Now, this will only work if the content covers the entire visible area of the contentPane, while you could mess around with converting the location information from one component context to another, a simpler solution would be to use JXLayer.
The reason I would avoid overriding paint in this case, is Swing components can be updated without requiring the parent component to be painted, this could wipe out what ever the parent component painted the last time it was painted...
Take a look at How to Use Root Panes for more details

Related

Mouse Drawing Application: Nothing shows up

This is a word-for-word example straight out of the book Java How to Program by Paul and Harvey Deitel.
PaintPanel.java
// Using class MouseMotionAdapter
import java.awt.Point;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JPanel;
public class PaintPanel extends JPanel {
private int pointCount = 0;
// array of 10,000 java.awt.Point references
private Point[] points = new Point[10000];
// set up gui and register mouse event handler
public PaintPanel() {
addMouseMotionListener(new MouseMotionAdapter() {
// store drag coordinates and repaint
public void MouseDragged(MouseEvent e) {
if (pointCount < points.length) {
points[pointCount] = e.getPoint();
pointCount++;
repaint();
} // end if
}
}
);
}
// draw ovals in a 4 x 4 bounding box at specified location on the window
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // clear drawing area
g.setColor(Color.BLUE);
// draw all points in the array
for(int i = 0; i < pointCount; i++)
g.fillOval(points[i].x, points[i].y, 4, 4);
}
}
Driver program Painter.java
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Painter {
public static void main(String[] args) {
JFrame app = new JFrame("A Simple Paint Program");
PaintPanel pp = new PaintPanel();
app.add(pp, BorderLayout.CENTER);
app.add(new JLabel("Drag the rat to draw"), BorderLayout.SOUTH);
app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
app.setSize(400, 200);
app.setVisible(true);
}
}
When I run it, it shows the drawing panel but nothing happens when I try to draw on it with the mouse. All code is copied verbatim from the book. What gives?
Java is case sensitive. It's mouseDragged, not MouseDragged. This is why you should always use #Override on methods you "think" you're overriding, this way you get compile time protection.
Runnable example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new PaintPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPanel extends JPanel {
private int pointCount = 0;
// array of 10,000 java.awt.Point references
private Point[] points = new Point[10000];
// set up gui and register mouse event handler
public PaintPanel() {
addMouseMotionListener(new MouseMotionAdapter() {
// store drag coordinates and repaint
#Override
public void mouseDragged(MouseEvent e) {
if (pointCount < points.length) {
points[pointCount] = e.getPoint();
pointCount++;
repaint();
} // end if
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
// draw ovals in a 4 x 4 bounding box at specified location on the window
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // clear drawing area
g.setColor(Color.BLUE);
// draw all points in the array
for (int i = 0; i < pointCount; i++) {
g.fillOval(points[i].x, points[i].y, 4, 4);
}
}
}
}

How to display floating tool tip text on a polygon

I have written a Java code to draw a polygon on an image. When I put my cursor inside the polygon it prints "Inside" otherwise "Outside". So the detection of the points inside the polygon is working fine.
But I want to implement the effect of setToolTipText inside the polygon i.e. at the time of mouse hover inside the polygon, it will show the floating text "Inside".
Similar to the effect in this image:
http://www.java2s.com/Code/Java/Swing-JFC/WorkingwithTooltipText.htm
What are the minimal changes to be made in the following code to get the desired effect?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.image.*;
import java.awt.Graphics.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
class page1 extends JFrame implements MouseListener,MouseMotionListener ,ActionListener
{
JFrame f;
JLabel l;
JPanel p1;
ImageIcon ii;
Image img;
int height;
int width;
Container c;
int pixels[];
PixelGrabber pg;
JPanel panel;
Graphics2D gg;
Polygon pp1=new Polygon();
boolean startHovercurrent,startHoverprev=false;
page1()
{
f=new JFrame("Sample Page");
ii=new ImageIcon("sample.jpg");
img=ii.getImage();
height=ii.getIconHeight();
width=ii.getIconWidth();
pixels=new int[ii.getIconWidth()*ii.getIconHeight()];
pg=new PixelGrabber(img,0,0,ii.getIconWidth(),ii.getIconHeight(),pixels,0,ii.getIconWidth());
try
{
pg.grabPixels();
}
catch(InterruptedException k)
{
}
//add points of polygon
pp1.addPoint(300,300);
pp1.addPoint(380,300);
pp1.addPoint(380,220);
pp1.addPoint(300,220);
l=new JLabel(ii,JLabel.CENTER);
c=f.getContentPane();
JDesktopPane desk = new JDesktopPane();
JInternalFrame p = new JInternalFrame("Image Frame",false, false, true, false);
JScrollPane scroll = new JScrollPane(l);
p.setContentPane(scroll);
p.setBounds(0, 0, 740, 600);
desk.add(p);
p.setVisible(true);
l.addMouseListener(this);
l.addMouseMotionListener(this);
c.add(desk, BorderLayout.CENTER);
f.setSize(1024,738);
f.setVisible(true);
}
public static void main(String args[])
{
new page1();
}
public void mouseClicked(MouseEvent me)
{
}
public void mouseEntered(MouseEvent me)
{
}
public void mouseExited(MouseEvent me)
{
}
public void mousePressed(MouseEvent me)
{
}
public void mouseReleased(MouseEvent me)
{
}
public void mouseMoved(MouseEvent me)
{
boolean contain1;
int mx,my;
gg=(Graphics2D)l.getGraphics();
gg.setColor(new Color(255,0,0) );
gg.fillPolygon(pp1);
mx = me.getX();
my = me.getY();
//check if mouse cursor is inside polygon or not
// do not print anything if next cursor position is in same state
contain1=pp1.contains(mx,my);
if (contain1) {
startHovercurrent = true;
if(startHovercurrent!=startHoverprev)
System.out.println("Inside");
startHoverprev=startHovercurrent;
}
else {
startHovercurrent = false;
if(startHovercurrent!=startHoverprev)
System.out.println("Outside");
startHoverprev=startHovercurrent;
}
}
public void mouseDragged(MouseEvent me)
{
}
public void actionPerformed(ActionEvent ae)
{
}
}
For this usage, How to Use Tool Tips suggests overriding the getToolTipText() method of the enclosing JComponent. This answer outlines the approach for JMapViewer and ChartPanel. In the example below, getToolTipText() simply returns the name of any Shape that contains() the triggering mouse event. For comparison, the JLabel at window's bottom gets a conventional too tip via setToolTipText().
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.ToolTipManager;
/**
* #see https://stackoverflow.com/a/53609066/230513
* #see https://stackoverflow.com/a/25944439/230513
*/
public class ShapeToolTip {
private static class ShapePanel extends JPanel {
private final List<Shape> list = new ArrayList<>();
public ShapePanel() {
Polygon p = new Polygon();
p.addPoint(500, 100);
p.addPoint(500, 400);
p.addPoint(200, 400);
list.add(p);
list.add(new Ellipse2D.Double(100, 100, 200, 200));
ToolTipManager.sharedInstance().registerComponent(this);
}
#Override
public String getToolTipText(MouseEvent e) {
for (Shape shape : list) {
if (shape.contains(e.getX(), e.getY())) {
return shape.getClass().getName();
}
}
return "Outside";
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(2));
for (Shape shape : list) {
g2d.draw(shape);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
}
private void display() {
JFrame f = new JFrame("ShapeToolTip");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new ShapePanel());
JLabel title = new JLabel("Shape Tool Tip", JLabel.CENTER);
title.setToolTipText("Title");
title.setFont(title.getFont().deriveFont(Font.BOLD, 24));
f.add(title, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new ShapeToolTip()::display);
}
}

How do I fire MouseMotionListener events in real-time?

I am trying to create a graphics drawing program that allows the user to draw red pixels on the screen by dragging their mouse over it. So in a way, you can think of this program as Microsoft's Paint program but with only the pencil drawing tool and color red.
Unfortunately the mouseDragged() function in my program is not working properly. It will skip some of the pixels on the screen if I move my mouse too fast, like this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FrameView extends JFrame {
JPanel panel;
Graphics2D drawingContext;
public static void main(String[] args) {
new FrameView();
}
public FrameView() {
panel = new JPanel();
panel.addMouseMotionListener(new MouseControls());
panel.setBackground(Color.WHITE);
this.add(panel);
this.setSize(new Dimension(500, 500));
this.setTitle("Drawing Program");
this.setVisible(true);
drawingContext = (Graphics2D)panel.getGraphics();
}
private class MouseControls extends MouseAdapter {
#Override
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
final int WIDTH = 1;
final int HEIGHT = 1;
Shape pixel = new Rectangle(x, y, WIDTH, HEIGHT);
drawingContext.setColor(Color.RED);
drawingContext.draw(pixel);
}
}
}
getGraphics is NOT how painting works in Swing, instead, you should be overriding the paintComponent method of the component and performing your custom painting there.
Painting is destructive, it is expected that when ever paintComponent is called, you will completely repaint the current state of the component.
Have a look at Painting in AWT and Swing and Performing Custom Painting for more details
As to you "mouse" problem, this is actually how it works, you won't be notified of EVERY pixel position the mouse has to pass through, your mouse would lag horribly across the screen if it did. Instead, the OS moves the mouse in ever increasing steps based on the speed of the movement of the user input.
Instead of drawing just the points, draw lines between them, for example
nb: I've deliberately painted the points larger so you can see where they are been reported, you will see that all the dots (for a single drag) are connected
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.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
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();
}
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 List<List<Point>> points = new ArrayList<>(25);
private List<Point> activeList;
public TestPane() {
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (activeList != null) {
activeList.add(e.getPoint());
repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
activeList = new ArrayList<>(25);
points.add(activeList);
}
#Override
public void mouseReleased(MouseEvent e) {
if (activeList != null && activeList.isEmpty()) {
points.remove(activeList);
}
activeList = null;
}
};
addMouseMotionListener(ma);
addMouseListener(ma);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
for (List<Point> group : points) {
Point previous = null;
for (Point p : group) {
// You can get rid of this, it's simply to show
// where the points would actually be rendered
g2d.fill(new Ellipse2D.Float(p.x - 2, p.y - 2, 4, 4));
if (previous != null) {
g2d.draw(new Line2D.Float(previous, p));
}
previous = p;
}
}
g2d.dispose();
}
}
}

I'm trying to draw a filled rectangle over an imageIcon using the coordinates of the image and the rectangle appears off

Eventually after I work out this small detail it will receive a building and room number to outline said building and room number so it is easy to locate but I can't get the rectangle to draw even close to acurately over a single room.
package programSTLApp;
/*
Program to request the classroom no. in STLCC and Display the location of
that classroom.
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class STLApp extends JFrame
{
private JLabel imageLabel;
private JButton button;
private JPanel imagePanel;
private JPanel buttonPanel;
public STLApp()
{
super("My STLCC Class Locator");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
buildImagePanel();
buildButtonPanel();
add(imagePanel, BorderLayout.CENTER);
add(buttonPanel,BorderLayout.SOUTH);
pack();
setVisible(true);
}
private void buildImagePanel()
{
imagePanel = new JPanel();
imageLabel = new JLabel("Click the button to see the drawing indicating "
+ "the location of your class");
imagePanel.add(imageLabel);
}
private void buildButtonPanel()
{
buttonPanel = new JPanel();
button = new JButton("Get Image");
button.addActionListener(new ButtonListener());
buttonPanel.add(button);
}
private class ButtonListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
ImageIcon SiteLayoutFV = new ImageIcon("D:\\B120.jpg");
imageLabel.setIcon(SiteLayoutFV);
imageLabel.setText(null);
pack();
}
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.RED);
g.fillRect(55,740,164,815);
}
public static void main(String[] args)
{
new STLApp();
}
}
As has already being pointed out, top level containers ain't a studiable class for performing custom painting, there is just to much going with these containers to make it easy to paint to.
Instead, create yourself a custom component, extending from something like JPanel, and override it's paintComponent method.
Once you have the floor pane rendered, you can render you custom elements over the top of it.
How you store this information is up to you, but basically, you need some kind of mapping that would allow you to take the floor/room and get the Shape that should be rendered.
Because the floor map might float (it may not always be rendered at 0x0 for example), you need to be able to translate the coordinates so that the Shape will always match.
Take a look at...
Performing Custom Painting
2D Graphics
For more details
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.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FloorPlan {
public static void main(String[] args) {
new FloorPlan();
}
public FloorPlan() {
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 BufferedImage floorPlan;
private Rectangle myOffice = new Rectangle(150, 50, 32, 27);
public TestPane() {
try {
floorPlan = ImageIO.read(new File("floorPlan.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return floorPlan == null ? new Dimension(200, 200) : new Dimension(floorPlan.getWidth(), floorPlan.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (floorPlan != null) {
int x = (getWidth() - floorPlan.getWidth()) / 2;
int y = (getHeight() - floorPlan.getHeight()) / 2;
g2d.drawImage(floorPlan, x, y, this);
g2d.setColor(Color.RED);
g2d.translate(x, y);
g2d.draw(myOffice);
}
g2d.dispose();
}
}
}

Drawing on JPanel behind GlassPane when clicking on GlassPane

Okay So I looked through multiple forums and Google and couldn't find an answer to my specific problem. So I have two panels stacked on top of each other and the one on top is a glassPane. When you drag your mouse around the glassPane it draws a vertical red line at the cursor,which works, but when I click on the glassPane I want it it draw a black line at the cursor position on the panel below the glassPane. I can get it to redirect the mouseClick to the bottom panel but it wont draw the line. It just makes the redline disappear until you move the mouse again. Also If I set the glassPane invisible and click on the bottom panel the line is drawn so the drawing code works just fine. Thanks in advance.
Main Class
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Robot;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
public class LiveField extends JPanel {
/**
* Create the panel.
*/
static JFrame frame;
static JPanel ContentPane;
private JPanel panel;
private MyGlassPane glassPane;
public static void main(String[] args) throws AWTException
{
LiveField live = new LiveField();
frame.setVisible(true);
}
public LiveField() throws AWTException {
frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1000, 433);
setLayout(new BorderLayout(0, 0));
ContentPane = new JPanel();
frame.setContentPane(ContentPane);
ContentPane.setLayout(new BorderLayout(0, 0));
panel = new JPanel()
{
public void paintComponent(Graphics g) {
super.paintComponent(g);
panel.setBackground(new Color(50,160,55));
}
};
glassPane = new MyGlassPane(panel);
frame.setGlassPane(glassPane);
glassPane.setVisible(true);
panel.addMouseListener(new MouseAdapter() {
int[] pos = new int[2];
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Handles click event");
Graphics g = panel.getGraphics();
g.setColor(new Color(50,165,55));
g.drawLine(pos[0], pos[1], 0+pos[0], 0);//to top
g.drawLine(pos[0], pos[1], 0+pos[0], panel.getHeight());//to bottom
int y = e.getYOnScreen();
int x = e.getXOnScreen();
pos[0]= x;
pos[1] = y;
g.setColor(new Color(0,0,0));
g.drawLine(x, y, 0+x, 0);//to top
g.drawLine(x, y, 0+x, panel.getHeight());//to bottom
g.dispose();
}
});
ContentPane.add(panel, BorderLayout.CENTER);
}
GlassPane Class
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import javax.swing.JComponent;
class MyGlassPane extends JComponent implements ItemListener {
Point point;
protected void paintComponent(Graphics g) {
}
public void setPoint(Point p) {
point = p;
}
public MyGlassPane(final Container contentPane) throws AWTException {
final Component glass = this;
addMouseMotionListener(new MouseMotionListener()
{
ArrayList<Integer> line = new ArrayList<Integer>();
Robot rb = new java.awt.Robot();
#Override
public void mouseMoved(MouseEvent e) {
//System.out.println("Moving");
Graphics g = glass.getGraphics();
if(!line.isEmpty())
{
//System.out.println("line is not empty");
g.setColor(new Color(50,160,55));
g.drawLine(line.get(0), line.get(1), 0+line.get(0), 0);//to top
g.drawLine(line.get(0), line.get(1), 0+line.get(0), contentPane.getHeight());//to bottom
}
//System.out.println("draw line");
int x = e.getXOnScreen();
int y = e.getYOnScreen();
Color col = rb.getPixelColor(x, y);
//System.out.println(col.toString() + " : " + Color.white.toString());
//System.out.println(col.equals(new Color(255,255,255)));
if(!col.equals(new Color(255,255,255)) && !inEndZone(x))
{
g.setColor(new Color(255,0,0));
line = new ArrayList<Integer>();
line.add(x);line.add(y);
g.drawLine(x, y, 0+line.get(0), 0);//to top
g.drawLine(x, y, 0+line.get(0), contentPane.getHeight());//to bottom
}
g.dispose();
}
private boolean inEndZone(int x) {
int ends = contentPane.getWidth()/10;
//System.out.println(x + " : " + ends);
if(x<ends)
{
//System.out.println("In endzone");
return true;
}
else if(x>contentPane.getWidth()-ends)
{
return true;
}
else
{
return false;
}
}
#Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
}
});
addMouseListener(new CBListener(this,contentPane));
}
#Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
setVisible(e.getStateChange() == ItemEvent.SELECTED);
}
}
Listener Class ( for dispatching the mouse click)
import java.awt.Component;
import java.awt.Container;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
class CBListener extends MouseInputAdapter {
Toolkit toolkit;
Robot rb;
MyGlassPane glassPane;
Container contentPane;
public CBListener(MyGlassPane glassPane, Container contentPane) {
toolkit = Toolkit.getDefaultToolkit();
this.glassPane = glassPane;
this.contentPane = contentPane;
}
#Override
public void mouseClicked(MouseEvent e) {
redispatchMouseEvent(e, false);
}
// A basic implementation of redispatching events.
private void redispatchMouseEvent(MouseEvent e, boolean repaint) {
Point glassPanePoint = e.getPoint();
Container container = contentPane;
Point containerPoint = SwingUtilities.convertPoint(glassPane,
glassPanePoint, contentPane);
if (containerPoint.y < 0) { // we're not in the content pane
} else {
// The mouse event is probably over the content pane.
// Find out exactly which component it's over.
Component component = SwingUtilities.getDeepestComponentAt(
container, containerPoint.x, containerPoint.y);
if ((component != null) && (component.equals(contentPane))) {
System.out.println("contentPane");
// Forward events over the check box.
Point componentPoint = SwingUtilities.convertPoint(glassPane,
glassPanePoint, component);
component.dispatchEvent(new MouseEvent(component, e.getID(), e
.getWhen(), e.getModifiers(), componentPoint.x,
componentPoint.y, e.getClickCount(), e
.isPopupTrigger()));
}
}
// Update the glass pane if requested.
if (repaint) {
glassPane.setPoint(glassPanePoint);
glassPane.repaint();
}
}
}
I can get it to redirect the mouseClick to the bottom panel but it
wont draw the line. It just makes the redline disappear until you move
the mouse again
No, It is drawing black line indeed. But the line is drawn above the red line that makes the red line to vanish till the mouse is moved again . I Guess you are looking for something like this:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class DoublePanel extends JFrame
{
JPanel mainPanel;
int x1;
public void prepareAndShowGUI()
{
setTitle("DoublePanel");
mainPanel = new JPanel()
{
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawLine(x1,0,x1,this.getHeight());
}
};
mainPanel.setBackground(new Color(50,160,55));
mainPanel.setLayout(new BorderLayout());
mainPanel.add(new upperPanel(this));
setContentPane(mainPanel);
setSize(500,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
}
public void setXValue(int x)
{
this.x1 = x;
mainPanel.repaint();
}
class upperPanel extends JPanel
{
int x; int y;
DoublePanel dp;
upperPanel(DoublePanel d)
{
this.dp = d;
setOpaque(false);
addMouseMotionListener(new MouseAdapter()
{
#Override
public void mouseMoved(MouseEvent evt)
{
x = evt.getX();
y = evt.getY();
repaint();
}
});
addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent evt)
{
dp.setXValue(evt.getX());
}
});
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.RED);
g.drawLine(x,0,x,this.getHeight());
}
}
public static void main(String st[])
{
SwingUtilities.invokeLater( new Runnable()
{
public void run()
{
DoublePanel dp = new DoublePanel();
dp.prepareAndShowGUI();
}
});
}
}
You need to call the bottom panel's repaint().

Categories

Resources