Simple question – why wouldn't an object move if it's the object of .move() inside onMouseMoved()? I'm trying to write Breakout as part of the Stanford 106A exercises on iTunes U and for some reason I can't get the paddle to track the mouse. I'm a java noob, so I'm sure it's something really simple. Could someone please take a look at this code?
/** Runs the Breakout program. */
public void run() {
setupBoard();
addMouseListeners();
}
/** Provides the initial GCanvas and blocks for the game */
private void setupBoard(){
this.setSize(APPLICATION_WIDTH,APPLICATION_HEIGHT);
addBricks();
paddle = new GRect(PADDLE_WIDTH, PADDLE_HEIGHT);
add(paddle, WIDTH/2-PADDLE_WIDTH/2,HEIGHT-PADDLE_Y_OFFSET);
}
public void MouseMoved(MouseEvent e){
paddle.move(e.getX()-paddle.getX(), 0);
}
private GRect paddle;
}
I'm not sure if having paddle be an instance variable is appropriate in this case, since its "value" doesn't change (the paddle's always the paddle), but if I just define it as a new GRect within setupBoard I get an error in the MouseMoved() method.
Your class that has the mouseMoved() method needs to implement the interface MouseMotionListener, and add the motion listener. Moreover, the event handler is mouseMoved() not MouseMoved(). So, e.g.:
public class Game extends JPanel implements MouseMotionListener {
public void run() {
addMouseMotionListener(this);
//...
}
public void mouseMoved(MouseEvent e) {
paddle.move(e.getX()-paddle.getX(), 0);
}
//...
};
Related
I am very new to Java, and I wanted to try to make a thing in BlueJ that requires BlueJ to know when the mouse is clicked, and to be able to determine the mouse's coordinates on the x,y plane.
In my class where I code, I have seen some imported class and things like Scanner and Graphics, so it might be something along those lines, but I am not sure.
I just mainly need
The thing to import (if it is a thing that needs to be imported)
How to make it tell if the mouse is clicked
How to make it be able to tell me the x, y position of the mouse when asked (like, what class method would I have to refer to to find this)
After I have that, I will work with that to try to make my program. Thank you!
EDIT: Upon request, here is my attempt
java.awt.event.MouseAdapter
public class main
{
MouseAdapter test = new MouseAdapter();
}
public void mouseMoved(test e)
{
System.out.println("hey your mouse moved");
}
I am clearly doing something horribly wrong
One way to achieve your goal would be to use java swing. The following code will print out a statement if the mouse is moved inside the created window:
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame jFrame = new JFrame();
jFrame.setSize(720,480);
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
jFrame.getContentPane().addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent mouseEvent) {
System.out.println("STUFF");
}
#Override
public void mouseMoved(MouseEvent mouseEvent) {
System.out.println("STUFF");
}
});
});
}
This is not an ideal solution but I hope it helps you to look in the right direciton.
I want to draw a ball on a JPanel. But the Ball object must not depend on the GUI. It has to change it's position independently. So my Ball class is:
class Ball implements Runnable{
int x=0;
#Override
public void run() {
while(true){
x+=10;
x%=100;
}
}
}
My JPanel is:
class Plane extends JPanel{
Ball b;
Plane(Ball b){
this.b=b;
}
#Override
public void paintComponent(Graphics g){
g.fillArc(b.x, 10, 10,10,0,360);
}
}
Now how can I change my GUI when b's position change. I can't keep instance of Plane in Ball class. Should I use Swing.Timer class inside Plane class to update GUI or should I make Plane class also a thread? Is there any better way to do this?
I would suggest to separate model (Ball) from Thread where the Ball is changed. Your thread can keep a reference to panel where getBall() method exists and use the method to change Ball's position. Then the thread can use
SwingUtilities.invokeAndWait(
runnable which update ball and calls panel.repaint() to reflect the ball changes
)
the the thread can just sleep for 10msec
You could always add a little indirection
interface BallUpdateListener {
public void ballUpdated (Ball b);
}
class Plane extends JPanel implements BallUpdateListener {
Ball b;
Plane(Ball b){
this.b=b;
this.b.addListener (this);
}
#Override
public void paintComponent(Graphics g){
g.fillArc(b.x, 10, 10,10,0,360);
}
}
class Ball implements Runnable{
int x=0;
List<BallUpdateListener> listeners = new ArrayList<> ();
#Override
public void run() {
while(true){
x+=10;
x%=100;
for (BallUpdateListener listener : listeners) {
ballUpdated (this);
}
}
}
public void addListener (BallUpdateListener listener) {
listeners.add (listener);
}
}
Keep in mind this puts the control of updates in the hands of the Ball class. For some problems, this is the right kind of approach. For others, this is a decidedly bad approach. It really depends on your constraints.
I'm trying to call repaint from another class. But it does not work. I have to draw on a frame.
public class Tester extends JFrame{
public static dtest d ;
public static void main(String[] args) {
Tester t = new Tester();
d = new dtest();
test tnew = new test();
}
public static class dtest extends JFrame implements MouseMotionListener{
public static int x,y;
dtest()
{
super("title");
setSize(500,500);
setVisible(true);
addMouseMotionListener(this);
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
public void paint(Graphics g)
{
System.out.println("I am called");
}
}
public static class test {
public test()
{
for(int i = 0 ; i < 5 ; i++)
{
System.out.println("I am called from run");
d.repaint();
}
}
}
}
this prints
I am called from run
I am called from run
I am called from run
I am called from run
I am called from run
so it does not executing the paint() portion. d.repaint() is not working. why?
Take a look at this page and look at the first answer. It's a similar if not exact question to yours.
JFrame's paint() method has been deprecated. The compiler, or your IDE, should be complaining a bit, especially if you place the #Override tag directly above the method (use this to test if this method can be rewritten... aka what you're trying to do).
This means that its use has been discouraged and some functionality may have been removed. When using javax.swing, you'll want to learn the system completely about JPanels and JComponents. To paint something on a screen, you'll want to add a custom class that extends JPanel with the add(Component c) method. Then, override the paintComponent(Graphics g) method in that class. Make sure to have the first line in that method be super.paintComponent(g); so that the window can refresh itself.
For completeness:
public class MyWindow extends JFrame {
MyPanel thePanel;
public MyWindow(int x, int y) {
setSize(x, y);
thePanel = new MyPanel(x, y);
this.add(thePanel);
}
}
public class MyPanel extends JPanel {
public MyPanel(int x, int y)
setSize(x, y);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(ImageManager.getImage("Cute Puppy"), 40, 40, null); // Or whatever
}
}
So, when the repaint() or revalidate() method is called on the MyWindow, the Panel will recieve a paintComponent call.
Please let me know in the comments if you need any additional help.
Edited:
Since you need to use MouseMotionListener, and I'm still not quite understanding the context and trouble of "I need to call repaint from another class"... I will try my best.
Firstly, check out this tutorial on the Oracle pages. Also, check out the others on GUI's. You'll learn a lot about organization and displaying that will make you realize how their system can work with yours.
Now, for your questions:
i have to use MouseMotionListener.
Not quite... it is a good way for set up but you can run a Thread (something that constantly runs methods over and over) to check the Mouse coordinates. You'll want to start doing this when you get into games and other miscellaneous applications.
new Thread() {
public void run() {
Point mouse;
int mousex;
int mousey;
while (true) {
mouse = MouseInfo.getPointerInfo().getLocation();
mousex = mouse.x - theWindow.getLocationOnScreen().x - 3; // You'll need to get the
// x coordinate, subtract the window's x coordinate, and subtract 3 because of
// the blue border around a standard pc window.
mousey = mouse.y - theWindow.getLocationOnScreen().y - 29; // 29 is top bar height
SomeOtherClass.processMove(mousex, mousey);
}
}
}.start();
Next: I tried that with JPanel but i could not do that. If you read the tutorial at the top of my edit, you see they implement MouseMotionListener with ease.
Next: I prefer to do it with JFrame. If you wish to process the mouse in the JFrame, do the following: Have your JFrame the listener, but the JPanel be where the mouse data comes from. As follows:
public class MyWindow extends JFrame implements MouseMotionListener {
public MyPanel thePanel;
public int x;
public int y;
public MyWindow() {
thePanel = new MyPanel();
thePanel.addMouseMotionListener(this);
// Make this JFrame get called when the mouse
// moves across the panel.
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
thePanel.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Other painting stuff
}
}
Next: Now i have to update the frame from another class. I could not find a way to update the GUI(the frame) from another class.
Simple. Since the JPanel is what needs to be updated, add the following method to the MyWindow class:
public void repaintWindow() {
thePanel.repaint();
}
And add this to whenever you need to update it:
MyWindow theWindow = new MyWindow();
theWindow.repaintWindow();
Next: all the answers here extended JPanel. So i could not find my answer.
I apologize, but you NEED a panel. It is possible to do with JFrames, but if you want to start doing things raw and low-level, you need to learn how these things work by learning to read the oracle tutorials and the oracle documentation. For now, use JPanels in any ways I've shown you.
Next: from another class I have to draw something on JFrame.Is that possible?
Yes, indeed! Whenever you want to draw something:
MyWindow theWindow = new MyWindow();
Graphics g = theWindow.thePanel.getGraphics();
BufferedImage someRandomImage = SomeRandomClass.getRandomImage();
g.drawImage(someRandomImage, 200, 481, null);
theWindow.repaintWindow();
I really hope I've helped but to program in java you need to use the tools they give you, especially when it comes to high level things like Swing. There are tutorials everywhere for this stuff. Please read them before asking for specific help in the future.
ok i have two classes similar like this(the graphics are set up the same way) and another class that is displayed on the bottom. as you can see i have two graphics2ds that i would like to display at the same time with the items class being transparent and on top (the items class has almost nothing in it, and the game class is fully covered with pictures and such)
is there any way to do this?
currently the items class take priority ever the game class because it was called last and totally blocks the game class.
public class game extends Canvas implements Runnable
{
public game()
{
//stuff here
setBackground(Color.white);
setVisible(true);
new Thread(this).start();
addKeyListener(this);
}
public void update(Graphics window)
{
paint(window);
}
public void paint(Graphics window)
{
Graphics2D twoDGraph = (Graphics2D)window;
if(back==null)
back = (BufferedImage)(createImage(getWidth(),getHeight()));
Graphics graphToBack = back.createGraphics();
//draw stuff here
twoDGraph.drawImage(back, null, 0, 0);
}
public void run()
{
try
{
while(true)
{
Thread.currentThread();
Thread.sleep(8);
repaint();
}
}catch(Exception e)
{
}
}
}
class two
public class secondary extends JFrame
{
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
public secondary()
{
super("Test RPG");
setSize(WIDTH,HEIGHT);
game game = new game();
items items = new items();
((Component)game).setFocusable(true);
((Component)items).setFocusable(true);
getContentPane().add(game);
getContentPane().add(items);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main( String args[] )
{
secondary run = new secondary();
}
}
Here are my suggestions:
Extend JComponent rather than Canvas (you probably want a lightweight Swing component rather than a heavyweight AWT one)
Then don't bother with the manual back-buffering for your drawing - Swing does back-buffering for you automatically (and will probably use hardware acceleration while doing so)
Have one component draw both items and the rest of the game background. There is no good reason to do it separately (even if you only change the items layer, the background will need to be redrawn because of the transparency effects)
Capitalise Your ClassNames, it makes my head hurt to see lowercase class names :-)
EDIT
Typically the approach would be to have a class that represents the visible area of the game e.g. GameScreen, with a paintCompoent method as follows:
public class GameScreen extends JComponent {
....
public void paintComponent(Graphics g) {
drawBackground(g);
drawItems(g);
drawOtherStuff(g); // e.g. animated explosions etc. on top of everything else
}
}
I started using jMonekyEngine and it's easy way of interacting with Swing GUI.
Following their tutorial here http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:swing_canvas
It all works and I get everything loaded,however I'm having trouble modifying things.
According to their tutorial, the constant update and happens here:
public void simpleUpdate(float tpf) {
geom.rotate(0, 2 * tpf, 0);
}
(this is an example from the tutorial on rotating objects).
what i'm trying to do is just increasing and decreasing the speed of rotation (by changing the 2 or tpf with a variable which gets update inside an ActionListener in the Swing gui.
However, since in their tutorial they stated that the swing gui is to be created inside the main method, I have to create a variable which is static in order to change it.
static float rotate = 0.0f;
it gets modified inside the main method, but when trying to use it like so:
public void simpleUpdate(float tpf) {
geom.rotate(0, rotate * tpf, 0);
}
it remains constant to the initial value.
I tried creating a GUI class to build the gui (extends JPanel) and using getters and setters, but still not go..
Any help would be appreciated!
Thanks!
EDIT:
Here's how I change the rotate value:
JButton faster = new JButton("Faster");
faster.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
rotate +=0.1f;
}
});
inside the main method. rotate is a static field.
This is working for me
http://test.jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_main_event_loop
http://test.jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_input_system?s[]=input
Is your action listener really triggering the event on click? maybe you have a problem there and not in the rotate variable. Note that I'm not using swing on this example..
import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
/** Sample 4 - how to trigger repeating actions from the main update loop.
* In this example, we make the player character rotate. */
public class HelloLoop extends SimpleApplication {
public static void main(String[] args){
HelloLoop app = new HelloLoop();
app.start();
}
protected Geometry player;
#Override
public void simpleInitApp() {
Box b = new Box(Vector3f.ZERO, 1, 1, 1);
player = new Geometry("blue cube", b);
Material mat = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
player.setMaterial(mat);
rootNode.attachChild(player);
initKeys();
}
/* This is the update loop */
#Override
public void simpleUpdate(float tpf) {
// make the player rotate
player.rotate(0, val*tpf, 0);
}
float val = 2f;
private void initKeys() {
// Adds the "u" key to the command "coordsUp"
inputManager.addMapping("sum", new KeyTrigger(KeyInput.KEY_ADD));
inputManager.addMapping("rest", new KeyTrigger(KeyInput.KEY_SUBTRACT));
inputManager.addListener(al, new String[]{"sum", "rest"});
}
private ActionListener al = new ActionListener() {
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("sum") ) {
val++;
}else if (name.equals("rest")){
val--;
}
}
};
}