Mouse Drawing Application: Nothing shows up - java

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);
}
}
}
}

Related

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();
}
}
}

Java drawing a line between the centre of components

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

Java Graphics, changing the color of drawings using click event

Ok so basically I'm trying to write a GUI application which draws 2 circles and 2 rectangles in its main window. I'm trying to get it so that whenever the user clicks within the circles or rectangles, that particular circle or rectangle changes to another random colour.
Currently I've got it so that the MouseClick event (anywhere on screen) causes all of the circles or rectangles to change colour, to the same colour.
This is what I've got so far:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Question2 {
public static void main(String[] args) {
SecondFrame f = new SecondFrame("Draw and Fill");
f.init();
}
}
class SecondFrame extends JFrame{
SecondFrame(String title) {
super(title);
}
private JPanel mainPanel;
private GridBagConstraints gbc = new GridBagConstraints();
private GridBagLayout gbLayout = new GridBagLayout();
void init() {
mainPanel = new JPanel();
mainPanel.setLayout(gbLayout);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setContentPane(mainPanel);
gbc.gridheight = 1;
mainPanel.addMouseListener(new MouseListener(){
#Override
public void mouseClicked(MouseEvent e) {
Point mousePosition;
mousePosition = mainPanel.getMousePosition();
repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
});
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public void paint(Graphics g){
super.paint(g);
Random ran = new Random();
// Assumes max and min are non-negative.
int red = 0 + ran.nextInt(255 - 0 + 1);
int green = 0 + ran.nextInt(255 - 0 + 1);
int blue = 0 + ran.nextInt(255 - 0 + 1);
Color myColor = new Color(red,green,blue);
g.setColor(myColor);
g.fillOval(50,50,200,200);
g.fillOval(50, 255, 200, 200);
g.fillRect(255,50,200,200);
g.fillRect(255, 255, 200, 200);
}
}
If you could point me in the right direction that would be much appreciated. Thanks.
You would keep a track of drawn object. Then check if click occurred within any of these objects. If yes, change its color. For example, you can use Shape to represent simple forms. Its contains() method can be useful to determine if a clicked point is inside the boundary of the shape. Below is an example that introduces ShapeItem that has two properties Shape and Color. And, a panel that uses a list of ShapeItem to paint the actual shapes.
Also consider some minor side notes:
Don't paint directly on top level container such as JFrame. Instead, use JPanel or extension of JComponent;
For painting override paintComponent() rather than paint(), and don't forget to call super.paintComponent(g);
Usually there is no need to extend JFrame unless new functionality is added;
Take a look at Performing Custom Painting tutorial, and Closer Look at the Paint Mechanism section in particular, for more details.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DemoShapes {
public static final Color DEFAULT_COLOR = Color.BLUE;
public DemoShapes() {
List<ShapeItem> shapes = new ArrayList<ShapeItem>();
shapes.add(new ShapeItem(new Rectangle2D.Double(110, 1, 100, 100),
DEFAULT_COLOR));
shapes.add(new ShapeItem(new Rectangle2D.Double(110, 110, 100, 100),
DEFAULT_COLOR));
shapes.add(new ShapeItem(new Ellipse2D.Double(1, 1, 100, 100),
DEFAULT_COLOR));
shapes.add(new ShapeItem(new Ellipse2D.Double(1, 110, 100, 100),
DEFAULT_COLOR));
JFrame frame = new JFrame("Shapes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ShapesPanel panel = new ShapesPanel(shapes);
frame.add(panel);
frame.setLocationByPlatform(true);
frame.pack();
frame.setVisible(true);
}
class ShapeItem {
private Shape shape;
private Color color;
public ShapeItem(Shape shape, Color color) {
super();
this.shape = shape;
this.color = color;
}
public Shape getShape() {
return shape;
}
public void setShape(Shape shape) {
this.shape = shape;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
class ShapesPanel extends JPanel {
private List<ShapeItem> shapes;
private Random rand = new Random();
public ShapesPanel(List<ShapeItem> shapesList) {
this.shapes = shapesList;
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
Color color = getRandomColor();
for (ShapeItem item : shapes) {
if (item.getShape().contains(e.getPoint())) {
item.setColor(color);
}
}
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
for (ShapeItem item : shapes) {
g2.setColor(item.getColor());
g2.fill(item.getShape());
}
g2.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
private Color getRandomColor() {
return new Color(rand.nextFloat(), rand.nextFloat(),
rand.nextFloat());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new DemoShapes();
}
});
}
}
You should use mousePosition to determine if that point is within the bounds of any ovals or rectangles. If it is, perform g.setColor(myColor) and fill that shape. Then change g to a normal, non-randomized color, and fill the rest of the shapes.

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