Move a BALL on Jpanel with keyboard down key - java

I have a class mypanel extends from jpanel where i use the graphics and make a ball. Second class is Main where i make a JFrame and add panel to frame. There is another class MKeyListener in Main which extends from KeyAdapter class where i handel the keyboard event. I have made a object of Jpanel class in Main class and register the MkeyListener class with the jpanel class. now i want to move down the ball on jpanel with down keyboard key butt ball is not moving down with down key that is code of my programe.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class mypanel extends JPanel{
int n=0;
int m=0;
int i=170;
int j=340;
int a=60;
int b=20;
public void paintComponent (Graphics g){
super.paintComponent(g);
Graphics2D g2= (Graphics2D)g;
g2.setColor(Color.green);
g2.fillOval(n,m,10,10);
}
}
public class Main {
JFrame frame;
mypanel p;
int x,y;
public Main (){
x=0;
y=0;
frame=new JFrame();
Container c = frame.getContentPane();
c.setLayout(new BorderLayout());
p = new mypanel();
c.add(p,BorderLayout.CENTER);
frame.setSize(400,400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MKeyListener k=new MKeyListener();
p.addKeyListener(k);
}
public static void main(String args []) {
Main a= new Main();
}
class MKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent event) {
if (event.getKeyCode()==KeyEvent.VK_DOWN ) {
x =x+4;
y=y+4;
p.n+=x;
p.m+=y;
p.repaint();
System.out.println("success");
}
}
}
}

KeyListener is is picky, the component it is registered to must have focus AND be focuable before it will trigger key events. It can also be overridden by any other focusable component, which can be a good and bad thing.
It's generally recommended to use the key bindings API instead, which gives you control over the focus level required to trigger events. It's also generally far more flexible in it's configuration and re-usability
See How to Use Key Bindings for more details
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String args[]) {
Main a = new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MyPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MyPanel extends JPanel {
private int n = 0;
private int m = 0;
private int i = 170;
private int j = 340;
private int a = 60;
private int b = 20;
public MyPanel() {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "Action.down");
am.put("Action.down", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
n += 4;
m += 4;
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.green);
g2.fillOval(n, m, 10, 10);
}
}
}
As a general piece of advice, it's generally a bad idea to expose fields of you object as public or package-private, you lose control over there management, meaning that they could be modified from any where with out your knowledge or control.
Better to self contain the management of these values (either internally or through the use of getters) or via a model-controller paradigm

Related

Why this circle didn't get smeared

import javax.swing.*;
import java.awt.*;
public class Test1 {
int x = 70;
int y = 70;
public static void main (String[] args) {
Test1 gui = new Test1 ();
gui.go();
}
public void go() {
JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel drawPanel = new MyDrawPanel();
frame.getContentPane().add(drawPanel);
frame.setSize(300,300);
frame.setVisible(true);
for (int i = 0; i < 130; i++) {
x++; y++;
drawPanel.repaint();
try { Thread.sleep(50);
} catch(Exception ex) { } }
}// close go() method
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.green);
g.fillOval(x,y,40,40);
}
} // close inner class
} // close outer class
page1page2
According to the page 2, the circle should be smeared in the frame... but actually, when I ran it, it just moved without smearing. Why was that?
btw, if these codes were not able to make a smearing circle, how could I make a smearing one?
cheers
As shown here, "If you do not honor the opaque property you will likely† see visual artifacts." Indeed, running your example on Mac OS X with Java 6 produces a series of circles that appear "smeared."
How could I make a smearing one?
Do not rely on painting artifacts to get the desired result; instead, render a List<Shape> as shown below.
Use javax.swing.Timer to pace animation.
Construct and manipulate Swing GUI objects only on the event dispatch thread.
Override getPreferredSize() to establish a drawing panel's initial geometry.
Code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test2 {
public static void main(String[] args) {
EventQueue.invokeLater(new Test2()::display);
}
public void display() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyDrawPanel drawPanel = new MyDrawPanel();
frame.add(drawPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class MyDrawPanel extends JPanel {
private int x = 30;
private int y = 30;
private final List<Shape> list = new ArrayList<>();
public MyDrawPanel() {
new Timer(50, (new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
x++;
y++;
list.add(new Ellipse2D.Double(x, y, 40, 40));
repaint();
}
})).start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g.setColor(Color.green);
for (Shape s : list) {
g2d.fill(s);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
}
†Emphasis mine.

Trying to use key listener but shape won't move

I have added a keylistener to try and get a shape to move right when I press the right arrow key. But it isn't working. I don't really know how to use keylistner that well. Can someone help me.
This is the code:
package walkingman;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class WalkingMan extends JPanel implements KeyListener{
int x = 0;
int y = 0;
#Override
public void paint(Graphics g){
super.paint(g);
g.fillOval(x, y, 150, 150);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame ("Walking Man");
frame.setSize(1080,720);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
WalkingMan game = new WalkingMan();
frame.add(game);
while (true){
game.repaint();
game.keyPressed(e);
}
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT){
x++;
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
}
There are a few issues with your code
You never add the KeyListener to the panel.
A KeyListener for a JPanel would only work if it is focusable & also focused.
Override paintComponent instead of paint.
Call setVisible at the end of the method.
Get rid of the whole while-loop, it'll only cause problems.
Use KeyBindings instead of KeyListeners.
Fixed code without key bindings:
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class WalkingMan extends JPanel implements KeyListener {
int x = 0;
int y = 0;
#Override
public void paintComponent(Graphics g) { // Overide paintComponent, not paint
super.paintComponent(g);
g.fillOval(x, y, 150, 150);
}
public WalkingMan() { // Class Constructor
setFocusable(true); // KeyListeners only work if the component is focusable
addKeyListener(this); // Add the KeyListener implemented by this class to the instance
}
public void createAndShowGUI() {
JFrame frame = new JFrame("Walking Man");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
WalkingMan game = new WalkingMan();
frame.add(game);
frame.setSize(1080, 720);
frame.setVisible(true); // Call setVisible after adding the components
game.requestFocusInWindow(); // Request focus for the panel
}
public static void main(String[] args) throws InterruptedException {
new WalkingMan().createAndShowGUI();
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
x++;
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
}
Set frame well before it is displayed And remove the while loop which is still running.
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame ("Walking Man");
frame.setSize(1080,720);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
WalkingMan game = new WalkingMan();
frame.add(game);
frame.setVisible(true);//Call visible method here
}
Why not restructure your code in a much clear way like this
import javax.swing.*;
import java.awt.*;
import javax.swing.border.LineBorder;
import java.awt.Color;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class WalkingMan extends JFrame{
EmilsKeyClass keyBoard = new EmilsKeyClass();
public WalkingMan (){
add(keyBoard,BorderLayout.CENTER);
keyBoard.addKeyListener(new KeyAdapter(){
#Override
public void keyPressed(KeyEvent e){
if(e.getKeyCode()== KeyEvent.VK_ENTER){
x++;
repaint();
}
}
});
keyBoard.setFocusable(true);
}
public static void main(String [] args){
WalkingMan frame = new WalkingMan ();
frame.setTitle("Walking Man");
frame.setSize(1080,720);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class EmilsKeyClass extends JPanel{
int x = 0;
int y = 0;
public EmilsKeyClass(){
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
super.paint(g);
g.fillOval(x, y, 150, 150);
//your code
}
}
}

Java application creating Rectangle when button is pressed

The intention of my code is to create a rectangle when the button is clicked. The button works fine but the rectangle itself is not showing up on the screen, and there are no errors. Thank you for helping btw.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tester {
static JButton button;
static JFrame frame;
static JPanel panel;
static Rectangle rec;
static void init(){
button = new JButton();
frame = new JFrame();
panel = new JPanel();
rec = new Rectangle(30,30,30,30);
button.setVisible(true);
panel.add(button);
frame.add(panel);
frame.setVisible(true);
panel.setVisible(true);
frame.setSize(200, 200);
button.setBackground(Color.GREEN);
button.setBounds(30, 30, 20, 20);
}
public static void main(String[] args) {
init();
ActionListener listener = new RectangleMover();
button.addActionListener(listener);
}
static class RectangleMover implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
RectanglePainter r = new RectanglePainter();
r.add(rec);
}
}
static class RectanglePainter extends JPanel{
void add(Rectangle r){
rec = r;
repaint();
}
protected void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
Random r = new Random();
int i =r.nextInt(2);
if (i==1)
g2.setColor(Color.BLUE);
else
g2.setColor(Color.RED);
g2.fill(rec);
g2.draw(rec);
}
}
}
Your generally approach is slightly skewed, rather than using another JComponent to "act" as the shape, you should be using it to paint all the shapes through it's paintComponent method
From my "red rectangle" period...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Tester {
public static void main(String[] args) {
new Tester();
}
public Tester() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JPanel panel;
private JButton button;
private JLabel label;
private ShapePane shapePane;
public TestPane() {
setLayout(new BorderLayout());
button = new JButton("Rectangle");
panel = new JPanel();
label = new JLabel();
button.setVisible(true);
panel.add(button);
panel.add(label);
shapePane = new ShapePane();
add(shapePane);
add(panel, BorderLayout.SOUTH);
class ClickListener implements ActionListener {
private int X = 20;
private int Y = 20;
#Override
public void actionPerformed(ActionEvent arg0) {
int width = shapePane.getWidth();
int height = shapePane.getHeight();
int x = (int)(Math.random() * (width - 20)) + 10;
int y = (int)(Math.random() * (height - 20)) + 10;
int w = (int)(Math.random() * (width - x));
int h = (int)(Math.random() * (height - y));
shapePane.add(new Rectangle(x, y, w, h));
}
}
ActionListener listener = new ClickListener();
button.addActionListener(listener);
}
}
public class ShapePane extends JPanel {
private List<Shape> shapes;
public ShapePane() {
shapes = new ArrayList<>(25);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void add(Rectangle rectangle) {
shapes.add(rectangle);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
}
}
As to answer your basic question, you could have tried calling revalidate and repaint, but because of the BorderLayout I doubt it would have worked as you would have basically been trying to replace the panel with your ShapeChanger component, and there are better ways to do that

Component won't display unless window is resized - Java

I have problem with image visibility after click the button. I have the main class with frame:
package superworld;
import java.awt.*;
import javax.swing.*;
public class SuperWorld {
public static void main(String[] args) {
JFrame frame= new JFrame();
frame.setSize(1050,650);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SuperPanel());
frame.setVisible(true);
// frame.setResizable(false);
}
}
Then I have class with Panel with all components:
package superworld;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.Timer;
public class SuperPanel extends JPanel implements ActionListener{
Timer mainTimer;
public static final int HEIGHT = 550;
public static final int WIDTH = 1050;
int i;
int w=-100;
int h=-50;
ArrayList<SuperMiasto> miasta = new ArrayList<SuperMiasto>();
private JButton heroButton;
private JButton cywilButton;
public SuperPanel() {
mainTimer = new Timer(10,this);
heroButton = new HeroButton(this);
cywilButton = new CywilButton(this);
setLayout(null);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(Color.GREEN);
for(i=0;i<10;i++)
{
miasta.add( new SuperMiasto() );
miasta.get(i).x=w;
miasta.get(i).y=h;
miasta.get(i).imagelabel = new JLabel(miasta.get(i).image);
miasta.get(i).imagelabel.setBounds(miasta.get(i).x,miasta.get(i).y,miasta.get(i).image.getIconWidth(),miasta.get(i).image.getIconHeight());
add(miasta.get(i).imagelabel);
w=w+200;
if (w > WIDTH-200)
{
h=h+200;
w=-100;
}
}
}
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
add(heroButton);
add(cywilButton);
}
public void actionPerformed(ActionEvent e) {
repaint();
}
}
And Class with button with add new object with image:
package superworld;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class HeroButton extends JButton implements ActionListener {
private JPanel buttonPanel;
HeroButton(JPanel buttonPanel) {
super("Dodaj hero");
this.buttonPanel = buttonPanel;
setBounds(0,500,150,50);
addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
SuperLudzie batman = new SuperLudzie();
batman.imagelabel = new JLabel(batman.image);
batman.imagelabel.setBounds(50,50,batman.image.getIconWidth(),batman.image.getIconHeight());
buttonPanel.add(batman.imagelabel);
}
}
And class of this SuperLudzie:
package superworld;
import java.awt.*;
import javax.swing.*;
public class SuperLudzie {
private String imie;
private int zycie;
private int inteligencja;
private int wytrzymalosc;
private int sila;
private int umiejetnosci_walki;
private int x,y;
ImageIcon image = new ImageIcon("C:/Users/Zuzanna Sawala/Moje dokumenty/NetBeansProjects/SuperWorld/mysz.jpg");
JLabel imagelabel;
}
Everything work great. I have only problem with this object and image created by button it's not visible just after clicking but after i resize a window. I know that it have something to do with setVisibility(true); but i'm not sure where to use it.
Use SwingUtilities.invokeLater() or EventQueue.invokeLater() to make sure that EDT is initialized properly.
Use overridden paintComponent() method instead of paint()
class SuperPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
...
}
#Override
public Dimension getPreferredSize() {
return new Dimension(..., ...);
}
}
Read more points...
Try to avoid null layout and use proper layout that suits as per our need.
Please have a look at How to Use Various Layout Managers that has sole responsibilities for positioning and sizing of the components.

JFrame repaint(); error

So, I'm currently working on making a ball that moves on keyboard command. My problem is that when I call repaint();, it gives me an error saying that it "Cannot make a static reference to the non-static method repaint() from the type Component." What am I doing wrong?
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
public class App extends JFrame{
JFrame f = new JFrame();
public static int keyVal = 0, x = 10, y = 10;
public static void main(String[] args) {
new App();
Ball();
while(true){
System.out.println(keyVal);
try{
Thread.sleep(50);
}
catch(Exception e){}
}
}
public static void Ball(){
while(true){
if(keyVal == 65){
x = x -1;
}
else if(keyVal == 68){
x = x + 1;
}
repaint();
//repaint(x, y, 10, 20);
}
}
public App(){
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Pong");
f.setSize(30,40);
f.setLocationRelativeTo(null);
f.addKeyListener(new KeyListener(){
public void keyPressed(KeyEvent e){
keyVal = e.getKeyCode();
}
public void keyReleased(KeyEvent e){
keyVal = 0;
}
public void keyTyped(KeyEvent e){}
});
f.add(new MyPanel());
f.pack();
f.setVisible(true);
}
class MyPanel extends JPanel {
public MyPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
}
public Dimension getPreferredSize() {
return new Dimension(500,200);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("test");
g.setColor(Color.orange);
g.fillRect(x, y, 10, 20);
}
}
}
Your class is already a JFrame subclass. There's no need to create another JFrame. Take out the JFrame f = new JFrame() and all the f.method(..) just use method(..)
Don't use while(true) or Thread.sleep(). You will run into problem. Instead look into How to use a Swing Timer. Here is a simple example. You could also find many other examples just doing a simple google search on how to use Swing Timer
No need to setSize() to the frame, you already pack() it.
You should look into How to use Key Bindings. If not now, you will come to find that there are focus issues, among other things, with using a KeyListener.
Run your program from the Event Dispatch Thead, like this
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
new App();
}
});
}
Freebie
A simple implementation of a javax.swing.Timer would be something like this
public App() {
...
Timer timer = new Timer(50, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
// do something
}
});
}
Here is the basic construct of the Timer
Timer( int dalay, ActionListener listener )
The delay it the amount of milliseconds delayed for each time the event is fired. So in the above code, for every 50 milliseconds, something will happen. This will achieve what you are trying to do with the Thread.sleep. You can call the repaint() from inside the actionPerformed
Here's a simple refactor of your code, that you can test out
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class App extends JFrame {
private MyPanel panel = new MyPanel();
public static int keyVal = 0, x = 10, y = 10;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new App();
}
});
}
public App() {
Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
x = x + 5;
panel.repaint();
}
});
timer.start();
add(panel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Pong");
pack();
setLocationRelativeTo(null);
setVisible(true);
}
class MyPanel extends JPanel {
public MyPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
}
public Dimension getPreferredSize() {
return new Dimension(500, 200);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("test");
g.setColor(Color.orange);
g.fillRect(x, y, 10, 20);
}
}
}

Categories