I'm new to drawing in Java and have been having some trouble working with the mouse listener event. What I am trying to do is draw a point on click, then draw a line that extends from that point on click, and finally the last point on click connects to make a triangle. As of now I am just working on getting the point and line to work. The way I have it now is close I think; a circle is drawn in the top corner instead of where the user clicks but on click a line is drawn from where the circle is. Tried using a boolean to decide when something should be drawn but have been unsuccessful..Thanks for any help.
Main Class
package TriangleDraw;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class TriangleDrawMain {
public static void main(String[] args) {
//create a frame or window
JFrame frame = new JFrame();
//set window size
frame.setSize(500, 500);
//set the title
frame.setTitle("Triangle Draw");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//add panel to frame and make it visible
MouseComponent component = new MouseComponent();
frame.add(component);
frame.setVisible(true);
}
}
Drawing Class
package TriangleDraw;
import java.util.*;
import java.awt.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import javax.swing.*;
import java.awt.geom.*;
public class MouseComponent extends JPanel implements MouseListener{
boolean drawPoint = true;
boolean drawLine = false;
boolean drawTriangle = false;
public MouseComponent(){
super();
pointX = 0;
pointY = 0;
oldX = 0;
oldY = 0;
addMouseListener(this);
}
int pointX, pointY, oldX,oldY;
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if(drawPoint == true){
g.drawOval(pointX,pointY,10,10);
drawPoint = false;
drawLine = true;
oldX = pointX;
oldY = pointY;
}
if(drawLine == true){
g.drawLine(pointX, pointY, oldX, oldY);
}
}
public void mouseClicked(MouseEvent mouse){
pointX = mouse.getX();
pointY = mouse.getY();
repaint();
}
public void mouseEntered(MouseEvent mouse){ }
public void mouseExited(MouseEvent mouse){ }
public void mousePressed(MouseEvent mouse){ }
public void mouseReleased(MouseEvent mouse){ }
}
I wouldn't change state in paintComponent, you don't know when that will be called (where you assign oldX and oldY). I suggest creating two Point objects, and switch between the two point objects in every other mouseClicked event.
If paintComponent is called more than once between mouseClicked, you'll end up having oldX and OldY equal to pointX and pointY.
Start drawPoint as false. And the change the names of your variables to save points.
Then you'll want something like this in your click:
public void mouseClicked(MouseEvent mouse){
if(!drawPoint)
{
pointX = mouse.getX();
pointY = mouse.getY();
drawPoint = true;
}
else if(!drawLine)
{
lineX = mouse.getX();
lineY = mouse.getY();
drawLine = true;
}
repaint();
}
And then your paint is simple:
public void paintComponent(Graphics g){
super.paintComponent(g);
if(drawLine){
g.drawLine(pointX, pointY, lineX, lineY);
}
else if(drawPoint){
g.drawOval(pointX-5,pointY-5,10,10);
}
}
It's actually important that in your paint loop, you check drawLine first, and in your mouseClicked you check drawPoint first.
Once you've grasped what's happening here, you can attempt the drawTriangle yourself!
Related
Good afternoon guys, I'm trying to rotate an polygon based on my mouse position, but I can't figure out how to rotate the polygon upwards based on my mouse y. I'm using MouseMotionListener. I've tried to do this until now:
public void mouseMoved(MouseEvent m){
int yantes= m.getY();
while (true){
int y = m.getY();
repaint();
if (y - yantes > 0){
rotation++;
if (rotation > 360) rotation = 0;
repaint();
break;
} else {
rotation--;
if (rotation < 0) rotation = 359;
repaint();
break;
}
}
}
The yantes variable tries to calculate the y before the move, and y the y in after the movement.
In your comment, you wrote:
I am using a book that used Java 6
Are you referring to the book Beginning Java SE 6 Game Programming, Third Edition ?
A java applet is a Container and so is a JPanel, so you can achieve the same results by extending class JPanel rather than extending Applet. That means you can write a regular java application without the need for HTML or a Web browser.
Instead of overriding method paint() in Applet, you need to override method paintComponent() in class JPanel.
The below code demonstrates rotating a square by moving the mouse. It rotates the square around the center point of the square. When you place the mouse inside the JPanel and move it to the left, the square rotates anti-clockwise. When you move the mouse to the right, the square rotates clockwise. If you move the mouse up and down, i.e. parallel to the y-axis, the square does not rotate.
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Rotating extends JPanel implements Runnable, MouseMotionListener {
private int theta;
private int lastX = Integer.MIN_VALUE;
private BasicStroke stroke;
private JFrame frame;
/**
* Creates and returns instance of this class.
*/
public Rotating() {
stroke = new BasicStroke(2.0f);
addMouseMotionListener(this);
setPreferredSize(new Dimension(600, 600));
}
/* Start 'MouseMotionListener' interface methods. */
#Override // javax.swing.event.MouseInputListener
public void mouseDragged(MouseEvent mousEvnt) {
// Do nothing.
}
#Override // javax.swing.event.MouseInputListener
public void mouseMoved(MouseEvent mousEvnt) {
int newX = mousEvnt.getX();
if (lastX == Integer.MIN_VALUE) {
lastX = newX;
}
if (newX < lastX) {
theta--;
if (theta < 0) {
theta = 359;
}
}
else if (newX > lastX) {
theta++;
if (theta > 360) {
theta = 0;
}
}
lastX = newX;
repaint();
}
/* End 'MouseMotionListener' interface methods. */
/* Start 'Runnable' interface methods. */
#Override
public void run() {
showGui();
}
/* End 'Runnable' interface methods. */
#Override // javax.swing.JComponent
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (g instanceof Graphics2D) {
Graphics2D g2d = (Graphics2D) g;
g2d.rotate(Math.toRadians(theta), 300, 300);
g2d.setStroke(stroke);
g2d.drawRect(200, 200, 200, 200);
}
}
private void showGui() {
frame = new JFrame("Rotating");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Rotating());
}
}
Note that when overriding method paintComponent() you nearly always need to first call method paintComponent() in the super class.
I'm trying to draw a shape that is responsive to mouse events,
I thought of extending awt.component that can be registered to event listeners but it ain't working, although it compiles with no errors.
import java.awt.Component;
import java.awt.event.*;
class Ball extends Component{
public Ball(){
this.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
// Some event to be triggered
}
});
}
}
Here's an example I'm testing on applet using appletviewer (for learning purpose):
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Component;
import java.awt.event.*;
public class Test extends Applet{
Ball ball;
public void init(){
ball = new Ball();
}
public void paint(Graphics g){
ball.paint(g);
}
}
class Ball extends Component{
int x, y;
public Ball(){
x = y = 50;
this.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
x += 50;
y += 50;
repaint();
}
});
}
public void paint(Graphics g){
g.fillOval(x, y, 25, 25);
}
}
It only works when the event listener is assigned to the applet as in the following code:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Component;
import java.awt.event.*;
public class Test extends Applet{
Ball ball;
public void init(){
ball = new Ball();
this.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
ball.x += 50;
ball.y += 50;
repaint();
}
});
}
public void paint(Graphics g){
ball.paint(g);
}
}
class Ball extends Component{
int x, y;
public Ball(){
x = y = 50;
}
public void paint(Graphics g){
g.fillOval(x, y, 25, 25);
}
}
This is happening because the repaint method, when called in Ball, only repaints the Ball object, and not the applet screen.
When you add the method in the applet, it repaints the applet screen.
So, you yourself have solved this problem.... You know the answer! I added this answer just for explanation.
Or, you would need to add repaint in both, in Ball to change the position, and in the applet to repaint it.
(The above image is taken from AutoCAD)
My application draws a line on a JPanel using two Point class variables: "startPoint" and "finishPoint".
"startPoint" is set from the first mouse click. Once a starting point has been established the finishPoint variable is set on the position of the cursor. Therefore the line moves/grows dynamically with the mouse movement until the "finishPoint" is finalised by a second mouse click.
During the period where a startPoint has been established and the line dynamically changes I would like to position a JTextField on the line midpoint (well... slightly off-center so it's not obscuring the line) if possible?
I know I'll get shouted at if I try and position a component without the use of a layout manager, but I can't see how a layout manager can help. I would like to position the JTextField using Coordinates. The only way I can think of doing that is to somehow add the textfield into a shape. Beyond that I'm at a loss.
Can someone put me in the right direction?
My code should anybody want to see it:
package Drawing;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
/*
* An extension to P2PLines. A line from point A to point B but with an animation.
*/
public class LineAnimation extends JPanel implements MouseListener, MouseMotionListener
{
private Graphics g;
private Point lineStart = new Point(0, 0);
private Point lineFinish = new Point(0, 0);
private boolean drawing;
int globalX = 0, globalY;
ArrayList<Line2D> edges = new ArrayList<>();
public LineAnimation()
{
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
drawing = false;
}
#Override public void mouseClicked(MouseEvent me) {}
#Override public void mousePressed(MouseEvent me)
{
if (drawing)
{
g = getGraphics(); // Get Graphics content
g.setColor(Color.black);
lineFinish.move(me.getX(), me.getY());
g.drawLine(lineStart.x, lineStart.y, me.getX(), me.getY());
edges.add(new Line2D.Float(lineStart.x, lineStart.y, lineFinish.x, lineFinish.y));
drawing = false;
g.dispose();
}
else
{
lineStart.move(me.getX(), me.getY());
drawing = true;
}
}
#Override public void paintComponent(Graphics g)
{
super.paintComponent(g);
drawPreviousLine((Graphics2D)g);
if (drawing)
{g.drawLine(lineStart.x, lineStart.y, globalX, globalY);}
}
private void drawPreviousLine(Graphics2D g)
{
for(Line2D lines: edges)
{g.draw(lines);}
}
#Override
public void mouseMoved(MouseEvent me)
{
repaint();
globalX = me.getX();
globalY = me.getY();
}
#Override public void mouseReleased(MouseEvent me) {}
#Override public void mouseEntered(MouseEvent me) {}
#Override public void mouseExited(MouseEvent me) {}
#Override public void mouseDragged(MouseEvent me) {}
public static void main(String[] args)
{
JFrame frame = new JFrame("Drawing Frame");
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
LineAnimation drawingFrame = new LineAnimation();
frame.add(drawingFrame);
frame.setVisible(true);
drawingFrame.addMouseListener(drawingFrame);
drawingFrame.addMouseMotionListener(drawingFrame);
}
}
So, I have a program that adds a square to a JPanel and lets the user drag the shape around the panel. What I want to do is be able to click on the bottom-right corner of the shape and resize it as the user drags it. I'm kind of stuck on how to do this. I know that as the user drags it will need to recalculate the rectangle's length and width to make the bottom right corner match where the mouse is. But how can I detect a click on the bottom right edge of the rectangle? Thanks for any help.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
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 {
Shapes shapeList = new Shapes();
Panel panel;
private static final long serialVersionUID = 1L;
public UMLWindow() {
addMenus();
panel = new Panel();
}
public void addMenus() {
getContentPane().add(shapeList);
setTitle("UML Editior");
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
shapeList.addSquare(100, 100);
}
public void loadFile() {
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("."));
int r = chooser.showOpenDialog(this);
if (r == JFileChooser.APPROVE_OPTION) {
}
}
}
// Shapes class, used to draw the shapes on the panel
// as well as implements the MouseListener for dragging
class Shapes extends JPanel {
private static final long serialVersionUID = 1L;
private List<Path2D> shapes = new ArrayList<Path2D>();
int currentIndex;
public Shapes() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
public void addSquare(int width, int height) {
Path2D rect2 = new Path2D.Double();
rect2.append(new Rectangle(getWidth() / 2 - width / 2, getHeight() / 2
- height / 2, width, height), true);
shapes.add(rect2);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(2));
for (Path2D shape : shapes) {
g2.draw(shape);
}
}
class MyMouseAdapter extends MouseAdapter {
private boolean pressed = false;
private Point point;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
for (int i = 0; i < shapes.size(); i++) {
if (shapes.get(i) != null
&& shapes.get(i).contains(e.getPoint())) {
currentIndex = i;
pressed = true;
this.point = e.getPoint();
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (pressed) {
int deltaX = e.getX() - point.x;
int deltaY = e.getY() - point.y;
shapes.get(currentIndex).transform(
AffineTransform.getTranslateInstance(deltaX, deltaY));
point = e.getPoint();
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
pressed = false;
}
}
}
I wrote a couple of things back in the day that might be helpful to you
To start, AreaManager (http://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/ui/shape/) This is kind of what you want, in that it's dealing with Shapes (Area's, actually). There's a dragger class which uses mouse drag, and a resizer class that uses the mouse wheel. But this isn't exactly the user interface you've described.
That user interface for doing changing the cursor and resizing based on the type of cursor and the mouse drag is in Draggable in http://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/ui/drag/. Draggable works with Components that are contained in Containers with the layoutmanager turned off. But it should be not so complicated to adapt to your purposes
I have an assignment that I am doing where I am supposed to implement and design an application that plays a game called catch the creature. Have the creature appear at a random location then disappear and reappear somewhere else. The goal is to "catch" the creature by clicking the creature with a mouse button. Record the number of times the creature is caught.
I need help just displaying the creature which is an JPEG of a pikachu, I have tried a few things but none of them work. Any help is appreciated thank you!
Main Code:
import javax.swing.*;
public class Catch_The_Creature
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Catch the Creature");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Creature panel = new Creature();
JOptionPane.showMessageDialog(frame, "Catch Pikachu!");
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
Creature Code:
import java.awt.*;
import java.util.Random;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class Creature extends JPanel
{
private final int WIDTH = 400, HEIGHT = 300;
private final int DELAY=20, IMAGE_SIZE = 60;
private ImageIcon image;
private int pikachuX, pikachuY;
private int x, y;
private int catchCount=0;
private static Random generator = new Random();
private Timer time;
private ActionListener updater;
private JLabel countLabel;
public Creature()
{
image = new ImageIcon("image/pikachu.jpg");
time = new Timer(DELAY, updater);
addMouseListener ((MouseListener) new MouseClickedListener());
setBackground (Color.green);
setPreferredSize(new Dimension(1900,1000));
time.start();
}
public boolean point(int x, int y)
{
if (x == pikachuX && y == pikachuY)
{
catchCount++;
return true;
}
return false;
}
public int getCatchCount()
{
return catchCount;
}
private class MouseClickedListener extends MouseAdapter
{
public void mouseClicked(MouseEvent event)
{
point(event.getX(), event.getY());
}
}
public void paintComponent(Graphics page)
{
super.paintComponent(page);
page.drawImage(image.getImage(),WIDTH, HEIGHT, null);
page.drawString("Pikachus Captured: " + catchCount, 10, 35);
setFont(new Font("Arial", Font.BOLD,35));
}
public void actionPerformed(ActionEvent event)
{
time.setDelay(1000);
x += pikachuX;
y += pikachuY;
if (x <= 0 || x >= WIDTH-IMAGE_SIZE)
pikachuX = pikachuX * -1;
if (y <= 0 || y >= HEIGHT-IMAGE_SIZE)
pikachuY = pikachuY * -1;
repaint();
}
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
public void mousePressed(MouseEvent arg0) {}
public void mouseReleased(MouseEvent arg0){}
}
It doesn't look like you ever add the ImageIcon to the panel or tell it to paint in the paintComponent() method.
First solution [Preferred]: Add ImageIcon to the panel. In the constructor
super.add(image);
Make sure you use the correct layout (probably a null or absolute layout) and that you update the coordinates of the ImageIcon itself, not just some member variables.
Second solution: Paint the ImageIcon in the paintComponent() method. This is probably discouraged because it goes against the general Swing principles.
Make sure your Image file is in the right directory. If you're running from netbeans or eclipse your file structure should look like this
ProjectRoot
src
bin
image
pikachu.jpeg
Since you are using "image/pikachu.png", you image filder should be a child of the project root folder as that's where the IDE will first search fore your file path
Edit: To draw image. Instead of using ImageIcon, use BufferedImage
try {
BufferedImage image = ImageIO.read("image/pikachu.jpeg");
} catch (Exception ex){
ex.printStackTrace();
}
public void paintComponent(Graphics page)
{
super.paintComponent(page);
page.drawImage(image, x, y, heightYouWant, widthYouWant, this);
page.drawString("Pikachus Captured: " + catchCount, 10, 35);
setFont(new Font("Arial", Font.BOLD,35));
}
All i needed to do was put values on where I wanted the picture to start at in the constructor.
public Creature()
{
image = new ImageIcon ("pikachu.png");
time = new Timer(DELAY, updater);
x = 0;
y = 50;
addMouseListener ((MouseListener) new MouseClickedListener());
setBackground (Color.green);
setPreferredSize(new Dimension(1900,1000));
time.start();
}
While still using an Image Icon and still paint the image in the paint component.
public void paintComponent(Graphics page)
{
super.paintComponent(page);
image.paintIcon (this, page, x, y);
page.drawString("Pikachus Captured: " + catchCount, 10, 35);
setFont(new Font("Arial", Font.BOLD,35));
}