The happy face Im using----)This project wants me to Modify the Rebound program from this chapter such that when the mouse button is clicked the animation stops, and when its clicked again the animation resumes.
When I click on the screen with the moving smiley face, it doesnt stop when I click it nor start up again because I couldnt stop the smiley face from moving What am I doing wrong? Here is the problem area.------) |
private class ReboundMouseListener implements MouseListener {
public void mouseClicked(MouseEvent event) {
if (timer.isRunning())
timer.stop();
else
timer.start();
}
}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
public void mousePressed(MouseEvent event) {}
public void mouseReleased(MouseEvent event) {}
}
Here is the rest of the code:
public class ReboundPanel extends JPanel {
private final int WIDTH =300, HEIGHT= 100;
private final int DELAY= 20, IMAGE_SIZE=35;
private ImageIcon image;
private Timer timer;
private int x, y, moveX, moveY;
//---------------------------------------------------------
// Sets up the panel,including the timer for the animation.
//---------------------------------------------------------
public ReboundPanel(){
timer= new Timer(DELAY, new ReboundListener());
image= new ImageIcon("happyFace.gif");
x=0;
y=40;
moveX=moveY=3;
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(Color.black);
timer.start();
}
//---------------------------------------------------------
// Draws the image in the current location.
//---------------------------------------------------------
public void paintComponent(Graphics page)
{
super.paintComponent(page);
image.paintIcon(this, page, x, y);
}
//*********************************************************
// Represents the action listener for the timer.
//*********************************************************
private class ReboundListener implements ActionListener
{
//--------------------------------------------------------
// Updates the position of the image and possibly the direction
// of movement whenever the timer fires an action event.
//--------------------------------------------------------
public void actionPerformed(ActionEvent event)
{
x += moveX;
y += moveY;
if (x <=0 || x >= WIDTH-IMAGE_SIZE)
moveX =moveX * -1;
if (y <=0 || y >= HEIGHT-IMAGE_SIZE)
moveY = moveY * -1;
repaint();
}
}
private class ReboundMouseListener implements MouseListener {
//--------------------------------------------------------------
// Stops or starts the timer (and therefore the animation)
// when the mouse button is clicked.
//--------------------------------------------------------------
public void mouseClicked(MouseEvent event) {
if (timer.isRunning())
timer.stop();
else
timer.start();
}
//--------------------------------------------------------------
// Provide empty definitions for unused event methods.
//--------------------------------------------------------------
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
public void mousePressed(MouseEvent event) {}
public void mouseReleased(MouseEvent event) {}
}
}
public class Rebound {
public static void main(String[] args) {
JFrame frame = new JFrame("Rebound");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ReboundPanel());
frame.pack();
frame.setVisible(true);
}
}
Looks like you are missing your addMouseListener() calls:
public ReboundPanel() {
// Other initializations ...
addMouseListener(new ReboundMouseListener()); // <-- add
timer.start();
}
Related
I need to make an animation with a part controlled with arrows. I created JPanel which draws the "background" simply with timer and repaint(). Then I'm trying to add a canvas with key listener.
public class MyPanel extends JPanel implements ActionListener{
MyPanel(){
... creating other objects ...
MyCanvas canv = new MyCanvas();
this.add(canv);
Timer timer = new Timer(30, this);
}
...actionPerformed and other functions for background animation...
}
public class MyCanvas extends Canvas implements ActionListener, KeyListener{
int rX;
int rY;
Color color;
KeyEvent e;
int code;
Timer timer;
MyCanvas() {
rX = 400;
rY = 400;
color=Color.red;
this.setSize(1220, 840);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
timer = new Timer(5, this);
timer.start();
}
public void KeyPressed(KeyEvent e){
code = e.getKeyCode();
}
public void paint (Graphics g)
{
g.setColor(color);
g.fillOval(this.rX, this.rY, 30, 30);
}
public void actionPerformed(KeyEvent evt) {
int keyCode = evt.getKeyCode();
if(keyCode == KeyEvent.VK_LEFT){
rX-=2;
}
...and so on...
public void keyPressed(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public void actionPerformed(ActionEvent e) {
repaint();
}
}
The background animation works and moves just fine, but canvas is added to JPanel, it completely covers it up. Also the key control doesn't work at all.
How to fix it?
So I am new to event handlers, and I wanted to create a program where I made a Purple panel inside a frame and if the user clicks the mouse button in the area of the panel and then types % with their keyboard, I want the panel to draw a line segment in the area of the panel. This is just testing the event handlers. Right now, I am trying it but it does not work. All help will be appreciated. After I get the hand of this, I want to try out the repaint() method, where if someone does the same actions as before, I wanted to check the background of the Panel. If you can help me with both, that'd be awesome but it is not a priority. Thank you.
import java.awt.Graphics; // for classes Graphics, Color, Font, Image
import java.awt.Color;
import java.awt.Font;
import java.awt.event.KeyEvent; // for classes KeyListener, MouseListener
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame; // for classes JFrame, JPanel, JLabel
import javax.swing.JPanel;
public class GardenGrows
{
public GardenGrows()
{
}
public static void main(String[] args)
{
GardenGrows gg = new GardenGrows();
gg.runIt();
}
// makes the frame and handles all properties of the frame
// also instantiates the Garden.java object
public void runIt()
{
JFrame frame = new JFrame ("Garden");
frame.setDefaultCloseOperation( frame.EXIT_ON_CLOSE );
frame.setLayout(null);
frame.setBackground(Color.GRAY);
frame.setSize( 1200,700);
frame.setLocation( 50, 10);
frame.setResizable(true);
frame.setVisible(true);
Garden gar = new Garden();
frame.getContentPane().add(gar);
}
}
class Garden extends JPanel implements KeyListener, MouseListener
{
private boolean mouseClicked;
private boolean keyClicked;
private int xpos;
private int ypos;
public Garden()
{
mouseClicked = false;
keyClicked = false;
addKeyListener(this);
addMouseListener(this);
setBackground(Color.PINK);
setLocation(50,50);
setSize(1000,500);
}
public void mousePressed(MouseEvent evt)
{
int x = evt.getX();
int y = evt.getY();
if(x>=50 || x<=1050 && y<=50 || y>=550)
{
mouseClicked = true;
}
}
public void mouseClicked(MouseEvent evt){}
public void mouseReleased(MouseEvent evt){}
public void mouseEntered(MouseEvent evt){}
public void mouseExited(MouseEvent evt){}
public void keyReleased(KeyEvent evt){}
public void keyPressed(KeyEvent evt){}
public void keyTyped(KeyEvent evt)
{
int letter = evt.getKeyCode();
if (letter == 13)
{
keyClicked =true;
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(keyClicked && mouseClicked)
g.drawLine(50,0,110,120);
}
}
Making a key listener work in a JPanel, will not be so simple, because it is not focusable. (Think about a JTextField, when you write text on it, it is focused). So, in order to make this work you will have to use KeyBindings. In practice, remove the KeyListener implementation from your JPanel, and use KeyBindings.
public class GardenGrows {
public GardenGrows() {
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// All swing applications must run on EDT Thread
GardenGrows gg = new GardenGrows();
gg.runIt();
});
}
// makes the frame and handles all properties of the frame
// also instantiates the Garden.java object
public void runIt() {
JFrame frame = new JFrame("Garden");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setBackground(Color.GRAY);
frame.setSize(1200, 700);
frame.setLocation(50, 10);
frame.setResizable(true);
frame.setVisible(true);
Garden gar = new Garden();
frame.getContentPane().add(gar);
}
}
class Garden extends JPanel implements MouseListener {
private boolean mouseClicked;
private boolean keyClicked;
private int xpos;
private int ypos;
public Garden() {
mouseClicked = false;
keyClicked = false;
addMouseListener(this);
setBackground(Color.PINK);
setLocation(50, 50);
setSize(1000, 500);
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_5, KeyEvent.SHIFT_MASK),
"percentageClicked");
getActionMap().put("percentageClicked", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
keyClicked = true;
repaint(); // Try to draw the line
}
});
}
public void mousePressed(MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
if (x >= 50 || x <= 1050 && y <= 50 || y >= 550) {
mouseClicked = true;
repaint(); // Try to draw the line
}
}
public void mouseClicked(MouseEvent evt) {
}
public void mouseReleased(MouseEvent evt) {
}
public void mouseEntered(MouseEvent evt) {
}
public void mouseExited(MouseEvent evt) {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (keyClicked && mouseClicked)
g.drawLine(50, 0, 110, 120);
}
}
I'm experimenting on a GUI that I programmed and I don't understand how I can fix my problem:
My GUI contains a jPanel that on receiving a mouseclick, paints a point with filloval command.
private void myPnlMousePressed(java.awt.event.MouseEvent evt) {
changed = true;
p.x = evt.getX();
p.y = evt.getY();
drewPoints(p.x, p.y);
}
private void drewPoints (int x, int y) {
if (gf == null) {
gf = (Graphics)myPnl.getGraphics();
}
myPointsList.add(new Point(x, y));
gf.fillOval(x, y, 5, 5);
xVal.setText("X = " + x);
yVal.setText("Y = " + y);
}
everything works fine but when I want to open an XML file that I created to save all the points it doesn't work.
The problem is that when I use the repaint method on the jPanel after choosing a file, all the points loads fine but the panel can't draw the points.
If I put the repaint method in the open button listener (before the choosing file) it works, but then if the user cancels the open option so the panel stays blank and I don't want to draw the points again.
I think it happens because the repaint process is not finished.
All the points added to a private List.
private void OpenFile() {
try {
File thisFile;
JFileChooser of = new JFileChooser();
int option = of.showOpenDialog(of);
if (option == JFileChooser.APPROVE_OPTION){
thisFileName = of.getSelectedFile().getPath();
thisFile = new File(thisFileName);
if (!of.getSelectedFile().getName().endsWith(".xml")) {
String error = "Error, You didn't select XML file";
JOptionPane.showMessageDialog(this, error, "Wrong type of file", JOptionPane.INFORMATION_MESSAGE);
return;
}
myPnl.repaint();
myPointsList.clear();
....
....
....
for (int i = 0; i < pointsList.getLength(); i++) {
Element point = (Element) pointsList.item(i);
p.x = Integer.parseInt(point.getElementsByTagName("X").item(0).getTextContent());
p.y = Integer.parseInt(point.getElementsByTagName("Y").item(0).getTextContent());
drewPoints(p.x, p.y);
}
....
how can I make it work??
Don't use gf = (Graphics)myPnl.getGraphics();, this is not how painting in Swing works. The getGraphics method can return null and is nothing more then a snap shot of the last paint cycle, any thing you paint to it will be erased on the next paint cycle (repaint).
Instead, override the JPanels paintComponent and put all you painting logic there. There is an expectation that when called, you are expected to fully re-paint the current state of the component.
See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing
You have to use the repaint() and override the paint() method:
class MyPanel extends JPanel implements MouseListener
{
private int x;
private int y;
public MyPanel() {
super();
addMouseListener(this);
}
#Override public void mouseEntered(MouseEvent e) { }
#Override public void mouseExited(MouseEvent e) { }
#Override public void mouseClicked(MouseEvent e) { }
#Override public void mousePressed(MouseEvent e) { }
#Override public void mouseReleased(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 10, 10);
}
}
If you want to draw all points, don't use x and y but a list of points:
class MyPanel extends JPanel implements MouseListener
{
private ArrayList<Point> points = new ArrayList<>();
public MyPanel() {
super();
addMouseListener(this);
}
#Override public void mouseEntered(MouseEvent e) { }
#Override public void mouseExited(MouseEvent e) { }
#Override public void mouseClicked(MouseEvent e) { }
#Override public void mousePressed(MouseEvent e) { }
#Override public void mouseReleased(MouseEvent e) {
points.add(new Point(e.getX(), e.getY()));
repaint();
}
#Override public void paint(Graphics g) {
super.paint(g);
for (Point p : points)
g.fillOval(p.getX(), p.getY(), 10, 10);
}
}
where:
class Point
{
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Then use it:
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
MyPanel myPanel = new MyPanel();
frame.add(myPanel);
frame.setVisible(true);
}
Im working on an assignment where an image moves around and when the user clicks on the panel the image stops. When the user clicks on the panel again the image starts. As of now i can only start and stop the image once before it stays going. I need help to loop this process so that the user can keep starting and stopping the image.
Here is my code
Main:
import javax.swing.*;
public class Rebound {
//-----------------------------------------------------------------
// Displays the main frame of the program.
//-----------------------------------------------------------------
public static void main (String[] args)
{
JFrame frame = new JFrame ("Rebound");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ReboundPanel());
frame.pack();
frame.setVisible(true);
}
}
Panel:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ReboundPanel extends JPanel
{
private final int DELAY = 10, IMAGE_SIZE = 35;
private ImageIcon image;
private Timer timer;
private int x, y, moveX, moveY;
public ReboundPanel()
{
timer = new Timer(DELAY, new ReboundListener());
addMouseListener (new StopListener());
image = new ImageIcon ("happyFace.gif");
x = 0;
y = 40;
moveX = moveY = 3;
setPreferredSize (new Dimension(1900, 1000));
setBackground (Color.black);
timer.start();
}
public void paintComponent (Graphics page)
{
super.paintComponent (page);
image.paintIcon (this, page, x, y);
}
private class ReboundListener implements ActionListener
{
public void actionPerformed (ActionEvent event)
{
x += moveX;
y += moveY;
if (x <= 0 || x >= 1900-IMAGE_SIZE)
moveX = moveX * -1;
if (y <= 0 || y >= 1000-IMAGE_SIZE)
moveY = moveY * -1;
repaint();
}
}
// Represents the action listener for the timer.
public class StopListener extends MouseAdapter
{
public void mouseClicked (MouseEvent event)
{
if (event.getButton() == MouseEvent.BUTTON1)
{
timer.stop();
}
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent event) {
if(event.getButton() == MouseEvent.BUTTON1)
{
timer.start();
removeMouseListener(this);
}
}
});
}
}
}
You can simply reuse the same listener, and check the state of the timer before starting/stopping it:
public void mouseClicked(MouseEvent event)
{
if (event.getButton() == MouseEvent.BUTTON1)
{
if (timer.isRunning()) {
timer.stop();
}
else {
timer.start();
}
}
}
In you StopListener class have an instance variable bool isMoving = true;
Then in your handler should use that to determine whether to stop or start the timer:
public void mouseClicked( MouseEvent event )
{
if( event.getButton() == MouseEvent.BUTTON1 )
{
if( isMoving )
timer.stop();
else
timer.start();
isMoving = !isMoving;
}
}
I'm making a GUI pairs guessing game with 9x12 panels to hold a random number in each. I have made it so when you hover over each individual panel, it changes from red to yellow, and back to red once your mouse leaves the panel area.
My problem now is changing the color of a clicked panel to green, and any previously clicked panel back to it's original color red. It turns green as intended, but am lost as to how to reset the previously clicked panel back to red after a new panel is clicked. I'm hoping there is an obvious answer but here is some relevant code (Not polished off):
public class NumberPanel extends JPanel {
int rand;
Random generator = new Random();
JLabel numbers;
boolean mouseEntered = false;
boolean mouseClicked = false;
boolean mouseUnClicked = false;
MainPanel mp;
public NumberPanel() {
setBackground(Color.RED);
setPreferredSize (new Dimension(40,40));
rand = generator.nextInt(8) +1;
addMouseListener(new NumberListener());
}
public NumberPanel (MainPanel mp) {
//Callback method for MainPanel
this.mp = mp;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Font font = new Font("Verdana", Font.BOLD, 18);
g.setFont(font);
g.drawString("" +rand, 14,24);
if (mouseEntered) {
setBackground(Color.YELLOW);
}
else {
setBackground(Color.RED);
}
if (mouseClicked) {
setBackground(Color.GREEN);
}
}
//represents the listener for mouse events
private class NumberListener implements MouseListener {
public void mouseEntered (MouseEvent event) {
mouseEntered=true;
repaint();
}
public void mouseExited(MouseEvent event) {
mouseEntered=false;
repaint();
}
public void mouseClicked(MouseEvent event) {
}
public void mouseReleased(MouseEvent event) {
}
public void mousePressed(MouseEvent event) {
mouseClicked=true;
repaint();
}
}
}
Just create a static NumberPanel field in NumberPanel called current:
private static NumberPanel current;
...
// create a static MouseListener instead of creating a new one for each
// NumberPanel instance.
private static final MouseAdapter mouseListener = new MouseAdapter(){
public void mousePressed(MouseEvent event) {
NumberPanel panel = (NumberPanel) event.getSource();
if(current != null) {
current.mouseClicked = false;
}
current = panel;
panel.mouseClicked = true;
// repaint number panels container
}
}
...
addMouseListener(mouseListener);
Something like that should keep track of the current clicked panel.