Java input error - java

Okay, I give up. I've been a C++ programmer for a few years, but I tried learning Java because it's a popular language. As I studied I learn a lot, but eventually I started playing around and tried using the input system so that when I click this red diamond shape polygon it turns green, but after several frustrating days... nada. I still only have a red diamond. It's probably something very small but I just can't find it
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Vici extends Applet
{
/**
*
*/
private static final long serialVersionUID = 1L;
private Space castle;
public Vici()
{
castle = new Space();
castle.addMouseListener(new SpaceInput());
}
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
int width = getSize().width;
int height = getSize().height;
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, width, height);
castle.paint(g2d);
}
class SpaceInput implements MouseListener
{
public void mouseEntered(MouseEvent m) { }
public void mouseExited(MouseEvent m) { }
public void mouseReleased(MouseEvent m)
{
switch(m.getButton())
{
case MouseEvent.BUTTON1:
castle.setColor(Color.GREEN);
castle.repaint();
repaint();
}
}
public void mouseClicked(MouseEvent m)
{
switch(m.getButton())
{
case MouseEvent.BUTTON1:
castle.setColor(Color.GREEN);
castle.repaint();
repaint();
}
}
public void mousePressed(MouseEvent m)
{
switch(m.getButton())
{
case MouseEvent.BUTTON1:
castle.setColor(Color.GREEN);
castle.repaint();
repaint();
}
}
}
}
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class Space extends Canvas
{
private Polygon poly;
private Color c;
private int[] polyX = { 0, 24, 0, -24 };
private int[] polyY = { 24, 0, -24, 0 };
public void init()
{
poly = new Polygon( polyX, polyY, polyX.length);
c = Color.red;
}
Space()
{
init();
}
void setColor(Color c)
{
this.c = c;
}
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
AffineTransform identity = new AffineTransform();
g2d.setTransform(identity);
g2d.translate(100, 100);
g2d.setColor(c);
g2d.fill(poly);
}
public void update( Graphics g )
{
paint( g );
}
}

I got rid of the extraneous "SpaceInput" class and added the mouse listener to the applet (not "castle"). And everything worked :)
public class Vici extends Applet implements MouseListener
{
private static final long serialVersionUID = 1L;
private Space castle;
public Vici()
{
castle = new Space();
// castle.addMouseListener(this);
addMouseListener (this);
}
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
int width = getSize().width;
int height = getSize().height;
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, width, height);
castle.paint(g2d);
}
public void mouseEntered(MouseEvent m) {
System.out.println ("mouse entered...");
}
public void mouseExited(MouseEvent m) {
System.out.println ("mouse mouseExited...");
}
public void mouseReleased(MouseEvent m)
{
System.out.println ("mouse mouseReleased...");
switch(m.getButton())
{
case MouseEvent.BUTTON1:
castle.setColor(Color.GREEN);
castle.repaint();
repaint();
}
}
public void mouseClicked(MouseEvent m)
{
System.out.println ("mouse mouseClicked...");
switch(m.getButton())
{
case MouseEvent.BUTTON1:
castle.setColor(Color.GREEN);
castle.repaint();
repaint();
}
}
public void mousePressed(MouseEvent m)
{
System.out.println ("mouse mousePressed...");
switch(m.getButton())
{
case MouseEvent.BUTTON1:
castle.setColor(Color.GREEN);
castle.repaint();
repaint();
}
}
}

#Chaz Bertino -
I think the entire problem was using "Canvas" (obsolete since Java 1.2) vs "JPanel" (replaces the old "Panel" and "Canvas" combined since J2SE 2.0).
Here's another example that behaves like you expected. The main differences is that it uses a Swing JPanel instead of an AWT Canvas:
import java.applet.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class HelloAWT extends Applet {
private Diamond diamond;
private static final int height = 350;
private static final int width = 350;
public void init () {
setBackground(Color.green);
resize (width, height);
diamond = new Diamond ();
diamond.init (Color.green);
add(diamond);
}
public void paint(Graphics g)
{
System.out.println ("HelloAWT#paint()...");
String msg = "Hello AWT!";
g.setFont(new Font ("Arial", Font.BOLD, 18));
FontMetrics fm = g.getFontMetrics ();
int x = (getWidth() - fm.stringWidth(msg)) / 2;
int y = (getHeight() / 2) + 50;
g.drawString(msg, x, y);
diamond.repaint ();
}
}
class Diamond extends JPanel implements MouseListener {
private static final int height = 100;
private static final int width = 100;
private Color c = Color.red;
private Color bkgd;
private int[] polyX;
private int[] polyY;
private Polygon poly;
public void init (Color bkgd) {
System.out.println ("Diamond#init(): bkgd=" + bkgd + "...");
setPreferredSize (new Dimension(width, height));
this.bkgd = bkgd;
polyX = new int[] { width/2, width, width/2, 0 };
polyY= new int[] { 0, height/2, height, height/2 };
System.out.println ("polyX=" + polyX[0] + "," + polyX[1] + "," + polyX[2] + "," + polyX[3] + "...");
System.out.println ("polyY=" + polyY[0] + "," + polyY[1] + "," + polyY[2] + "," + polyY[3] + "...");
poly = new Polygon( polyX, polyY, polyX.length);
addMouseListener (this);
}
public void paint(Graphics g)
{
System.out.println ("Diamond()#paint(), bounds=" + getHeight() + "," + getWidth () + "...");
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(bkgd);
g2d.fillRect(0, 0, width, height);
g2d.setColor(c);
g2d.fill(poly);
}
public void mouseEntered(MouseEvent m) {
System.out.println ("mouseEntered()...");
}
public void mouseExited(MouseEvent m) {
System.out.println ("mouseExited()...");
}
public void mouseReleased(MouseEvent m) {
System.out.println ("mouseReleased()...");
}
public void mouseClicked(MouseEvent m) {
System.out.println ("mouseClicked(), current color=" + c + "...");
if (c == Color.red)
c = Color.blue;
else
c = Color.red;
repaint ();
}
public void mousePressed(MouseEvent m) {
System.out.println ("mousePressed()...");
}
}

Related

How do I rotate objects/images independently in Java?

I am trying to have a series of rectangles rotating about their respective centres and moving to the right, but since the plane contains all the rectangles, all the rectangles rotate in unison about the centre of the latest added rectangle instead of independently around their respective centres. Here are the codes:
The main program:
import java.awt.Graphics2D;
import java.util.ArrayList;
public class Rectangles {
public static final int SCREEN_WIDTH = 400;
public static final int SCREEN_HEIGHT = 400;
public static void main(String[] args) throws Exception {
Rectangles game = new Rectangles();
game.play();
}
public void play() {
board.setupAndDisplay();
}
public Rectangles() {
board = new Board(SCREEN_WIDTH, SCREEN_HEIGHT, this);
rectangle_2 = new Rectangle_2();
rectangles = new ArrayList<Rectangle_2>();
}
public void drawRectangles(Graphics2D g, float elapsedTime) {
ticks++;
if (ticks % 4000 == 0) {
Rectangle_2 rectangle = new Rectangle_2();
rectangles.add(rectangle);
}
rotateRectangles(g);
drawRectangles(g);
moveRectangles(elapsedTime);
for (int i = 0; i < rectangles.size(); i++) {
Rectangle_2 rectangle = rectangles.get(i);
if (rectangle.getX() < -75) {
rectangles.remove(i);
i--;
}
}
}
public void drawRectangles(Graphics2D g) {
for (Rectangle_2 rectangle: rectangles) {
rectangle.drawRectangle(g);
}
}
public void rotateRectangles(Graphics2D g) {
for (Rectangle_2 rectangle: rectangles) {
rectangle.rotateRectangle(g);
}
}
public void moveRectangles(float elapsedTime) {
for (Rectangle_2 rectangle: rectangles) {
rectangle.move(10 * elapsedTime);
}
}
private Board board;
private Rectangle_2 rectangle_2;
private int ticks = 0;
private ArrayList<Rectangle_2> rectangles;
}
The rectangle class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Rectangle_2 {
public Rectangle_2() {
x = 0;
y = 200;
rectangle = new Rectangle((int) x, (int) y, 25, 25);
}
public void drawRectangle(Graphics2D g) {
g.setColor(Color.red);
g.draw(rectangle);
}
public void rotateRectangle(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
angle += 0.001;
g2.rotate(angle, rectangle.getX() + rectangle.getWidth() / 2, rectangle.getY() + rectangle.getHeight() / 2);
g2.setColor(Color.red);
}
public void move(float elapsedTime) {
x = x + elapsedTime;
rectangle.setLocation((int) x, (int) y);
}
public boolean collides(Rectangle r) {
return r.intersects(rectangle);
}
#Override
public String toString() {
return "Pipe [x = " + x + ", y = " + y + ", rectangle = " + rectangle + "]";
}
public Rectangle getRectangle() {
return rectangle;
}
public double getX() {
return x;
}
private double x;
private double y;
private double angle = 0;
private Rectangle rectangle;
}
The board class where the animation takes place:
import java.awt.*;
import javax.swing.*;
public class Board extends JPanel {
private static final long serialVersionUID = 1L;
public Board(int width_, int height_, Rectangles simulator_) {
width = width_;
height = height_;
game = simulator_;
lastTime = -1L;
}
public void setupAndDisplay() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(this));
f.setSize(width, height);
f.setLocation(200, 200);
f.setVisible(true);
this.setFocusable(true);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
boolean first = (lastTime == -1L);
long elapsedTime = System.nanoTime() - lastTime;
lastTime = System.nanoTime();
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
g.setColor(Color.white);
game.drawRectangles((Graphics2D) g, (first ? 0.0f : (float) elapsedTime / 1e9f));
repaint();
}
private int width;
private int height;
private long lastTime;
private Rectangles game;
}
Please note the rectangle takes a couple of seconds to appear because of the delay implemented. Thank you :).
The Graphics context is a shared resource, that is, during a single paint cycle, all the components get the same Graphics context. Any changes you make to the Graphics context are also maintained (or compound in the case of same transformations). So this means, each time you call Graphics#rotate, you are actually compounding any of the previous rotations which might have been executed on it.
You need to change you code in two ways...
You need a independent update cycle, independent of the paint cycle
Create a local copy of the Graphics context BEFORE you apply any transformations
For example...
Rectangles becomes the main driver/engine. It's responsible for managing the entities and updating them each cycle. Normally, I'd use some kind of interface that described the functionality that other case might be able to use, but you get the idea
public class Rectangles {
public static void main(String[] args) throws Exception {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Rectangles game = new Rectangles();
game.play();
}
});
}
public void play() {
Board board = new Board(this);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(board);
f.pack();
f.setLocation(200, 200);
f.setVisible(true);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateRectangles();
board.repaint();
lastTime = System.nanoTime();
}
});
timer.start();
}
public Rectangles() {
rectangle_2 = new Rectangle_2();
rectangles = new ArrayList<Rectangle_2>();
}
protected void updateRectangles() {
boolean first = (lastTime == -1L);
double elapsedTime = System.nanoTime() - lastTime;
elapsedTime = (first ? 0.0f : (float) elapsedTime / 1e9f);
ticks++;
if (ticks <= 1 || ticks % 100 == 0) {
Rectangle_2 rectangle = new Rectangle_2();
rectangles.add(rectangle);
}
rotateRectangles();
moveRectangles(elapsedTime);
for (int i = 0; i < rectangles.size(); i++) {
Rectangle_2 rectangle = rectangles.get(i);
if (rectangle.getX() < -75) {
rectangles.remove(i);
i--;
}
}
}
public void drawRectangles(Graphics2D g) {
for (Rectangle_2 rectangle : rectangles) {
rectangle.drawRectangle(g);
}
}
protected void rotateRectangles() {
for (Rectangle_2 rectangle : rectangles) {
rectangle.rotateRectangle();
}
}
protected void moveRectangles(double elapsedTime) {
for (Rectangle_2 rectangle : rectangles) {
rectangle.move(10 * elapsedTime);
}
}
private long lastTime = -1L;
private Rectangle_2 rectangle_2;
private int ticks = 0;
private ArrayList<Rectangle_2> rectangles;
}
Board becomes nothing more then a surface onto which the entities can be rendered
public class Board extends JPanel {
public Board(Rectangles engine) {
game = engine;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
game.drawRectangles((Graphics2D) g);
}
private Rectangles game;
}
And Rectangle_2 is a simple container of information which knows how to paint itself when given the chance. You will note the movement and rotation methods just update the state, they do nothing else.
drawRectangle first creates a copy of the supplied Graphics2D context, before it applies it's changes and renders the rectangle, when done, it calls dispose to dispose of the copy
public class Rectangle_2 {
public Rectangle_2() {
x = 0;
y = 200;
rectangle = new Rectangle((int) x, (int) y, 25, 25);
}
public void drawRectangle(Graphics2D g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.rotate(angle, rectangle.getX() + rectangle.getWidth() / 2, rectangle.getY() + rectangle.getHeight() / 2);
g2.setColor(Color.red);
g2.draw(rectangle);
g2.dispose();
}
public void rotateRectangle() {
angle += 0.001;
}
public void move(double elapsedTime) {
x = x + elapsedTime;
rectangle.setLocation((int) x, (int) y);
}
public boolean collides(Rectangle r) {
return r.intersects(rectangle);
}
#Override
public String toString() {
return "Pipe [x = " + x + ", y = " + y + ", rectangle = " + rectangle + "]";
}
public Rectangle getRectangle() {
return rectangle;
}
public double getX() {
return x;
}
private double x;
private double y;
private double angle = 0;
private Rectangle rectangle;
}

Trigger MouseListener when pressing on my JComponent, even if it is transformed by an AffineTransform

I am trying to add a MouseListener to my custom JComponent. I just want the MouseListener to be triggered when pressing withing the bounds of the circle (the JComponent's painting method draws a circle). I have tried with the below code but I just cannot get it to work (loook especially in the mousePressed method). How can I tackle this problem?
The SSCCE:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class AffineTransformTest {
private static TransformingCanvas canvas;
public static void main(String[] args) {
JFrame frame = new JFrame();
canvas = new AffineTransformTest.TransformingCanvas();
TranslateHandler translater = new TranslateHandler();
canvas.addMouseListener(translater);
canvas.addMouseMotionListener(translater);
canvas.addMouseWheelListener(new ScaleHandler());
frame.setLayout(new BorderLayout());
frame.getContentPane().add(canvas, BorderLayout.CENTER);
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
private static class TransformingCanvas extends JComponent {
private double translateX;
private double translateY;
private double scale;
TransformingCanvas() {
translateX = 0;
translateY = 0;
scale = 1;
setOpaque(true);
setDoubleBuffered(true);
}
#Override
public void paint(Graphics g) {
AffineTransform tx = new AffineTransform();
tx.translate(translateX, translateY);
tx.scale(scale, scale);
Graphics2D ourGraphics = (Graphics2D) g;
ourGraphics.setColor(Color.WHITE);
ourGraphics.fillRect(0, 0, getWidth(), getHeight());
ourGraphics.setTransform(tx);
ourGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ourGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
ourGraphics.setColor(Color.BLACK);
ourGraphics.fillOval(50, 50, 50, 50);
}
}
private static class TranslateHandler implements MouseListener,
MouseMotionListener {
private int lastOffsetX;
private int lastOffsetY;
public void mousePressed(MouseEvent e) {
lastOffsetX = e.getX();
lastOffsetY = e.getY();
double width = canvas.scale * 50;
double height = canvas.scale * 50;
double x = (AffineTransformTest.canvas.getWidth() - width) / 2;
double y = (AffineTransformTest.canvas.getHeight() - height) / 2;
Rectangle2D.Double bounds = new Rectangle2D.Double(x, y, width, height);
System.out.println(bounds + " " + e.getPoint());
if (bounds.contains(e.getPoint())) {
System.out.println("Click!");
}
}
public void mouseDragged(MouseEvent e) {
int newX = e.getX() - lastOffsetX;
int newY = e.getY() - lastOffsetY;
lastOffsetX += newX;
lastOffsetY += newY;
canvas.translateX += newX;
canvas.translateY += newY;
canvas.repaint();
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
}
private static class ScaleHandler implements MouseWheelListener {
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
canvas.scale += (.1 * e.getWheelRotation());
canvas.scale = Math.max(0.00001, canvas.scale);
canvas.repaint();
}
}
}
}
Here is the code. Some quick notes, there is still some debug in the code, and replace calls to LOGGER object with System.out.println().
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.util.logging.Logger;
import javax.swing.JComponent;
import javax.swing.event.MouseInputListener;
public abstract class LCARSComponent extends JComponent implements MouseInputListener {
/**
* A reference to the global Logger object.
*/
protected final static Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
protected int x;
protected int y;
protected int w;
protected int h;
protected double scaleFactor = 1.0;
protected Area area;
protected Area scaledArea;
protected int style;
protected Color color;
protected AffineTransform renderingTransform;
protected ActionListener actionListener;
public LCARSComponent(Container parent, int x, int y, int w, int h, int style) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.style = style;
setBounds(x,y,w,h);
addMouseListener(this);
}
#Override
protected void paintComponent(Graphics g) {
/**
* First, paint the background if the component is opaque. Required when
* JComponent is extended, and the paintCompnent() method is overridden.
*/
if(isOpaque()) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
/**
* Create a Graphics2D object so we can use Java 2D features.
*/
Graphics2D g2d = (Graphics2D) g.create();
/**
* Set the anti aliasing rendering hint and the color to draw with.
*/
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(color);
scaleComponent();
/**
* Draw the Area object of the LCARS component, and fill it.
*/
g2d.draw(scaledArea);
g2d.fill(scaledArea);
g2d.drawRect(scaledArea.getBounds().x, scaledArea.getBounds().y, scaledArea.getBounds().width, scaledArea.getBounds().height);
/**
* Clean up when the method has completed by disposing the Graphics2D object that was created.
*/
g2d.dispose();
}
protected void scaleComponent() {
double sw = (double)getParent().getWidth() / (double)getParent().getPreferredSize().width;
double sh = (double)getParent().getHeight() / (double)getParent().getPreferredSize().height;
LOGGER.info("scaledWidth = " + sw);
LOGGER.info("scaledHeight = " + sh);
double scaleFactor;
if(sh < sw) {
scaleFactor = sh;
}
else {
scaleFactor = sw;
}
LOGGER.info("scaleFactor = " + scaleFactor);
if(scaleFactor != this.scaleFactor) {
this.scaleFactor = scaleFactor;
scaledArea = new Area(area);
renderingTransform = new AffineTransform();
renderingTransform.scale(scaleFactor, scaleFactor);
scaledArea.transform(renderingTransform);
}
setBounds((int)(this.x*scaleFactor), (int)(this.y*scaleFactor), this.getWidth(), this.getHeight());
}
public Point screenToComponent(Point pt) {
if(renderingTransform == null) {
Graphics2D g2d = (Graphics2D)(this.getParent().getGraphics());
renderingTransform = g2d.getTransform();
}
Point2D pt2d = renderingTransform.transform(pt,null);
LOGGER.info("mouse click: " + pt.getX() + ", " + pt.getY() + " -- " + pt2d.getX() + ", " + pt2d.getY());
return new Point((int)Math.round(pt2d.getX()), (int)Math.round(pt2d.getY()));
}
public void setActionListener(ActionListener actionListener) {
this.actionListener = actionListener;
}
#Override
public void mouseClicked(MouseEvent e) {
Point pt = e.getPoint();
LOGGER.info("mouseClicked: " + this.getName() + " - " + pt.getX() + ", " + pt.getY());
if(area.contains(e.getPoint())) {
if(actionListener != null) {
actionListener.actionPerformed(new ActionEvent(e.getSource(), e.getID(), e.paramString()));
}
if(color.equals(Color.black))
color = Color.blue;
else
color = Color.black;
this.repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
if(area.contains(e.getLocationOnScreen()))
System.out.println("mousePressed()...");
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
if(area.contains(e.getLocationOnScreen()))
System.out.println("mouseReleased()...");
}
#Override
public void mouseEntered(MouseEvent e) {
Point pt = e.getPoint();
// TODO Auto-generated method stub
System.out.println("mouseEntered()...");
LOGGER.info("mouseEntered: " + this.getName() + " - " + pt.getX() + ", " + pt.getY());
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
Point pt = e.getPoint();
System.out.println("mouseExited()...");
LOGGER.info("mouseExited: " + pt.getX() + ", " + pt.getY());
}
#Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("mouseDragged()...");
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("mouseMoved()...");
}
}
Two points:
First, I would use a Shape or Area object and use its .contains() method. Bounds is always a Rectangle that surrounds your entire shape. Also, not sure why you are creating a bounds rectangle when you can simply use the setBounds() method of your JComponent.
Second, the bounds of a JComponent can be translated, but I haven't found anything built-in to scale them. Though, you can change the size dynamically. I am working on an identical problem. Right now I am considering dynamically changing the bounds when my JComponent scales. I am trying to understand correlation between screen coordinates and JComponent coordinates. The mouse coordinates always seem to be in unscaled frame/screen coordinates (might be an artifact of the full screen mode I am using. The solutions I have seen paint everything in a JPanel and do not use discrete JComponents to solve the scaling problem. The code is a little hard to follow, and not particularly modular, but it does work.
In any case, I am sure it can ultimately be done. It is simply a matter of getting the math right. I will post the code for the scalable JComponent extension when I have finished it and it works reliably. Hope this helps a little.

Java - MouseListener Action Event in paintComponent

Here i have a code which draws a rectangle on the mouseClicked position using the paintComponent.I can get the output message but anything related to graphics and .draw() wont work.
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public final class testclass extends JFrame {
static JPanel p;
Timer t;
int x = 1;
int y = 1;
int xspeed = 1;
int yspeed = 1;
public testclass() {
initComponents();
this.setBounds(100, 300, 500, 500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.start();
this.add(p);
}
public void initComponents() {
final ActionListener action = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println("Hello!");
p.repaint();
}
};
t = new Timer(50, action);
p = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D gD = (Graphics2D) g;
moveBALL();
gD.drawOval(x, y, 25, 25);
p.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {
System.out.println("a");
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("b");
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println("c");
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("d");
}
#Override
public void mouseClicked(MouseEvent e) {
gD.drawRect(e.getX(), e.getY(), 10, 60);
gD.setColor(Color.green);
System.out.println("clicked");
}
});
}
void moveBALL() {
x = x + xspeed;
y = y + yspeed;
if (x < 0) {
x = 0;
xspeed = -xspeed;
} else if (x > p.getWidth() - 20) {
x = p.getWidth() - 20;
xspeed = -xspeed;
}
if (y < 0) {
y = 0;
yspeed = -yspeed;
} else if (y > p.getHeight() - 20) {
y = p.getHeight() - 20;
yspeed = -yspeed;
}
}
};
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new testclass().setVisible(true);
p.setBackground(Color.WHITE);
}
});
}
}
What is the proper way to implement a mouseListener() in this program?
Thanks.
Some suggestions on current code:
Watch class naming scheme i.e testclass should be TestClass or even better Test (but thats nit picking). All class names begin with capital letter and each new word thereafter is capitalized.
Dont extend JFrame unnecessarily.
Dont call setBounds on JFrame rather use appropriate LayoutManager and/or override getPreferredSize() of JPanel and return dimensions which fits its content.
Always call pack() on JFrame before setting it visible (taking above into consideration).
Use MouseAdapter vs MouseListener
Dont call moveBall() in paintComponent rather call it in your Timer which repaints the screen, not only slightly better design but we also should not do possibly long running tasks in paint methods.
As for your problem I think your logic is a bit skewed.
One approach would see the Rectangle (or Rectangle2D) get replaced by its own custom class (which will allow us to store attributes like color etc). Your ball would also have its own class which has the method moveBall() and its attributes like x and y position etc. On every repaint() your JPanel would call the method to move the ball, the JPanel itself could wrap the moveBall() in its own public method which we could than call from the timer which repaints the screen.
Here is an example of your code with above fixes implemented (please analyze it and if you have any questions let me know):
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.*;
public class Test {
private MyPanel p;
private Timer t;
public Test() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents();
frame.add(p);
frame.pack();
frame.setVisible(true);
t.start();
}
private void initComponents() {
final ActionListener action = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
p.moveEntities();//moves ball etc
p.repaint();
}
};
t = new Timer(50, action);
p = new MyPanel();
p.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
p.addEntity(e.getX(), e.getY(), 10, 50, Color.GREEN);
System.out.println("clicked");
}
});
p.setBackground(Color.WHITE);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class MyPanel extends JPanel {
int width = 300, height = 300;
ArrayList<MyRectangle> entities = new ArrayList<>();
MyBall ball = new MyBall(10, 10, 25, 25, Color.RED, width, height);
void addEntity(int x, int y, int w, int h, Color c) {
entities.add(new MyRectangle(x, y, w, h, c));
}
void moveEntities() {
ball.moveBALL();
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(ball.getColor());
g2d.fillOval((int) ball.x, (int) ball.y, (int) ball.width, (int) ball.height);
for (MyRectangle entity : entities) {
g2d.setColor(entity.getColor());
g2d.fillRect((int) entity.x, (int) entity.y, (int) entity.width, (int) entity.height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
}
class MyRectangle extends Rectangle2D.Double {
Color color;
public MyRectangle(double x, double y, double w, double h, Color c) {
super(x, y, w, h);
color = c;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
class MyBall extends Ellipse2D.Double {
int xspeed = 1;
int yspeed = 1;
Color color;
private final int maxWidth;
private final int maxHeight;
public MyBall(double x, double y, double w, double h, Color c, int maxWidth, int maxHeight) {
super(x, y, w, h);
color = c;
this.width = w;//set width and height of Rectangle2D
this.height = h;
//set max width and height ball can move
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
void moveBALL() {
x = x + xspeed;
y = y + yspeed;
if (x < 0) {
x = 0;
xspeed = -xspeed;
} else if (x > maxWidth - ((int) getWidth() / 2)) {// i dont like hard coding values its not good oractice and resuaibilty is diminshed
x = maxWidth - ((int) getWidth() / 2);
xspeed = -xspeed;
}
if (y < 0) {
y = 0;
yspeed = -yspeed;
} else if (y > maxHeight - ((int) getHeight() / 2)) {
y = maxHeight - ((int) getHeight() / 2);
yspeed = -yspeed;
}
}
}
First of all the paint component is called every time swing needs to redraw the component.
And you are adding a new instance of mouse listener to the panel every time the paint is called.
Just move the line
p.addMouseListener(new MouseListener() {...}
out of the paint component, preferably after the initialization of the panel.
default template is
JPanel p = new JPanel(){
#Override
public void paintComponent(Graphics g) {
}
};
p.addMouseListener(new MouseListener() or new MouseAdapter()
//Your overridden methods
});
Hope this helps.

Rotating an image nuisance

Alright guys i'm trying to make an Asteroids type game and I need to be able to rotate an image around so that the front of the ship follows my mouse. I have looked for a few hours now and have found a couple of things but none that satisfy my needs.
If anyone knows how to do this please share!
thanks in advance
here is the code i have now
package Asteroids;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class Asteroids extends JFrame implements Runnable, MouseListener,
MouseMotionListener, KeyListener {
private Image dbImage;
private Graphics dbg;
int x, y, mx, my;
int a, b, c, degree;
double scale = 1.0;
ImageIcon shipIcon = new ImageIcon(this.getClass().getClassLoader()
.getResource("AstroidsShip.png"));
Image ship = shipIcon.getImage();
public static void main(String[] args) {
Asteroids frame = new Asteroids();
Thread thread = new Thread(frame);
thread.start();
}
public Asteroids() {
addMouseListener(this);
addMouseMotionListener(this);
addKeyListener(this);
setTitle("Astroids");
setSize(500, 500);
setBackground(Color.WHITE);
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
x = getWidth() / 2 - 10;
y = getHeight() - getHeight() / 2;
}
public void run() {
while (true) {
try {
} catch (Exception e) {
}
}
}
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
g.drawString("POS: " + mx + ", " + my, 10, 40);
System.out.println(getAngle());
g.drawImage(ship, x, y, this);
g.drawLine(x + 12, y + 10, mx, my);
repaint();
}
public int getAngle() {
a = mx - (x + 12);
b = (y - 10) - my;
return degree = (int) Math.toDegrees(Math.atan2(b, a));
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
mx = e.getX();
my = e.getY();
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
You can use Java2D. It allows to rotate the image and do a lot lot of other cool operations on the image. It also have got hardware acceleration support (through DirectX or OpenGL).
Java2D is built-in in JRE.
Inside your paintComponent method, you could make the code look like:
public void paintComponent(Graphics g) {
g.drawString("POS: " + mx + ", " + my, 10, 40);
System.out.println(getAngle());
Graphics2D g2d = new (Graphics2D)g;
g2d.translate(X, Y);
g2d.rotate(DEGREES);
g2d.drawImage(ship, 0, 0, WIDTH, HEIGHT, this);
g.drawLine(x + 12, y + 10, mx, my);
repaint();
}
For more complex use, you could create a method with all of your ship drawing calculations:
public void paintComponent(Graphics g) {
g.drawString("POS: " + mx + ", " + my, 10, 40);
System.out.println(getAngle());
drawShip(g);
g.drawLine(x + 12, y + 10, mx, my);
repaint();
}
public void drawShip(Graphics g){
Graphics2D g2d = (Graphics2D)g;
g2d.translate(X, Y);
g2d.rotate(DEGREES);
g2d.drawImage(ship, 0, 0, WIDTH, HEIGHT, this);
}
One way is to use a rotate instance from one of the methods of AffineTransform that accepts anchors for the X,Y co-ordinates.

problem displaying mouse coordinates on the screen in java

I'm trying to display mouse coordinates (math coordinates) in my JPanel , but i get each coordinates on top of the other ,can' figure out why .
here's my code :
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.applet.*;
import javax.swing.JPanel;
import javax.swing.event.MouseInputAdapter;
public class drawarea extends JPanel {
int n;
private Point mouseCoords = null;
int UNIT = 20;
drawarea() {
super();
setBackground(Color.white);
addMouseMotionListener(new MouseInputAdapter() {
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
mouseCoords = new Point(e.getX(), e.getY());
repaint();
}
/**
* #see java.awt.event.MouseListener#mouseExited(MouseEvent)
*/
public void mouseExited(MouseEvent e) {
super.mouseExited(e);
mouseCoords = null;
repaint();
}
});
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
}
public void paint(Graphics g) {
//draw axis x and y
g.setColor(Color.red);
g.drawLine(0, r.height / 2, r.width, r.height / 2);
g.drawLine(r.width / 2, 0, r.width / 2, r.height);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
dessinBoule(g2);
}
private void dessinBoule(Graphics2D g) {
// if mouse isnt inside the ara where
// i want the coordinates to bes displayed
if (mouseCoords == null) {
return;
}
g.setColor(Color.BLACK);
int decPolice = 15;
g.drawString("x = " + getFormatedString("" + mouseCoords.x)
+ " , y = " + getFormatedString("" + mouseCoords.y), 2, 15);
}
private String getFormatedString(String s) {
if (s.length() > 4) {
return s.substring(0, 3);
}
return s;
}
}
thanks.
You're drawing on your graphics area, so g.drawString(...) draws a string on top of what is already there. You must either erase what is there first, by drawing a rectangle in the background colour, or use a separate component that you can manage with a separate paint(...) method.
An example of #richj's suggestion is shown below. Note that in Swing you should override paintComponent(). Also, the implementation of MouseInputAdapter is empty, so you don't need to invoke super().
import java.awt.*;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
public class DrawArea extends JPanel {
private Point mouseCoords = new Point();
DrawArea() {
super();
this.setPreferredSize(new Dimension(320, 240));
setBackground(Color.white);
addMouseMotionListener(new MouseInputAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
mouseCoords = e.getPoint();
repaint();
}
#Override
public void mouseExited(MouseEvent e) {
mouseCoords = null;
repaint();
}
});
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.clearRect(0, 0, getWidth(), getHeight());
g2.setColor(Color.red);
if (!(mouseCoords == null)) {
g2.drawString(mouseCoords.toString(), 10, getHeight() - 10);
}
}
private static void create() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new DrawArea());
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
create();
}
});
}
}

Categories