Hi
i am trying to add a mouse listener to my frame to get the position of the mouse clicked and check if it is inside the circle, the problem is that it is not triggering
public class CircleDraw extends Frame implements MouseListener {
static int circles = 0;
private double color;
double mousex = 0;
double mousey = 0;
int score;
public void mouseClicked(MouseEvent evt)
{
mousex = evt.getX();
mousey = evt.getY();
}
public void mouseEntered (MouseEvent me) {}
public void mousePressed (MouseEvent me) {}
public void mouseReleased (MouseEvent me) {}
public void mouseExited (MouseEvent me) {}
public void paint(Graphics g) {
try {
this.addMouseListener(this);
while (circles < 20) {
color = 10*Math.random();
Shape circle = new Ellipse2D.Double(900*Math.random(),900*Math.random(), 50.0f, 50.0f);
Graphics2D ga = (Graphics2D)g;
ga.draw(circle);
if(color >2)
ga.setPaint(Color.green);
else
ga.setPaint(Color.BLACK);
ga.fill(circle);
if(circle.contains(mousex, mousey) && color > 2)
score ++;
else
if(circle.contains(mousex, mousey) && color < 2)
score--;
Thread.sleep(1000);
System.out.println(circles);
System.out.println(mousex);
System.out.println(mousey);
circles ++;
ga.setPaint(Color.white);
ga.fill(circle);
}
System.exit(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
Frame frame = new CircleDraw();
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
frame.setSize(1000, 1000);
frame.setVisible(true);
}}
It is deadly to add your mouselistener in the paint() method, since this method is called very very often (with each repaint), and so many listeners are added (with each repaint).
You should add the listener to your content-panel and not to the JFrame itself. This will do it. You can do this in the constructor of your class:
public CircleDraw() {
this.getContentPane().addMouseListener(this);
}
This won't solve your problem completely I think, since you won't get your mouseclick while your paint-method is active. Your code-design (especially your while-loop) does not give any time to other events to fire. So the mouseclick-event will be handled after your 20 loops. You can check this by adding
public void mouseClicked(MouseEvent evt) {
mousex = evt.getX();
mousey = evt.getY();
System.out.println("X: "+mousex+"/ Y: "+mousey);
}
to your code. You have to run your GUI in a different thread (e.g. use SwingUtilities and a Runnable() therefor). I recommend you to get a good book on JAVA development. Or you can start with online-tutorials like this one.
IMHO you should not try to deal with awt, instead use SWING or SWT for GUI-design, since this is much more compfortable.
add the listener in the constructor, the paint is called repeatedly
Here are some of the problems I see with that source:
Adds the listener in paint()
Calls wait() within the paint() method.
Calls System.exit() within the paint() method (not strictly a problem, but very unusual).
Is poorly formatted and hard to understand
Calls deprecated methods.
Codes in AWT in the wrong millennium.
Related
I have a Java exercise using KeyListeners that I have been stuck on for a while. Any help would be greatly appreciated. The exercise is:
"Write a program to get a character input from the keyboard and display the character where the mouse points."
I did some debugging and it seems like the KeyListener is never registering when a key is pressed.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class EventProgrammingExercise10 extends JFrame {
CharPanel chars;
private int x;
private int y;
String s;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
EventProgrammingExercise10 frame = new EventProgrammingExercise10();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public EventProgrammingExercise10() {
setTitle("EventProgrammingExercise10");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 300);
chars = new CharPanel();
chars.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
chars.repaint();
}
});
add(chars);
}
public void setX(int n) {
x = n;
}
public void setY(int n) {
y = n;
}
class MouseLocListener extends MouseMotionAdapter {
public void mouseMoved(MouseEvent e) {
setX(e.getX());
setY(e.getY());
}
}
class CharPanel extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString(String.valueOf('a'), x, y);
}
}
}
Thanks.
A KeyListener will only work if the component that owns it has the focus. You must first make your JPanel focusable, i.e., setFocusable(true), and then request that it have focus, i.e., requestFocusInWindow().
I wouldn't use a MouseListener at all. What I'd do if I had to use a KeyListener, and what I know works, would be:
Make my JPanel Focusable and have focus
Give it a BufferedImage that is exactly its size and draw this in its paintComponent method.
Add a KeyListener/KeyAdapter to it
In the KeyAdapter, keyPressed method, Use the MouseInfo class to get a PointerInfo object: PointerInfo pInfo = MouseInfo.getPointInfo()
Use PointerInfo to get the current mouse's location on screen via pInfo.getLocation();
Get the drawing JPanel's locationOnScreen.
Translate the mouse pointer location to one that is relative to that of the component's using simple vector graphics.
If the point is in bounds of the location, get a Graphics object from the BufferedImage
Draw the char in the BufferedImage
Repaint the JPanel
Look #Hovercraft and you forget to add the MouseLocListener. Than it works :)
chars.addMouseMotionListener(new MouseLocListener());
chars.setFocusable(true);
chars.requestFocusInWindow();
It looks like you should attach lKeyListener not to chars panel but to the frame itself.
This way KeyListener will allways work even if panel losses focus for any reason.
I'm new at Java. I'm trying to use GUI to input and display a weighted binary tree. To create root node, user clicks on screen. Subsequently, he drags from one point to another to create an edge and a new node. Once he releases the mouse, he should be prompted to enter the weight, and then edge (with weight displayed) and new node should be displayed.
In the input, while I'm able to create the root, when I try to drag to create the next node, the program goes into a loop.
Code is given below.
class myPanel extends JPanel implements MouseListener, MouseMotionListener
{
int node_is_present[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //1 if node exists, 0 otherwise
int no_of_nodes=0;
int node_coords[][]=new int[15][2]; //stores co-ordinates of each node
int weight[]=new int[15]; //stores weight of line in the order entered
int x1,x2,y1,y2;
int tracker=-1;
int SIZE=20;
public void clear()
{
x1=0;
y1=0;
x2=0;
y2=0;
}
#Override
public void mouseClicked(MouseEvent me) {}
#Override
public void mousePressed(MouseEvent me) //will store intial x,y
{
tracker=1;
x1=me.getX();
y1=me.getY();
repaint();
}
#Override
public void mouseReleased(MouseEvent me) //will store final x,y and update arrays
{
x2=me.getX();
y2=me.getY();
if(x1!=x2)
tracker=2;
node_is_present[no_of_nodes]=1;
node_coords[no_of_nodes][0]=me.getX();
node_coords[no_of_nodes][1]=me.getY();
no_of_nodes++;
repaint();
}
#Override
public void mouseEntered(MouseEvent me){}
#Override
public void mouseExited(MouseEvent me) {}
#Override
public void mouseDragged(MouseEvent me){}
#Override
public void mouseMoved(MouseEvent me) {}
public void paintComponent(Graphics g)
{
if(tracker==1 && no_of_nodes==0) //for root node
{
g.drawOval(x1-(SIZE/2),y1-(SIZE/2),SIZE,SIZE);
g.drawString(String.valueOf(no_of_nodes+1),x1-(SIZE/2),y1-(SIZE/2));
}
else if(tracker==2 && no_of_nodes>0)
{
g.drawLine(x1 -(SIZE/2) , y1 -(SIZE/2) , x2 -(SIZE/2) , y2 -(SIZE/2));
g.drawOval(x2-(SIZE/2),y2-(SIZE/2),SIZE,SIZE);
g.drawString(String.valueOf(no_of_nodes+1),x2-(SIZE/2),y2-(SIZE/2));
String str=JOptionPane.showInputDialog("Enter the weight of the edge: ");
int w=Integer.parseInt(str);
weight[no_of_nodes-1]=w;
g.drawString(String.valueOf(w),Math.round((x1+x2)/2),Math.round((y1+y2)/2));
clear();
}
}
myPanel()
{
this.setSize(1500, 500);
addMouseListener(this);
addMouseMotionListener(this);
clear();
}
}
public class tree1
{
public static void main(String[] args) {
JFrame frame=new JFrame();
myPanel panel=new myPanel();
frame.setSize(1500, 800);
frame.setLocation(0, 0);
frame.setTitle("Tree");
frame.setBounds(100,100,1500,800);
frame.add(panel);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Painting in Swing may occur at any time for any reason. As #HoverCraftFullOfEels has already pointed out, you should have NO application within any paint method, these should contain ONLY the functionality required to paint your component.
Start by taking a look at Performing Custom Painting and Painting in AWT and Swing for more details about the paint sub system
Basically, within your paintComponent, call super.paintComponent first and remove, in particular, the else block.
Make yourself some kind of model, which holds the required data and then use the paintComponent method to paint that model.
There is a problem with the repaint() method in Java. I made a new thread that constantly repaints the screen. When I release the spacebar I want my player to fall smoothly by setting its position and then waiting for 50 milliseconds and looping that 20 times. Instead, it waits the whole amount of time in the loop, then repaints. I am wondering why it doesn't constantly repaint the changes in the players co-ordinates. Thank you.
(Edit) Thanks everyone for the help. This is my first time using stack overflow, and I am only 13 and still learning java, so I probably will go back to the tutorials again.
My 'a' class (main):
public class a {
public static void main(String[] args) {
JFrame frame = new JFrame("StickFigure Game");
frame.setSize(740, 580);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
b board = new b();
frame.add(board);
frame.addKeyListener(board);
}
}
My 'b' class (JPanel/drawing):
public class b extends JPanel implements KeyListener {
c player = new c();
public class MyRunnable implements Runnable {
public void run() {
while (true)
repaint();
}
}
MyRunnable run = new MyRunnable();
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(player.getImage(), player.getX(), player.getY(), 80, 140,
null);
}
public b() {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
public static void slow(int n) {
long t0, t1;
t0 = System.currentTimeMillis();
do {
t1 = System.currentTimeMillis();
} while (t1 - t0 < n);
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_D) {
player.setPos(player.getX() + 6, player.getY());
}
if (e.getKeyCode() == KeyEvent.VK_A) {
player.setPos(player.getX() - 6, player.getY());
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
player.setPos(player.getX(), player.getY() - 60);
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
for (int i = 0; i < 20; i++) {
slow(50);
player.setPos(player.getX(), player.getY() + 2);
}
}
}
public void keyTyped(KeyEvent e) {
}
}
my 'c' class (player):
public class c {
private ImageIcon i = new ImageIcon("guy.png");
private Image img = i.getImage();
private int x = 0;
private int y = 100;
public void wait(int what) {
try {
Thread.sleep(what);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public c() {
}
public Image getImage() {
return img;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setPos(int mx, int my) {
x = mx;
y = my;
}
}
I haven't gone through all the code here but here are some pointers:
Swing has its own concurrency mechanisms which allow you to handle UI updates. You can use a Swing Timer rather than a raw Thread. Related is the use of Thread.sleep - don't do this, it only blocks the EDT and prevents UI updates.
The Swing paint chain mechanism requires you to override paintComponent rather than paint.
Always use Key Bindings rather than KeyListeners in Swing. KeyListeners require component focus to work to interact with the KeyEvents. Key Bindings do not have this limitation.
"There is a problem with the repaint() method in java." Did you consider that perhaps the problem is with your code instead? You are blocking the event thread and giving the system no time to do the intermediate repaints. In particular, this method:
public static void slow (int n){
long t0,t1;
t0=System.currentTimeMillis();
do{
t1=System.currentTimeMillis();
}
while (t1-t0<n);
}
and this loop:
for(int i = 0;i<20;i++){
slow(50);
player.setPos(player.getX(), player.getY()+2);
}
do not relinquish control to the system so that repaints can actually happen. Rewrite those using Swing timers. Look at this tutorial for an introduction on how to use these.
Also, your thread that constantly calls repaint() in a tight loop:
public void run(){
while(true) repaint();
}
is a terrible idea. You don't need to call repaint() at full CPU speed. Once every 30 milliseconds or so is fine for animation. Again, consider using Swing utilities to do this rather than writing your own looping thread.
The repaint is only a "request" to paint as soon as possible. so when you call it it causes a call to the paint method as soon as possible.
from here
So basically you just flooding the scheduled calls of paint or update with while(true) repaint();.
Oracle's stance on painting in AWT and Swing
One way you could do it, or should I say how I would do it, is to make your c class implement KeyListener, so that when a key is pressed (and only when it is pressed) you update it's location.
So move your KeyListener methods to class c, in your class b constructor you can add the call this.addKeyListener(player) or make a method void addPlayer(c player) that adds it.
I am trying to move a ball in applet using thread but its not moving. Can anyone help me out as m new to applet and proceeding for game development..for reference here is my code
public class ballGame extends JApplet implements Runnable
{
int x_pos=50;
int y_pos=100;
int rad=10;
Thread t;
public void start()
{
super.start();
t=new Thread("t");
t.start();
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.red);
setBackground(Color.BLACK);
g.drawOval(x_pos,y_pos,2*rad,2*rad);
while(true)
{
x_pos++;
//validate();
repaint();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}//end of while
}//end of paint()
}
Swing is a single thread environment. That is, all updates and interactions are executed within a single thread. Swing is also NOT thread safe. This means that all updates to the UI MUST be executed within the context of that thread (the Event Dispatching Thread or ETD).
Any code that blocks the EDT will prevent it from (amongst other things), repainting the UI and responding to input from the user.
You're paint code will NEVER update the screen, in fact it will make your application appear to "hang", as the paint method isn't being allowed to complete and is blocking the ETD.
It is an exception that the paint method will return quickly after been called and may be called repeatedly in quick succession.
Generally speaking, a Thread is probably a little over kill, something like a javax.swing.Timer would be more then suitable under these circumstances.
public class AnimatedBoat {
public static void main(String[] args) {
new AnimatedBoat();
}
public AnimatedBoat() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new AnimationPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class AnimationPane extends JPanel {
private BufferedImage boat;
private int xPos = 0;
private int direction = 1;
public AnimationPane() {
try {
boat = ImageIO.read(new File("boat.png"));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += direction;
if (xPos + boat.getWidth() > getWidth()) {
xPos = getWidth() - boat.getWidth();
direction *= -1;
} else if (xPos < 0) {
xPos = 0;
direction *= -1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int y = getHeight() - boat.getHeight();
g.drawImage(boat, xPos, y, this);
}
}
}
As a side note. You should rarely need to override the paint method of a top level container like JApplet or JFrame, while there are a number of good reasons for this, the one that you're going to most interested in is the fact that they're not double buffered, meaning you are likely to see flickering as the screen is updated.
It's better to use something like JPanel and override it's paintComponent method instead.
Take a look at
Performing Custom Painting
Concurrency in Swing
Painting in AWT and Swing
For more information
nb
While I've used a JFrame for my example, it would be a simple matter to take the animation panel and put it into a JApplet, this is another reasons why you don't need/want to extend from top level containers ;)
Having an infinite loop in paint means that not a single pass of the method can complete.
Also you should never call Thread.sleep(100) in the paint method. This blocks the EDT and degrades performance.
Instead use a Swing Timer to do the update and repainting work. Also I would sub-class a JComponent and override paintComponent.
You can not invoke repaint() method inside paint(). And you can not organize infinitely loop inside paint() method - doing so, you are blocking drawing in your applet.
x_posis an int value, thus it is passed to methods by value, not by reference. That is why, when you change its value, the value inside of your circle is not updated...
You create a Thread without a run() method. This method should contain the runnable code... Furthermore, the paint() method is to paint stuff, not update stuff!
So move your while loop from the paint() method into the run() method of your thread:
t=new Thread("t") {
#Override
public void run()
{
while(true)
{
x_pos++;
//validate();
repaint();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}//end of while
}
};
Note that ballGame does not require the implement Runnable part. As the thread you created will provide it.
Have the while loop inside the run method of Runnable.
UPDATE:
Have this in the start method.
t=new Thread(this);
t.start();
I want to move a image across the screen by 16 to the right when the arrow key is pressed. I want to move it with a speed(1px/10ms) until reaches the point. The image is created inside a class that is child of JPanel.
I wrote the next code but the image changes the position instatly instead making a movement:
public class Test extends JFrame implements KeyListener {
private int x=0;
private int y=0;
BufferedImage img;
...
...
public void paint(Graphics g){
g.drawImage(img,x,y,null);
}
// Move to a point 16 pixels to right
public void moveRight(){
for(int i=0;i<16;i++){
x++;
repaint();
try {
Thread.sleep(10); // Sleep 10 milliseconds until next position change
}catch (InterruptedException e) {}
}
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_RIGHT){
moveRight();
}
}
}
The problem is your sleep inside the EDT (Event-Dispatching-Thread). repaint() triggers an event that will be dispatched by the EDT and will in turn perform the actual repainting of your component. Since you are blocking the EDT, the repaint does not perform directly (but after the end of all your code then a single repaint event occurs (because repaint events are grouped whenever possible). You will probably need to use SwingWorker to fix this issue.
What if you call moveRight() in another thread?
try this:
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_RIGHT){
new Thread(new Runnable(){
public void run(){
moveRight();
}
}).start();
}
}
I've not tested and I even don't know if this is a good aproach