problems with drawing and displaying shapes on images - java

Please bear with me, english is neither my first nor my second language.
The basic idea is to load images and draw a few shapes using the mouse.
I created these three java classes (see code at the botoom end):
1 Main, right now this is only used to initiate the second class "Action"
2 Action, this class should contain every action the user performs on the ui (drawing, loading images...)
3 UI, this class creates the UI and holds every object concerning the UI (Jlabels, JButtons, JFrame ....)
At this stage it (kinda) works as intended but i have still a few questions. I tried to visualise every problem but i can only use 2 images in this post, so please use this image.
1) Drawing shapes works as itended but as soon as the user creates (releases the mousebutton) the shape it should be displayed in blue colours. This doesn't work unless a new shape is drawn. How can i update the shape after the user releases the button? As seen in the first and second frame of the linked image.
-- solved
added a call to paint(); in the mouseReleased event.
2) The first shape is darker/a fuller colour than the rest of the shapes, see second and fifth frame in the linked image. I am not sure how to correct this one, any ideas?
--solved
exchanged this two lines
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
g2d.fill(shape);
3) None of the shapes are visiable after resizing the UI, as seen in the third and foruth frame of the linked image. How do i force the program to draw them?
-- solved
added ComponentListener to the JFrame, now calling paint() in the componentResized() event
3.1) How do i get the shapes to stay within the original image (the black square) after resizing? Fourth frame of the linked image.
-- solved
i forgot to add an offset if the frame was resized....
4) Checking if the mouse is still within the borders of the image works only if the user doesn't use the scrollpanes. Does anyone have a better idea to check if the mouse is within the image borders?
5) The shapes flicker during drawing if there is more than one shape, i guess because they are drawn everytime the user drags the mouse while drawing. How to fix this problem?
Don't hesitate to point out anything else that is wrong or really the best coding practice.
Thank you in advance.
update
-added titels
-changed formating
-added the described changes
Main class
public class Main {
public static void main(String[] args) {
new Action();
}
}
UIclass
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
public class UI {
public JLabel jlabel_image;
public JFrame jframe_ui;
public JLabel jlabel_info;
private Action action;
private JScrollPane jscrollpane_image;
public UI(Action action) {
this.action = action;
jlabel_image = new JLabel();
jlabel_image.setHorizontalAlignment(jlabel_image.CENTER);
jlabel_image.setVerticalAlignment(jlabel_image.CENTER);
jlabel_image.addMouseListener(action);
jlabel_image.addMouseMotionListener(action);
jscrollpane_image = new JScrollPane(jlabel_image);
jlabel_info = new JLabel("mouse: ");
jframe_ui = new JFrame("test frame");
jframe_ui.addComponentListener(action);
jframe_ui.setPreferredSize(new Dimension(500,500));
jframe_ui.getContentPane().setLayout(new BorderLayout());
jframe_ui.setMinimumSize(new Dimension(500,500));
jframe_ui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe_ui.add(jscrollpane_image, BorderLayout.CENTER);
jframe_ui.add(jlabel_info, BorderLayout.SOUTH);
jframe_ui.pack();
jframe_ui.setVisible(true);
}
}
Action class
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.ImageIcon;
public class Action implements ActionListener, ComponentListener, MouseListener, MouseMotionListener {
private UI ui;
private Point startpoint;
private Point endpoint;
private ArrayList<Shape> shapes;
private boolean mouseonimage;
public Action() {
ui = new UI(this);
shapes = new ArrayList<Shape>();
mouseonimage = false;
BufferedImage bufferedimage = new BufferedImage(800, 800, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bufferedimage.createGraphics();
g2.setPaint(Color.BLACK);
g2.fillRect(0, 0, 800, 800);
g2.dispose();
ui.jlabel_image.setIcon(new ImageIcon(bufferedimage));
}
#Override
public void componentHidden(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void componentMoved(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void componentResized(ComponentEvent arg0) {
// TODO Auto-generated method stub
paint();
}
#Override
public void componentShown(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseDragged(MouseEvent me) {
// TODO Auto-generated method stub
if(mouseonimage) {
if(checkMouseCoordinates(me.getPoint())) {
endpoint = me.getPoint();
paint();
}
}
}
#Override
public void mouseMoved(MouseEvent me) {
// TODO Auto-generated method stub
checkMouseCoordinates(me.getPoint());
}
#Override
public void mouseClicked(MouseEvent me) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent me) {
// TODO Auto-generated method stub
mouseonimage = true;
checkMouseCoordinates(me.getPoint());
}
#Override
public void mouseExited(MouseEvent me) {
// TODO Auto-generated method stub
mouseonimage = false;
checkMouseCoordinates(me.getPoint());
}
#Override
public void mousePressed(MouseEvent me) {
// TODO Auto-generated method stub
if(mouseonimage) {
if(me.getButton() == MouseEvent.BUTTON1) {
if(checkMouseCoordinates(me.getPoint())) {
startpoint = me.getPoint();
endpoint = me.getPoint();
}
}
}
}
#Override
public void mouseReleased(MouseEvent me) {
// TODO Auto-generated method stub
if(checkMouseCoordinates(me.getPoint())) {
endpoint = me.getPoint();
}
if(startpoint != null) {
if(Math.abs(startpoint.x - endpoint.x) > 9) {
if(Math.abs(startpoint.y - endpoint.y) > 9) {
shapes.add(createrectangle(startpoint, endpoint));
}
}
}
startpoint = null;
endpoint = null;
paint();
}
#Override
public void actionPerformed(ActionEvent me) {
// TODO Auto-generated method stub
}
public boolean checkMouseCoordinates(Point point) {
boolean withinBoarders = false;
if(mouseonimage) {
int imageFrameWidth = ui.jlabel_info.getBounds().width;
int imageFrameHeight = ui.jlabel_info.getBounds().y;
int imageWidth = ui.jlabel_image.getIcon().getIconWidth();
int imageHeight = ui.jlabel_image.getIcon().getIconHeight();
int x = 0;
int y = 0;
int w = imageFrameWidth;
int h = imageFrameHeight;
System.out.println(ui.jlabel_info.getBounds());
if(imageFrameWidth > imageWidth) {
x = (imageFrameWidth - imageWidth)/2 - 9;
w = imageWidth;
}
if(imageFrameHeight > imageHeight) {
y = (imageFrameHeight - imageHeight)/2;
h = imageHeight;
if(imageFrameWidth > imageWidth) {
x = x + 7;
}
if(imageFrameHeight > imageHeight) {
y = y - 1;
}
}
Rectangle imageFrame = new Rectangle(x, y, w, h);
if(imageFrame.contains(point)) {
withinBoarders = true;
ui.jlabel_info.setText(String.format("mouse: on image :: %d/%d :: %d/%d :: %d/%d||%d/%d",point.x, point.y, imageFrameHeight, imageFrameWidth, imageFrame.x, imageFrame.width, imageFrame.y, imageFrame.height));
} else {
ui.jlabel_info.setText(String.format("mouse: not on image %d/%d",point.x, point.y));
}
} else {
ui.jlabel_info.setText("mouse: not on image");
}
return withinBoarders;
}
private Shape createrectangle(Point start, Point end) {
int image_x = (ui.jlabel_image.getWidth() - ui.jlabel_image.getIcon().getIconWidth()) / 2;
int image_y = (ui.jlabel_image.getHeight() - ui.jlabel_image.getIcon().getIconHeight()) / 2;
int image_w = ui.jlabel_image.getIcon().getIconWidth();
int image_h = ui.jlabel_image.getIcon().getIconHeight();
int x = start.x;
int y = start.y;
int h = end.y;
int w = end.x;
x = x < image_x ? image_x : x;
x = x > (image_x + image_w - 1) ? (image_x + image_w - 1) : x;
w = w < image_x ? image_x : w;
w = w > (image_x + image_w - 1) ? (image_x + image_w - 1) : w;
y = y < image_y ? image_y : y;
y = y > (image_y + image_h - 1) ? (image_y + image_h - 1) : y;
h = h < image_y ? image_y: h;
h = h > (image_y + image_h - 1) ? (image_y + image_h - 1) : h;
return new Rectangle2D.Float(Math.min(x, w), Math.min(y, h), Math.abs(x - w), Math.abs(y - h));
}
private void paint() {
Graphics g;
g = ui.jlabel_image.getGraphics();
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(new BufferedImage(ui.jlabel_image.getIcon().getIconWidth(), ui.jlabel_image.getIcon().getIconHeight(), BufferedImage.TYPE_INT_RGB), (ui.jlabel_image.getWidth() - ui.jlabel_image.getIcon().getIconWidth()) / 2, (ui.jlabel_image.getHeight() - ui.jlabel_image.getIcon().getIconHeight()) / 2, null);
for(Shape shape: shapes) {
g2d.setPaint(Color.BLUE);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
g2d.fill(shape);
g2d.setPaint(Color.BLUE);
g2d.draw(shape);
}
if(startpoint != null) {
if(endpoint != null) {
g2d.setPaint(Color.RED);
g2d.draw(createrectangle(startpoint, endpoint));
}
}
}
}

For the fist problem you have to repaint in order to see the changes, just add a single line:
#Override
public void mouseReleased(MouseEvent me) {
endpoint = me.getPoint();
if(Math.abs(startpoint.x - endpoint.x) > 9) {
if(Math.abs(startpoint.y - endpoint.y) > 9) {
shapes.add(createrectangle(startpoint, endpoint));
}
}
// Add this line
paint();
startpoint = null;
endpoint = null;
}
The second problem, I think is caused because you are telling the graphics to composite the
destination (i.e, the graphics of the image you already have) to have an alpha value of 0.5.
Try to change this code:
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
for this
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
Right now I don't have time, but later I can help you. Also I think there are better ways of achieving that. For example using a Jpanel instead of a Jlabel or an ImageIcon

Related

Why is my Mario clone game sprite getting cut off when I try to change it? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
BIG EDIT: I have now a MCVE for this
In my Super Mario 3 clone, my sprite draws correctly upon instantiating the JFrame, but when I press one of the buttons I've set to jump, it gets partially cut off. Everything on the screen is a JLabel.
Here is the code:
//for all
import java.nio.file.*;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.awt.image.*;
import java.net.*;
import java.awt.*;
import javax.swing.*;
import static java.lang.invoke.MethodHandles.*;
import java.awt.event.*;
//my Mario class (cut down a lot)
class Mario {
// all numbers multiplied by 2 from OG game
protected Direction dir;
protected int x, y;
protected BufferedImage sprite;
public Mario() {
this.x = 54;
this.y = 808;
dir = Direction.RIGHT;
setSprite(MVCE.SMALLSTANDFACERIGHT);
}
public void moveRight() {
if (this.dir == Direction.LEFT) {
this.dir = Direction.RIGHT;
} else if (this.dir == Direction.RIGHT) {
this.x += 2;
}
}
public void jump() {
this.y -= 46;
}
public void setSprite(String spriteName) {
URL spriteAtLoc = MVCE.urlGenerator(spriteName);
this.sprite = MVCE.generateAndFilter(sprite, spriteAtLoc);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(sprite, 0, 0, null); // DO NOT SET x and y TO ANYTHING,
// this sets 0,0 to top left!!
}
}
// my MarioRender class:
class MarioRender extends JLabel {
protected Mario marioSprite;
public MarioRender() {
marioSprite = new Mario();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
marioSprite.paint(g2);
}
public void moveMarioRight() {
marioSprite.moveRight();
setLocation(this.marioSprite.x, this.marioSprite.y);
repaint();
}
public void jumpMario() {
marioSprite.jump();
setLocation(this.marioSprite.x, this.marioSprite.y);
repaint();
}
}
// direction class, solely for moving
enum Direction {
LEFT, RIGHT
}
// my calling class, which I called MVCE where I make the frame
public class MVCE extends JFrame {
MarioRender m = new MarioRender();
JLabel bg;
public MVCE() {
bg = new JLabel();
this.setSize(868, 915);
this.setVisible(true);
this.add(bg, BorderLayout.CENTER);
bg.setLayout(null);
bg.add(m);
m.setBounds(m.marioSprite.x, m.marioSprite.y, m.marioSprite.sprite.getWidth(),
m.marioSprite.sprite.getHeight());
KeyListener kl = new MoveListener();
this.addKeyListener(kl);
this.setFocusable(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static final String SMALLSTANDFACERIGHT = "SmallStandFaceRight.bmp"; // 30
// x
// 32
public static final String SMALLJUMPFACERIGHT = "SmallJumpFaceRight.bmp"; // 32
// x
// 32
// generate URL
public static URL urlGenerator(String name) {
URL u = lookup().lookupClass().getResource(name);
return u;
}
// return image with filtered color
public static BufferedImage generateAndFilter(BufferedImage b, URL u) {
try {
b = ImageIO.read(u);
int width = b.getWidth();
int height = b.getHeight();
int[] pixels = new int[width * height];
b.getRGB(0, 0, width, height, pixels, 0, width);
for (int i = 0; i < pixels.length; i++) {
// System.out.println(pixels[i]);
if (pixels[i] == 0xFFff00fe) {
pixels[i] = 0x00ff00fe;
}
}
BufferedImage newSprite = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
newSprite.setRGB(0, 0, width, height, pixels, 0, width);
b = newSprite;
} catch (IOException e) {
System.out.println("sprite not found");
e.printStackTrace();
}
return b;
}
// key listener
class MoveListener implements KeyListener {
public void keyPressed(KeyEvent k) {
if ((k.getKeyCode() == 39)) {
m.marioSprite.setSprite(SMALLSTANDFACERIGHT);
m.moveMarioRight();
}
if (k.getKeyCode() == 83) { // S key
m.marioSprite.setSprite(SMALLJUMPFACERIGHT);
m.jumpMario();
}
}
public void keyReleased(KeyEvent k) {
}
public void keyTyped(KeyEvent k) {
}
}
public static void main(String[] args) {
MVCE m = new MVCE();
}
}
sprites can be found here and here tho the downloads are in .jpg, whereas in my code, they're .bmp but you can just download, open in another app, save as bmp, or change the code
This is most likely a result of the horizontal and vertical constraints on your JLabel objects. From the look of the picture, the Mario that is jumping is slightly wider horizontally than the Mario standing on the ground.

Java Swing Rectangel2D: how to select the one on the top [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
easy question:
I draw more than one Rectangel2D (or other shapes) in one JPane with overlapping.
I want to select the one on the top by click the overlapping area and do something, e.g. change color or drag.
But I can't select the one which I want.
The order of the Shapes is not under control.
I find a method setComponentZOrder, but that is for component not for Rectangel2D.
I think this is a typical question, but I can't find the answer.
The order that a Shape such as a Rectangle2D are drawn is determined by the order that they are held in whatever collection holds them as this collection is iterated through in your JComponent's (such as a JPanel's) painting method. Thus the last items in the collection, be it an array or ArrayList or LinkedList, is drawn on top.
So if you want to get the top Shape on mouse press or click, then the key will be to iterate through the same collection backwards, getting the first Shape that contains(Point p) the mouse Point location. That's it.
For example, please look at my code here which does just his in this method which is called from the MouseListener (actually MouseAdapater):
public Shape getShapeAtPoint(Point p) {
Shape shapeAtPoint = null;
for (int i = shapeList.size() - 1; i >= 0; i--) {
if (shapeList.get(i).contains(p)) {
return shapeList.get(i);
}
}
return shapeAtPoint;
}
For example:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class RandomShapes extends JPanel {
private static final Stroke STROKE = new BasicStroke(4f);
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final int SHAPE_COUNT = 30;
private static final int SHAPE_WIDTH = 100;
private static final int SHAPE_HEIGHT = SHAPE_WIDTH;
private List<Path2D> paths = new ArrayList<>();
private Map<Path2D, Color> colorMap = new HashMap<>();
private Random random = new Random();
public RandomShapes() {
for (int i = 0; i < SHAPE_COUNT; i++) {
Shape shape = createRandomShape(i);
Path2D path = new Path2D.Double(shape);
paths.add(path);
colorMap.put(path, createRandomColor());
}
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
private class MyMouse extends MouseAdapter {
private Path2D selectedPath = null;
private Point p1;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
for (int i = paths.size() - 1; i >= 0; i--) {
Path2D path = paths.get(i);
if (path.contains(e.getPoint())) {
selectedPath = path;
p1 = e.getPoint();
paths.remove(selectedPath);
paths.add(selectedPath);
repaint();
break;
}
}
}
private void movePath(MouseEvent e) {
Point p2 = e.getPoint();
int tx = p2.x - p1.x;
int ty = p2.y - p1.y;
p1 = p2;
AffineTransform at = AffineTransform.getTranslateInstance(tx, ty);
selectedPath.transform(at);
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
if (selectedPath != null) {
movePath(e);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (selectedPath != null) {
movePath(e);
}
selectedPath = null;
}
}
private Color createRandomColor() {
float min = 0.2f;
float h = random.nextFloat();
float s = min * random.nextFloat() + (1f - min);
float b = min * random.nextFloat() + (1f - min);
return Color.getHSBColor(h, s, b);
}
private Shape createRandomShape(int i) {
Dimension size = getPreferredSize();
int x = random.nextInt(size.width - SHAPE_WIDTH);
int y = random.nextInt(size.height - SHAPE_HEIGHT);
switch (i % 3) {
case 0:
return new Ellipse2D.Double(x, y, SHAPE_WIDTH, SHAPE_HEIGHT);
case 1:
return new Rectangle2D.Double(x, y, SHAPE_WIDTH, SHAPE_HEIGHT);
case 2:
return new RoundRectangle2D.Double(x, y, SHAPE_WIDTH, SHAPE_HEIGHT, 15, 15);
default:
break;
}
return null;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(STROKE);
for (Path2D path : paths) {
g2.setColor(colorMap.get(path));
g2.fill(path);
g2.setColor(colorMap.get(path).darker());
g2.draw(path);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("RandomShapes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RandomShapes());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Note that if you want to delete a shape on right mouse click (MouseEvent.BUTTON3), this edit to the MyMouse MouseAdapter class can make this happen (see comments in code):
private class MyMouse extends MouseAdapter {
private Path2D selectedPath = null;
private Point p1;
#Override
public void mousePressed(MouseEvent e) {
int button = e.getButton();
// if the *middle* mouse button is pushed, ignore it
if (button == MouseEvent.BUTTON2) {
return;
}
// iterate through all the shapes,
// starting at the top of the list (last drawn shapes)
for (int i = paths.size() - 1; i >= 0; i--) {
Path2D path = paths.get(i);
if (path.contains(e.getPoint())) {
// if the mouse presses on one of the shapes
selectedPath = path;
p1 = e.getPoint();
// remove the shape from the collection
paths.remove(selectedPath);
if (button == MouseEvent.BUTTON1) {
// re-add it back in at the end of the collection
// only if the left mouse button has been pressed
paths.add(selectedPath);
}
repaint();
break;
}
}
}
// ....
}

Java Graphics Not Displaying In OS X

I'm a Computer Science student who uses a mid-2009 MacBook Pro running OS X Yosemite 10.10.3. I recently had a class activity in my Object-Oriented programming class where we went step-by-step in creating an interactive Java program in which the user simply clicks a football and watch it get kicked over the goalpost with a green background.
However, even though my Java code matched the code of my classmates' Windows computers with no syntax errors, there are some problems with my program properly running while theirs work perfectly fine:
While the window for the application opens with the title and green background, neither the football nor goalpost is displayed. However, if I manually stretch the window, they show back up. I've tried changing the window dimensions to see if that was causing it to no avail.
When the football is clicked, instead of moving towards the goalpost as intended, both the football and goalpost vanish and don't return. Only the green background is displayed, even when I try manually stretching the window again.
I still submitted the code to my instructor, which worked fine on his computer (he doesn't understand the problem either since he doesn't use OS X). I tried to run the code on two other IDE's to see if Eclipse was the problem, but they all produced the same results. If this is an OS X or computer-exclusive problem, how am I able to get around this?
This is my current code:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class Football extends JFrame {
final int WINDOW_WIDTH = 800;
final int WINDOW_HEIGHT = 400;
private int x = 40; // Ball's X coordinate
private int y = 300; // Ball's Y coordinate
private final int WIDTH = 35; // Ball's width
private final int HEIGHT = 60; // Ball's height
private final int X_MOVE = 14; // Pixels to move ball
private final int Y_MOVE = 4;
private final int TIME_DELAY = 25; // Time delay
private Timer timer; // Timer object
/**
init method
*/
public Football() {
setTitle("Football");
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
// Set Background to a Dark Green
getContentPane().setBackground(new Color(0, 220, 50));
// initTimer();
addMouseListener(new FbMouseListener());
}
public void paint(Graphics g)
{
// Call the superclass paint method.
super.paint(g);
// Set the color to Brown
g.setColor(new Color(129, 74, 25));
// Draw the football
g.fillOval(x, y, WIDTH, HEIGHT);
// Draw the Goalpost
g.setColor(Color.YELLOW);
g.fillRect(670, 240, 5, 140);
g.fillRect(610, 80, 5, 140);
g.fillRect(740, 120, 5, 140);
// Need Thicker line
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(5));
g2.drawLine(612, 220, 742, 260);
}
private class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent e) {
// Update the ball's position
y -= Y_MOVE;
x += X_MOVE;
// Force a call to the paint method
repaint();
}
}
public void initTimer()
{
timer = new Timer(TIME_DELAY, new TimerListener());
timer.start();
}
private class FbMouseListener implements MouseListener
{
public void mouseClicked(MouseEvent e)
{
if (e.getX() >= x && e.getX() <= (x + WIDTH) && e.getY() >= y && e.getY() <= (y + HEIGHT))
{
initTimer();
}
}
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
public static void main(String[] args)
{
Football fb = new Football();
}
}
Any help or suggestions would be appreciated, as I would like to make sure this doesn't affect any future programs I create.
Generally, overriding paint of a top level container like JFrame is a bad idea, JFrame contains a bunch of child components that can be painted independently of the parent, which seems to be the case here
As you can see, there are (at least) 3 other components in between the frame and the user
Generally, you should create a custom class which extends from something like JPanel and override it's paintComponent and perform your custom painting there.
import java.awt.BasicStroke;
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.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Football {
public static void main(String[] args) {
new Football();
}
public Football() {
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("Football");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new FootballPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class FootballPane extends JPanel {
public static final int WINDOW_WIDTH = 800;
public static final int WINDOW_HEIGHT = 400;
private int x = 40; // Ball's X coordinate
private int y = 300; // Ball's Y coordinate
private static final int WIDTH = 35; // Ball's width
private static final int HEIGHT = 60; // Ball's height
private static final int X_MOVE = 14; // Pixels to move ball
private static final int Y_MOVE = 4;
private static final int TIME_DELAY = 25; // Time delay
private Timer timer; // Timer object
/**
* init method
*/
public FootballPane() {
// Set Background to a Dark Green
setBackground(new Color(0, 220, 50));
// initTimer();
addMouseListener(new FbMouseListener());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(WINDOW_WIDTH, WINDOW_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
// Call the superclass paint method.
super.paintComponent(g);
// Set the color to Brown
g.setColor(new Color(129, 74, 25));
// Draw the football
g.fillOval(x, y, WIDTH, HEIGHT);
// Draw the Goalpost
g.setColor(Color.YELLOW);
g.fillRect(670, 240, 5, 140);
g.fillRect(610, 80, 5, 140);
g.fillRect(740, 120, 5, 140);
// Need Thicker line
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(5));
g2.drawLine(612, 220, 742, 260);
}
private class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// Update the ball's position
y -= Y_MOVE;
x += X_MOVE;
// Force a call to the paint method
repaint();
}
}
public void initTimer() {
timer = new Timer(TIME_DELAY, new TimerListener());
timer.start();
}
private class FbMouseListener implements MouseListener {
public void mouseClicked(MouseEvent e) {
if (e.getX() >= x && e.getX() <= (x + WIDTH) && e.getY() >= y && e.getY() <= (y + HEIGHT)) {
initTimer();
}
}
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
}
}
See Painting in AWT and Swing and Performing Custom Painting for more details

How to repaint properly in JPanel inside JFrame

stackoverflow community!
I am making a small GUI based game in JAVA.
I am having a few troubles right now.
To give you basic understanding of my program,
I have a window that shows menu(JPanel) first. When I click on "start game" button. It proceeds to another JPanel on which I can play game.
![menu_window][1]
I have a timer working on a small bullet that is moving periodically. Every time the timer works, the Panel repaints the bullet. I can see the repaint method works but it doesn't remove the previous trace.
![enter image description here][2]
This is my main class
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Main {
private final int window_x_size = 500;
private final int window_y_size = 500;
private JFrame frame;
private JPanel Menu;
private Game myGame = new Game();//extends from JPanel
private JButton startButton = new JButton("Game Start");
private JButton exitButton = new JButton("Game Exit");
private JButton showRank = new JButton("Rank");
private JButton OneOnOne = new JButton("One on One");
private ActionListener MyButtonListener = new MyButtonListener();
public class MyButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == startButton) {
frame.remove(Menu);
frame.setContentPane(myGame);
frame.validate();
frame.repaint(); // prefer to write this always.
} else if (source == exitButton) {
System.exit(1);
} else if (source == showRank) {
} else {// one on one
}
}
}
public Main() {
frame = new JFrame();
frame.setBackground(Color.white);
frame.setSize(window_x_size, window_y_size);
frame.setTitle("My First GUI Game");
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
Menu = new JPanel();
startButton.addActionListener(MyButtonListener);
exitButton.addActionListener(MyButtonListener);
showRank.addActionListener(MyButtonListener);
OneOnOne.addActionListener(MyButtonListener);
Menu.setLayout(new GridLayout(4, 1));
Menu.add(startButton);
Menu.add(OneOnOne);
Menu.add(showRank);
Menu.add(exitButton);
frame.setContentPane(Menu);
frame.setVisible(true);
}
public static void main(String[] args) {
/*
* This is the most important part of your GUI app, never forget
* to schedule a job for your event dispatcher thread :
* by calling the function, method or constructor, responsible
* for creating and displaying your GUI.
*/
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new Main();
}
});
}
}
This is my Game class
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Game extends JPanel {
private Random rnd = new Random();
private ActionListener MyBulletListener = new BulletListener();
public KeyListener myKeyListen = new MyKeyListener();
Timer bullet_timer;
private boolean IsExplosion = false;
private ImageIcon spacecraftImg = new ImageIcon("spacecraft.png");
private Rectangle spacecraftBox = new Rectangle(5, 10,
spacecraftImg.getIconWidth(), spacecraftImg.getIconHeight());
private ImageIcon explosionImg = new ImageIcon("explosion.png");
private ImageIcon bulletImg = new ImageIcon("bullet.png");
private Rectangle bulletBox = new Rectangle(70, 200,
bulletImg.getIconWidth(), bulletImg.getIconHeight());
private MySound explosion_sound = new MySound();
public Game() {
addKeyListener(myKeyListen);
bullet_timer = new Timer(500, MyBulletListener);
bullet_timer.start();
}
public class MyKeyListener implements KeyListener {
private int x;
private int y;
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
int keyCode = e.getKeyCode();
if (keyCode == 37) {
x = -10;
y = 0;
} else if (keyCode == 38) {
x = 0;
y = -10;
} else if (keyCode == 39) {
x = 10;
y = 0;
} else {
x = 0;
y = 10;
}
if (spacecraftBox.x + x < 0
|| spacecraftBox.x + x > 500
|| spacecraftBox.y + y < 0
|| spacecraftBox.y + y > 500) {
} else {
move_plane(x, y);
repaint();
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
public class BulletListener implements ActionListener {
private int x;
private int y;
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
Object source = e.getSource();
if (source == bullet_timer) {
int dir = rnd.nextInt(4);
if (dir == 0) {// move left
x = -10;
y = 0;
} else if (dir == 1) {// move right
x = 10;
y = 0;
} else if (dir == 2) {// move up
x = 0;
y = -10;
} else {// move down
x = 0;
y = 10;
}
if (bulletBox.x + x < 0
|| bulletBox.x + x > 500
|| bulletBox.y + y < 0
|| bulletBox.y + y > 500) {
} else {
move_bullets(x, y);
repaint();
}
}
}
}
#Override
public void paint(Graphics g) {
g.drawImage(bulletImg.getImage(), (int) bulletBox.getX(),
(int) bulletBox.getY(), null);
g.drawImage(spacecraftImg.getImage(), (int) spacecraftBox.getX(),
(int) spacecraftBox.getY(), null);
if (IsExplosion) {
g.drawImage(explosionImg.getImage(), (int) bulletBox.getX(),
(int) bulletBox.getY(), null);
MySound.play();
IsExplosion = false;
}
}
public void move_plane(int x, int y) {
spacecraftBox.translate(x, y);
if (spacecraftBox.intersects(bulletBox)) {
IsExplosion = true;
}
}
public void move_bullets(int x, int y) {
bulletBox.translate(x, y);
if (spacecraftBox.intersects(bulletBox)) {
IsExplosion = true;
}
}
}
Plus I added KeyListener but it doesn't work. I have no idea how to fix it out.
I tried googling about the issue. I tried the game panel focusable in main class but it didn't work.
I would really appreciate your help.
Best Regards,
Dongseop
This is almost always due to your painting method not calling the super's painting method to clean up dirty pixels. Since you're overriding paint, you would need to call super.paint(g); as the first method call in your paint override.
Other issues:
Next I'm going to suggest that you not override paint but rather paintComponent(Graphics g), as this will give your animation automatic double buffering and make the animation smoother. Again, call super.paintComponent(g); in your method override.
The easiest way to swap views is to use a CardLayout.
Better to use KeyBindings rather than a KeyListener as this will help you get around the KeyListener's focus issue, the issue which is probably preventing your KeyListener from working. It also allows you to use reusable Actions. Please search this site on KeyListeners to see what I mean and to see examples of Key Bindings (some by me). Also Google Java Key Bindings Tutorial to see the official tutorial on how to use these.

Move an Oval in java

I made a mini code that draw oval and link each other , now i try to move the oval(Circle) but I have a problem (in coding)
// Panneau.java
public class Panneau extends JPanel {
private int R = 20;
private boolean isDrag = false;
String text = "stack";
int x = 250, y = 200;
int height = 50, width = 50;
Random Rnd = new Random();
int rand=Rnd.nextInt();
int r=Math.abs(rand%250);
int r2=Math.abs(rand%250);
public Panneau() {
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if ((x<=e.getX() && x+R>=e.getX()) && ( y<=e.getY() && y+R>=e.getY())) {
moveVertex(e.getX(),e.getY());
isDrag = true;
}
}
#Override
public void mouseReleased(MouseEvent e) {
isDrag = false;
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (isDrag) moveVertex(e.getX(),e.getY());
}
});
}
private void moveVertex(int x1, int y1) {
if ((x!=x1) || (y!=y1)) {
x=x1-10;
y=y1-10;
repaint();
}
}
#Override
protected void paintComponent(Graphics g){
// declaration
super.paintComponent(g);
g.setColor(Color.black);
g.drawLine(x,y,x+r,y+r2);
g.setColor(Color.yellow);
g.fillOval(x-height/2, y-width/2,width, height);
g.fillOval((x-height/2)+r, (y-width/2)+r2,width, height);
FontMetrics fm = g.getFontMetrics();
double textWidth = fm.getStringBounds(text, g).getWidth();
g.setColor(Color.blue);
g.drawString(text, (int) (x - textWidth/2),(int) (y + fm.getMaxAscent() / 2));
g.drawString(text, (int) (x - textWidth/2)+r,(int) (y + fm.getMaxAscent() / 2)+r2);
}
}
I must move the two circles and the line must not move(Graph node)
please help me and thanks :)
After the update ( thanks to MadProgrammer) now I can move all the figure ( but if I clicked in the red circle only) , I want to move just circles thanks :)
Basically, because instead of using reapint(int, int) you could use repaint()
private void moveVertex(int x1, int y1) {
int OFFSET = 1;
if ((x != x1) || (y != y1)) {
x = x1 - 10;
y = y1 - 10;
repaint();
}
}
This will ensure that the entire component is repainted.
While I wouldn't discount the use of repaint(int, int), because your painting process is relatively simple, it's not going to provide you with a great deal of benefit at this stage
Updated with additional example
IF I understand, you want to be able to move a single node and have the line remain joined.
While it might be possible to implement within the code you have available, a simpler soltution would be to take advantage of the 2D Graphics Shape API, this provides a number of really useful functions, including determining of points fall within a given shape.
It also means you don't need to keep track of a large number of parameters, but instead, get a self contained object that just knows how it should be painted...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestGraphNode {
public static void main(String[] args) {
new TestGraphNode();
}
public TestGraphNode() {
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 Panneau());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Panneau extends JPanel {
private int radius = 50;
private String text = "stack";
private List<Ellipse2D> nodes;
private Ellipse2D dragged;
private Point offset;
public Panneau() {
nodes = new ArrayList<>(25);
nodes.add(new Ellipse2D.Float(50 - (radius / 2), 100 - (radius / 2), radius, radius));
nodes.add(new Ellipse2D.Float(350 - (radius / 2), 100 - (radius / 2), radius, radius));
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
for (Ellipse2D node : nodes) {
if (node.contains(e.getPoint())) {
System.out.println("Clicked...");
dragged = node;
// Adjust for the different between the top/left corner of the
// node and the point it was clicked...
offset = new Point(node.getBounds().x - e.getX(), node.getBounds().y - e.getY());
// Highlight the clicked node
repaint();
break;
}
}
}
#Override
public void mouseReleased(MouseEvent e) {
// Erase the "click" highlight
if (dragged != null) {
repaint();
}
dragged = null;
offset = null;
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (dragged != null && offset != null) {
// Adjust the position of the drag point to allow for the
// click point offset
Point to = e.getPoint();
to.x += offset.x;
to.y += offset.y;
// Modify the position of the node...
Rectangle bounds = dragged.getBounds();
bounds.setLocation(to);
dragged.setFrame(bounds);
// repaint...
repaint();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
// declaration
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Draw the connecting lines first
// This ensures that the lines are under the nodes...
Point p = null;
for (Ellipse2D node : nodes) {
g2d.setColor(Color.BLACK);
Point to = node.getBounds().getLocation();
to.x += radius / 2;
to.y += radius / 2;
if (p != null) {
g2d.draw(new Line2D.Float(p, to));
}
p = to;
}
// Draw the nodes...
for (Ellipse2D node : nodes) {
g2d.setColor(Color.yellow);
g2d.fill(node);
if (node == dragged) {
g2d.setColor(Color.BLUE);
g2d.draw(node);
}
g2d.setColor(Color.BLUE);
FontMetrics fm = g.getFontMetrics();
int textWidth = fm.stringWidth(text);
int x = node.getBounds().x;
int y = node.getBounds().y;
int width = node.getBounds().width;
int height = node.getBounds().height;
g.drawString(text,
x + ((width - textWidth)) / 2,
y + ((height - fm.getHeight()) / 2) + fm.getAscent());
}
g2d.dispose();
}
}
}

Categories

Resources