I'm writing a program using Java2D which displays a 3D cube and responds to mouse clicks and movement.
I've got a JFrame containing a JComponent. This JComponent possesses variables holding information like the coordinates of cube vertices and such like. I want to detect mouse clicks and mouse movements on this component, so I've extended the MouseAdapter class and added an instance to the JComponent. So far so good - it detects clicks and everything else fine.
But within the mouseClicked() method that I'm overriding, I want to access the coordinate variables in the JComponent class, so that I can tell, for example, if a mouse click is close to a cube vertex.
I can see a couple of ways I could get round this, for example implementing the MouseListener interface on the JComponent class itself instead, or else making the variables that I want access to static. But isn't there another way that is less of a fudge, which allows me to keep the listener as a separate class?
Even though the Cube looks "3D" it is drawn in 2D so if you have the verticies stored somewhere, and the cube never rotates or translates, couldn't you just use the MouseEvent.getX() and MouseEvent.getY() and compare those values to the stored verticy coordinates?
even if the cube rotated/translated you could just update the stored verticies each time and the above solution should work just fine.
and If you have the cube say in a JPanel, which in turn is inside another JPanel, you just add the "mouseListener" to whatever component you want to listen for the clicks and such.
I'm not sure how the cube works, if it is a predefined class or if you just drew some squares, and then connected them with lines. Either way this should work, because if you just have a Cube object and that type inherits from JComponent you should be able to add a mouseListener directly to it.
Justin, I might be wrong, but I read the question differently - I think Paul's asking how to access the stored co-ordinates, to be able to compare them with the MouseEvent.getX() / getY() results.
If that's right, Paul, then I would do it by giving the MouseAdapter a constructor, which takes your component as an argument. That way, when you instantiate the MouseAdapter, you just pass it the component. If your co-ordinate variables in the component are public, you can access them directly, otherwise, just add accessors (get's).
So, you'd have something like:
Sorry if this wasn't what you were asking...
[Edited to add a few extra comments] [ January 16, 2008: Message edited by: David Payne ]
Joined: Jan 15, 2008
Thanks Justin and David!
David, I think your solution could well work. In the end though, I completed the program by implementing the interfaces MouseInputListener and MouseWheelListener on the class with the variables I needed to access. I'm so new to Java that I wasn't aware you could implement two interfaces on the same class, before I did some research.
In fact the cube does rotate and translate. It doesn't just translate the 2D image, it translates the representation of the cube in 3D space and draws it exactly as you would see it, in perspective. It assumes the viewer's eye is in the middle of the window according to the original window size (and 2200 pixels distance from the screen), so if you resize the window your eye is probably in the wrong place. I'm quite proud of the program so I'm posting the full source code below. It's made up of four classes, so it's probably best if you save them in four separate files, called respectively MyFrame.java, MyComponent.java, Point3D.java and PlanePoint.java. Look for the comments in caps to see where to separate the files. Most of the code isn't properly commented though I'm afraid. I'm sorry if this isn't the accepted place to post long source code. I'm very new here!
I think there are bits of code here that aren't needed (used for testing purposes). I could also save memory by cutting down on variables (lots of variables helped to get it clear in my head), and it may not be the most efficient way of doing things, but the vector maths is pretty sound (I'm a mathematician). You can't beat that feeling you get when you try a piece of code and it works! I'd be interested to see what people think. Please post comments or questions.
Finally here's how you get it to work: Originally you see just the face of the cube that is nearest you. Click and drag anywhere on the cube (or window) to translate it. Roll the mouse wheel to translate the cube towards or away from you. But best of all, click and drag on any of the vertices to rotate the cube. That's the bit that took the most thought and effort!
Joined: Jan 31, 2006
Just had a play with your cube app - most impressive, well done
Joined: Jan 15, 2008
Thanks David! Just finished a fully commented final version that responds correctly to window resizing, and with all the unused variables and methods removed. Give me a shout if anyone wants it.
It's tricky to explain exactly how it works, but parts of it make use of the cross product and dot (also called scalar) product of two vectors. These can be looked up on wikipedia.
For the rotation, imagine the vertices as lying on a sphere with centre the same as the centre of the cube. A point on or near the cube on the screen corresponds to a point (well really two points!) on the sphere. For a mouse drag from a vertex, the program works out how the sphere has been rotated and then rotates all vertices accordingly.