Problem definition: I want to use graphics in java to print ball and a rectangle ,the ball should move towards the rectangle by arrow keys or mouse moved.
the Problem with the code is that it is printing the ball, again and again, I want to print the ball once only
public class MouseGui extends javax.swing.JFrame implements
MouseMotionListener, MouseListener, KeyListener {
int x = 10, y = 10;
public MouseGui() {
initComponents();
addKeyListener(this);
addMouseListener(this);
}
#Override
public void paint(final Graphics g) {
g.setColor(Color.red);
g.fillOval(x, y, 50, 50);
g.setColor(Color.blue);
g.fillRect(200, 300, 100, 80);
if (x > 180 || y > 280) {
g.drawString("Target hit!!", 80, 20);
}
}
public static void main(final String args[]) {
MouseGui obj = new MouseGui();
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new MouseGui().setVisible(true);
}
});
}
#Override
public void mouseMoved(final MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override
public void keyPressed(final KeyEvent e) {
int a = e.getKeyCode();
if (e.getKeyCode() == VK_UP) {
y = y - 10;
repaint();
} else if (e.getKeyCode() == VK_DOWN) {
y = y + 10;
repaint();
} else if (e.getKeyCode() == VK_RIGHT) {
x = x + 10;
repaint();
} else if (e.getKeyCode() == VK_LEFT) {
x = x - 10;
repaint();
}
}
}
Here is how this code shows output :
The problem is not that the ball gets painted multiple times, the problem is that old drawings are never cleared.
When you override paint methods, it is recommended that you call the super method, so that it does its own stuff first .
Calling super.paint(g) here , will clear the Graphics object :
#Override
public void paint(final Graphics g) {
super.paint(g);
g.setColor(Color.red);
g.fillOval(x, y, 50, 50);
g.setColor(Color.blue);
g.fillRect(200, 300, 100, 80);
if (x > 180 || y > 280) {
g.drawString("Target hit!!", 80, 20);
}
}
Also, as suggested by #JoopEggen, when doing custom painting on Swing components, you usually use a lower-level component like a JPanel and override its paintComponent method, i.e :
#Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(x, y, 50, 50);
g.setColor(Color.blue);
g.fillRect(200, 300, 100, 80);
if (x > 180 || y > 280) {
g.drawString("Target hit!!", 80, 20);
}
}
See this lesson to get some examples : Performing Custom Painting
Calling super.paintComponent(g) is a must.
Related
I've done this plenty of times but I'm stuck. I've checked previous projects of mine and can't find the answer. The rectangle is supposed to show up at 400,400 and be 100,100 big, (Bottom right corner). When the start button is press I want it to show the rectangle. Thanks in advance!
!!!: There are multiple classes in this I just didn't post them since they don't have a use, if they do I'll post them.
class MazeRunner extends JFrame implements ActionListener, MouseMotionListener {
JButton b1;
int pkp = 0;
MazeRunner(){
b1= new JButton("Start");
add(b1);
b1.addActionListener(this);
b1.setBounds(10,10,50,50);
addMouseMotionListener(this);
setTitle("Maze Runner");
setLayout(null);
setSize(500, 500);
setResizable(false);
setVisible(true);
}
public static void main(String[] args) {
new MazeRunner();
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == b1){
remove(b1);
pkp++;
validate();
repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
if (pkp == 1) {
if(e.getX() >= 400 && e.getX() <= 500 && e.getY() >= 400 && e.getY() <= 500) {
dispose();
}
}
}
protected void paintComponent(Graphics g) {
draw(g);
}
private void draw(Graphics g) {
if(pkp == 1) {
g.setColor(Color.BLACK);
g.fillRect(400, 400, 100, 100);
}
repaint();
}
}
First of all the method paintComponent() is missing it's constructor so it should look like
public void paintComponent(Graphics g){
super.paintComponent(g);
draw(g);
}
second of all, im not sure if Graphics g object has a method called "fillRect"
so I would recommend you to convert it to object of type Graphics2D, so in this case it would be:
public void draw(Graphics g){
Graphics2D g2 = (Graphics2D) g;
if(pkp == 1) {
g2.setColor(Color.BLACK);
g2.fillRect(400, 400, 100, 100);
}
repaint();
}
I'm writing an application that has a "Drawing area" where the user is to place components. The drawing area contains a grid that the components will snap to, but and it works fine when I resize the window and such
; but when I pan the area, the grid does not redraw itself.
How would I go about drawing the new area and repainting? I create the grid when I override paintComponent(...) by looping through the x and y space in the window and using g.drawLine(...) every 10 units. Based on this example, I pan using a MouseMotionListener in the constructor for my Drawing class which extends JPanel.
public final class Drawing extends JPanel {
private int spacing;
private Point origin = new Point(0,0);
private Point mousePt;
/**
* Default Constructor for Drawing Object. Calls JPanel default constructor.
*/
public Drawing() {
super();
spacing = 10;
setBackground(new Color(255, 255, 255));
setBorder(BorderFactory.createLineBorder(new Color(0, 0, 0)));
GroupLayout workspacePanelLayout = new GroupLayout(this);
setLayout(workspacePanelLayout);
workspacePanelLayout.setHorizontalGroup(workspacePanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING).addGap(0, 343, Short.MAX_VALUE));
workspacePanelLayout.setVerticalGroup(workspacePanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING).addGap(0, 400, Short.MAX_VALUE));
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent evt) {
// this stuff is mainly for debugging....
mousePt = evt.getPoint();
System.out.println((mousePt.x - origin.x) + "," + (mousePt.y - origin.
System.out.println(origin.x + ", " + origin.y);
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
//this is what is more important.
#Override
public void mouseDragged(MouseEvent evt) {
if (evt.getButton() == MouseEvent.BUTTON2 || xorlogic.Window.cursorState == 1) {
int dx = evt.getX() - mousePt.x;
int dy = evt.getY() - mousePt.y;
origin.setLocation(origin.x+dx, origin.y+dy);
mousePt = evt.getPoint();
repaint();
}
}
});
}
and the paintComponent(...) which is implemented later:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(0, origin.y, getWidth(), origin.y);
g.drawLine(origin.x, 0, origin.x, getHeight());
// set up grid
int x = 0;
int y = 0;
g.setColor(new Color(220, 220, 220));
while (x < getWidth()) {
g.drawLine(origin.x + x, 0, origin.x + x, getHeight());
x += getSpacing();
}
while (y < getHeight()) {
g.drawLine(0, origin.y + y, getWidth(), origin.y + y);
y += getSpacing();
}
}
I really appreciate your help. Thanks!
The best way to pan is to use Graphics2D.scale that way you can (a) avoid complicated logic in your paintComponent and (b) make panning a reusable feature, as shown here
https://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/ui/drag/Zoomable.java#l58
i am trying to make a simple java game with a bat(paddle) and ball. So far i have painted the 2 objects onto the panel, however i cant get them to move. i have added key events for the bat and a move() method for the ball. Below are all my classes.
Game class:
public class Game extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Game();
}});
}
MyDrawingPanel myDrawingPanel = new MyDrawingPanel(this);
MyUIPanel myUIPanel = new MyUIPanel(this);
public Game()
{
setSize(1160,660); // you may change frame and panel sizes
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(myDrawingPanel);
cp.add(myUIPanel);
setVisible(true);
}
}
MyDrawingPanel class:
class MyDrawingPanel extends JPanel {
Game game;
Ball ball = new Ball(this);
Bat bat = new Bat(this);
public MyDrawingPanel(Game game)
{
this.game=game;
setPreferredSize(new Dimension(800,600));
setBackground(Color.RED);
requestFocus();
}
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
Graphics2D gBat = (Graphics2D) g;
bat.paint(gBat);
}
}
Ball class:
public class Ball {
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
private MyDrawingPanel myDrawingPanel;
public Ball(MyDrawingPanel myDrawingPanel) {
this.myDrawingPanel = myDrawingPanel;
}
public void move() {
if (x + xa < 0)
xa = 1;
if (x + xa > myDrawingPanel.getWidth() - 30)
xa = -1;
if (y + ya < 0)
ya = 1;
if (y + ya > myDrawingPanel.getHeight() - 30)
ya = -1;
x = x + xa;
y = y + ya;
}
public void paint(Graphics2D g) {
g.fillOval(x, y, 30, 30);
}
}
Bat class:
public class Bat{
int x = 0;
int xa = 0;
private MyDrawingPanel myDrawingPanel;
public Bat(MyDrawingPanel myDrawingPanel)
{
this.myDrawingPanel = myDrawingPanel;
}
public void move(){
if(x + xa > 0 && x + xa <myDrawingPanel.getWidth()-60 )
x = x + xa;
}
public void paint(Graphics2D g)
{
g.setColor(Color.BLUE);
g.fillRoundRect(x, 500, 100, 20, 10, 10);
}
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if(e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
public void keyReleased(KeyEvent e)
{
xa = 0;
}
}
Methods such as keyPressed and keyReleased don't do anything without a KeyListener implementation. So currently, your methods are useless. What you should do have the DrawingPanel class implement the KeyListener, like this
public class DrawingPanel extends JPanel implements KeyListener {
...
}
The methods, keyPressed and keyReleased should be in that class. You'll also want setter methods for what ever variables are updated in the Bat class, like x and xa, is those are the variables that determine the movement of the Bat.
So in the keyPressed, which should be in the DrawingPanel class, it could look something like this
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
bat.setXa(bat.getXa() - 1);
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
bat.setXa(1);
repaint();
}
}
Notice how I call repaint(). That's what you need to do after you move something.
This should get you started in the right direction
EDIT Forget the majority of the above answer.
Instead of using a KeyListener though I would recommeng using key binding. You may face focus problems using KeyListener. I implemented the keybinding for the DrawingPanel and it works fine. It'll give you some ideas to work with.
class MyDrawingPanel extends JPanel {
Game game;
Ball ball = new Ball(this);
Bat bat = new Bat(this);
public MyDrawingPanel(Game game) {
this.game = game;
setPreferredSize(new Dimension(800, 600));
setBackground(Color.RED);
requestFocus();
Action rightAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
bat.x += 10;
repaint();
}
};
Action leftAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
bat.x -= 10;
repaint();
}
};
InputMap inputMap = getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "rightAction");
actionMap.put("rightAction", rightAction);
inputMap.put(KeyStroke.getKeyStroke("LEFT"), "leftAction");
actionMap.put("leftAction", leftAction);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
Graphics2D gBat = (Graphics2D) g;
bat.paint(gBat);
}
}
See How to use key bindings
I have been following the Java Game Programming for Beginners tutorial series, and wished to experiment by applying a background image. Unfortunately, when I render it through the paintComponent method, it moves with my sprite (albeit at one unit continuously as opposed to five); and when I render it through the paint method, I get a strange, flickering box that matches the color designated in the setBackground (color) property of the JFrame and it moves with the sprite identically to that of the prior instance (within paintComponent).
How might I code the image so as to remain static, as a background should be?
Code:
public class JavaGame extends JFrame{
int x, y;
private Image dbImage;
private Graphics dbg;
Image ghost;
Image bg;
public class AL extends KeyAdapter{
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT){
if(x <= 8)
x = 8;
else
x += -5;
}
if(keyCode == e.VK_RIGHT){
if(x >= 235)
x = 235;
else
x += +5;
}
if(keyCode == e.VK_UP){
if(y <= 18)
y = 18;
else
y += -5;
}
if(keyCode == e.VK_DOWN){
if(y >= 235)
y = 235;
else
y += +5;
}
}
public void keyReleased(KeyEvent e){
}
}
public JavaGame(){
//Load images
ImageIcon i = new ImageIcon("C:/Users/Taylor/workspace/Java game/src/ghost.png");
ghost = i.getImage();
ImageIcon j = new ImageIcon("C:/Users/Taylor/workspace/Java game/src/bg.png");
bg = j.getImage();
//Game properties
addKeyListener(new AL());
setTitle("Java Game");
setSize(500, 500);
setResizable(false);
setVisible(true);
setBackground(Color.GRAY);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 150;
y = 150;
}
public void paint(Graphics g){
g.drawImage(bg, 0, 0, null);
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, x, y, this);
}
public void paintComponent(Graphics g){
g.setColor(Color.WHITE);
g.drawImage(ghost, x, y, this);
repaint();
}
public static void main(String[] args) {
new JavaGame();
}
Pictures:
Were you copy/pasting code at random? That is what it looked like. There were so many odd aspects to that code that I did not document them all (a good one for code review, maybe). The example uses an asynchronous method to load the images (in order to get the animated image, animating). Use ImageIO.read(URL) for a synchronous way to load static images.
Here are some brief tips:
By the time this becomes deployed, the images will likely become an embedded resource and will not be accessible by File object. Add them to the run-time class-path and access them by URL.
Swing GUIs should be started and altered on the EDT (see the change to the main()).
Always call super.paint(g); (or paintComponent(g)) at the start of the method.
Don't extend frame, don't paint to a top level component. Instead extend panel and override paintComponent(). Add the panel to the frame.
Code
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
import javax.swing.*;
public class JavaGame extends JPanel {
int x, y;
private Image dbImage;
private Graphics dbg;
Image ghost;
Image bg;
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
if (x <= 8)
x = 8;
else
x += -5;
}
if (keyCode == e.VK_RIGHT) {
if (x >= 235)
x = 235;
else
x += +5;
}
if (keyCode == e.VK_UP) {
if (y <= 18)
y = 18;
else
y += -5;
}
if (keyCode == e.VK_DOWN) {
if (y >= 235)
y = 235;
else
y += +5;
}
}
public void keyReleased(KeyEvent e) {
}
}
public JavaGame() throws Exception {
// Load images
//ImageIcon i = new ImageIcon(
// "C:/Users/Taylor/workspace/Java game/src/ghost.png");
URL urlGhost = new URL("http://1point1c.org/gif/thum/plnttm.gif");
ghost = Toolkit.getDefaultToolkit().createImage(urlGhost);
//ImageIcon j = new ImageIcon(
// "C:/Users/Taylor/workspace/Java game/src/bg.png");
URL urlBG = new URL("http://pscode.org/media/stromlo2.jpg");
bg = Toolkit.getDefaultToolkit().createImage(urlBG);
setFocusable(true);
// Game properties
addKeyListener(new AL());
x = 150;
y = 150;
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
repaint();
}
};
Timer timer = new Timer(50,al);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bg, 0, 0, null);
//dbImage = createImage(getWidth(), getHeight());
//dbg = dbImage.getGraphics();
//paintComponent(dbg);
g.drawImage(dbImage, x, y, this);
g.setColor(Color.WHITE);
g.drawImage(ghost, x, y, this);
//repaint();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
JFrame f = new JFrame("Java Game");
f.setSize(500, 500);
f.setResizable(false);
f.setVisible(true);
f.setBackground(Color.GRAY);
f.setContentPane(new JavaGame());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
I need to draw a rectange,circle and line and then animate them(press left -> it(all objects) moves left for examp.)
I draw objects like this
class MyCanvas extends JComponent {
int x = 10;
int y = 10;
public MyCanvas()
{
Action someaction = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e) {
x+=30;
//revalidate();
repaint();
}
};
this.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), someaction);
}
#Override
public void paintComponent(Graphics g) {
g.drawRect(x,y, 200, 200);
g.drawOval(x, y, 50, 50);
g.drawLine(x, y, 50, 30);
}
}
But it doesn't move.
use paintComponent(Graphics g) for Swing JComponents instead of paint(Graphics g)
use KeyBindings for KeyEvents for Swing JComponents
put Objects (prepare before paintComponent(Graphics g)) to the Array, paint elements from Array in paintComponent(Graphics g)