There is one Paraview user interface as follow attracted me.
I think this interface can be used to assign value into array. It works like this :
I want to implement this into a Java program but I found no Java API can support my idea. The closest design from me would be adding multiple JSlider like this :
But what if it is a 100 size array, I wouldn't want to add 100 JSliders. Do you have better solution for this ?
Okay, so this is a pretty basic example. It needs a lot more work and optimisation, but should get you moving in the right direction
Have a look at Painting in AWT and Swing, Performing Custom Painting, 2D Graphics and How to Write a Mouse Listener 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.Point;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
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 TestGraph {
public static void main(String[] args) {
new TestGraph();
}
public TestGraph() {
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 GraphPane(0, 100, new int[100]));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class GraphPane extends JPanel {
protected static final int COLUMN_WIDTH = 10;
protected static final int VERTICAL_INSETS = 10;
private int[] data;
private int minValue, maxValue;
private Path2D.Double graph;
private List<Shape> buttons;
private Point mousePoint;
public GraphPane(int minValue, int maxValue, int[] data) {
this.data = data;
this.minValue = minValue;
this.maxValue = maxValue;
buttons = new ArrayList<>(data == null ? 25 : data.length);
updateView();
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
updateData(e);
}
#Override
public void mouseDragged(MouseEvent e) {
updateData(e);
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
protected void updateData(MouseEvent e) {
// Which "column" was clicked on
int column = (int) Math.round(((double) e.getX() / (double) COLUMN_WIDTH)) - 1;
// Get the "height" of the clickable area
int clickRange = getHeight() - (VERTICAL_INSETS * 2);
// Adjust the y click point for the margins...
int yPos = e.getY() - VERTICAL_INSETS;
// Calculate the vertical position that was clicked
// this ensures that the range is between 0 and clickRange
// You could choose to ignore values out side of this range
int row = Math.min(Math.max(clickRange - yPos, 0), clickRange);
// Normalise the value between 0-1
double clickNormalised = row / (double) clickRange;
// Calculate the actual row value...
row = minValue + (int) (Math.round(clickNormalised * maxValue));
// Update the data
data[column] = row;
mousePoint = new Point(
COLUMN_WIDTH + (column * COLUMN_WIDTH),
getHeight() - (VERTICAL_INSETS + (int) Math.round((data[column] / 100d) * clickRange)));
updateView();
repaint();
}
#Override
public void invalidate() {
super.invalidate();
updateView();
}
protected Shape createButton(int xPos, int yPos) {
return new Ellipse2D.Double(xPos - COLUMN_WIDTH / 2, yPos - COLUMN_WIDTH / 2, COLUMN_WIDTH, COLUMN_WIDTH);
}
protected void updateView() {
graph = new Path2D.Double();
buttons.clear();
if (data != null && data.length > 0) {
int verticalRange = getHeight() - (VERTICAL_INSETS * 2);
int xPos = COLUMN_WIDTH;
int yPos = getHeight() - (VERTICAL_INSETS + (int) Math.round((data[0] / 100d) * verticalRange));
graph.moveTo(xPos, yPos);
if (data[0] > 0) {
buttons.add(createButton(xPos, yPos));
}
for (int index = 1; index < data.length; index++) {
xPos = (index * COLUMN_WIDTH) + COLUMN_WIDTH;
yPos = getHeight() - (VERTICAL_INSETS + (int) Math.round((data[index] / 100d) * verticalRange));
graph.lineTo(xPos, yPos);
if (data[index] > 0) {
buttons.add(createButton(xPos, yPos));
}
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(data == null ? 0 : (data.length + 1) * COLUMN_WIDTH, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (data != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(64, 64, 64, 32));
for (int index = 0; index < data.length; index++) {
int xPos = (index * COLUMN_WIDTH) + COLUMN_WIDTH;
g2d.drawLine(xPos, VERTICAL_INSETS, xPos, getHeight() - VERTICAL_INSETS);
}
g2d.setColor(Color.BLACK);
g2d.draw(graph);
for (Shape button : buttons) {
g2d.fill(button);
}
if (mousePoint != null) {
g2d.setColor(new Color(255, 192, 203));
Ellipse2D dot = new Ellipse2D.Double((mousePoint.x - COLUMN_WIDTH / 2) - 2, (mousePoint.y - COLUMN_WIDTH / 2) - 2, COLUMN_WIDTH + 4, COLUMN_WIDTH + 4);
g2d.draw(dot);
g2d.setColor(new Color(255, 192, 203, 128));
g2d.fill(dot);
}
g2d.dispose();
}
}
}
}
Before anyone says I didn't put the "fill" in, I deliberately used a Path2D to make it much simpler to achieve ;)
here is a small example how to create this using polygon class .i sorted x coordinate and use polygon class to make this.
GraphPane.class
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.Collections;
import javax.swing.JPanel;
public class GraphPane extends JPanel {
ArrayList<XYpoints> poinList = new ArrayList();
private int px;
private int py;
private XYpoints last;
private boolean drag;
private static Color graphColor=new Color(32, 178, 170);
public GraphPane() {
initComponents();
poinList.add(new XYpoints(50, 400));
poinList.add(new XYpoints(450, 50));
poinList.add(new XYpoints(600, 400));
}
private void initComponents() {
setBackground(new java.awt.Color(255, 255, 255));
addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseDragged(java.awt.event.MouseEvent evt) {
System.out.println("drag");
if (drag) {
last.setY(evt.getY());
GraphPane.this.repaint();
}
}
});
addMouseListener(new java.awt.event.MouseAdapter() {
public void mousePressed(java.awt.event.MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
for (XYpoints poinList1 : poinList) {
px = poinList1.getpX();
py = poinList1.getpY();
if (x < px + 5 && x > px - 5 && y < py + 5 && y > py - 5) {
System.out.println("inter");
poinList1.setIntersect(true);
last = poinList1;
drag = true;
GraphPane.this.repaint();
return;
}
}
poinList.add(new XYpoints(x, y));
Collections.sort(poinList, new XComp());
GraphPane.this.repaint();
}
public void mouseReleased(java.awt.event.MouseEvent evt) {
if (drag) {
drag = false;
last.setIntersect(false);
GraphPane.this.repaint();
}
}
});
}
#Override
protected void paintComponent(Graphics gr) {
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr.create();
Polygon p = new Polygon();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (XYpoints poinList1 : poinList) {
px = poinList1.getpX();
py = poinList1.getpY();
p.addPoint(px, py);
}
g.setColor(graphColor);
g.fillPolygon(p);
for (XYpoints poinList1 : poinList) {
px = poinList1.getpX();
py = poinList1.getpY();
g.setColor(Color.red);
if (poinList1.isIntersect()) {
g.setColor(Color.blue);
}
g.fillOval(px - 5, py - 5, 10, 10);
}
g.dispose();
}
}
XYpoints.class
import java.awt.Polygon;
import java.util.Comparator;
public class XYpoints extends Polygon {
private int x;
private int y;
private boolean inter;
public XYpoints(int x, int y) {
this.x = x;
this.y = y;
}
public void setIntersect(boolean state) {
inter = state;
}
public void setY(int y){
this.y=y;
}
public boolean isIntersect() {
return inter;
}
public int getpX() {
//System.out.println("send " + this.x);
return this.x;
}
public int getpY() {
return this.y;
}
}
XComp .class
class XComp implements Comparator<XYpoints> {
#Override
public int compare(XYpoints t, XYpoints t1) {
if (t.getpX() < t1.getpX()) {
return -1;
} else {
return 1;
}
}
}
myframe.class
import javax.swing.JFrame;
public class myframe extends JFrame {
public myframe() {
GraphPane pane = new GraphPane();
setContentPane(pane);
setSize(650, 500);
setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new myframe();
}
});
}
}
Related
I am working on a 4 Way Pong Program. I have it to the point where my paddles will move with mouse movement, and the ball will bounce around the screen.
I am stuck when it comes to figuring out how to check for collisions between the ball and the paddles (which will increase the score) and between the ball and the edges of the JPanel (which will end the game).
Any guidance is greatly appreciated...
Game Class
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Game extends JPanel {
JFrame window = new JFrame();
Timer timer = new Timer(30, new ActionHandler());
ArrayList<Ball> balls = new ArrayList<Ball>();
ArrayList<Paddle> horizPaddles = new ArrayList<Paddle>();
ArrayList<Paddle> vertPaddles = new ArrayList<Paddle>();
Paddle pTop;
Paddle pBottom;
Paddle pRight;
Paddle pLeft;
Ball b;
int score = 0;
JLabel scoreLabel;
//==========================================================
public Game() {
window.setBounds(100,100,900,500);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setTitle("4 Way Pong");
window.setResizable(false);
JPanel scorePanel = new JPanel(true);
scoreLabel = new JLabel("Current Score: " + Integer.toString(score));
scoreLabel.setFont(new Font("sansserif", Font.PLAIN, 20));
scoreLabel.setForeground(Color.RED);
scorePanel.add(scoreLabel);
JPanel buttons = new JPanel(true);
Container con = window.getContentPane();
con.setLayout(new BorderLayout());
con.add(this, BorderLayout.CENTER);
con.add(buttons, BorderLayout.SOUTH);
con.add(scorePanel, BorderLayout.NORTH);
this.setBackground(Color.BLACK);
this.addMouseMotionListener(new MouseMoved());
ButtonCatch bc = new ButtonCatch();
JButton btn;
btn = new JButton("New Game");
btn.addActionListener(bc);
buttons.add(btn);
btn = new JButton("Swap Colors");
btn.addActionListener(bc);
buttons.add(btn);
btn = new JButton("High Scores");
btn.addActionListener(bc);
buttons.add(btn);
btn = new JButton("Save Score");
btn.addActionListener(bc);
buttons.add(btn);
btn = new JButton("Quit");
btn.addActionListener(bc);
buttons.add(btn);
timer.start();
window.setVisible(true);
}
//==========================================================
public static void main(String[] args) {
new Game();
}
//==========================================================
public void update() {
for(Ball b : balls) {
b.move(getWidth() + 30, getHeight() + 25);
}
//checkSideCollision();
//checkHorizPaddleCollision();
//checkVertPaddleCollision();
repaint();
}
//==========================================================
public void checkSideCollision() {
if(b.getyPos() > getHeight()) {
JOptionPane.showMessageDialog(null, "Game Over. You Scored " + score + ".", "GAME OVER", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}
//==========================================================
public void checkHorizPaddleCollision() {
if(b.getxPos() == pBottom.getX() && b.getyPos() == pBottom.getY()) {
//b.yPos = b.yPos - 5;
score++;
}
}
//==========================================================
public void checkVertPaddleCollision() {
}
//==========================================================
public class ButtonCatch implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
switch(e.getActionCommand()) {
case "Quit": JOptionPane.showMessageDialog(null, "You Quit... No Score Recorded", "Game Over", JOptionPane.INFORMATION_MESSAGE); System.exit(0);
case "New Game": newGame(); break;
case "Swap Colors": swapColors(); break;
case "High Scores": try { displayScores(); } catch (Exception e1) { System.out.println(e1.getMessage()); } break;
case "Save Score": try { saveScore(); } catch (Exception e2) { System.out.println(e2.getMessage()); } break;
}
}
}
//==========================================================
public void paint(Graphics g) {
super.paint(g);
for(Ball b : balls) {
b.draw(g);
}
for(Paddle p : horizPaddles) {
p.draw((Graphics2D) g);
}
for(Paddle p : vertPaddles) {
p.draw((Graphics2D) g);
}
}
//==========================================================
//FIX FOR DISPLAYING SCORES
private void displayScores() throws Exception {
}
//==========================================================
//FIX -- Store Score in a File
private void saveScore() throws Exception {
int userScore = score;
String name = JOptionPane.showInputDialog("Enter Your Name: ");
JOptionPane.showMessageDialog(null, "Saved!\n" + name + " scored " + userScore, "Score Recorded", JOptionPane.INFORMATION_MESSAGE);
}
//==========================================================
private void swapColors() {
for(Ball b : balls) {
if(b.color.equals(Color.red)) {
b.setColor(Color.yellow);
} else if (b.color.equals(Color.yellow)) {
b.setColor(Color.blue);
} else {
b.setColor(Color.red);
}
}
}
//==========================================================
private void newGame() {
//CREATE BALL
balls.clear();
b = new Ball();
b.color = Color.red;
b.dx = (int)(Math.random() * 4) + 1;
b.dy = (int)(Math.random() * 4) + 1;
b.xPos = (int)(Math.random() * 4) + 1;
b.yPos = (int)(Math.random() * 4) + 1;
balls.add(b);
//CREATE PADDLES
horizPaddles.clear();
vertPaddles.clear();
// bottom
pBottom = new Paddle();
pBottom.x = getWidth() / 2;
pBottom.y = getHeight();
pBottom.setX(pBottom.getX()-20);
pBottom.setY(pBottom.getY()-20);
pBottom.setWidth(100);
pBottom.setHeight(20);
horizPaddles.add(pBottom);
//top
pTop = new Paddle();
pTop.x = getWidth() / 2;
pTop.y = getHeight();
pTop.setX(0 + pTop.getX());
pTop.setY(0);
pTop.setWidth(100);
pTop.setHeight(20);
horizPaddles.add(pTop);
//left
pLeft = new Paddle();
pLeft.x = getWidth() / 2;
pLeft.y = getHeight();
pLeft.setX(0);
pLeft.setY(pLeft.getY() / 2);
pLeft.setWidth(20);
pLeft.setHeight(100);
vertPaddles.add(pLeft);
//right
pRight = new Paddle();
pRight.x = getWidth() / 2;
pRight.y = getHeight();
pRight.setX(875);
pRight.setY(pRight.getY() / 2);
pRight.setWidth(20);
pRight.setHeight(100);
vertPaddles.add(pRight);
timer.start();
}
//==========================================================
public class ActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
update();
}
}
//==========================================================
public class MouseMoved implements MouseMotionListener {
#Override
public void mouseMoved(MouseEvent e) {
for(Paddle p : horizPaddles) {
p.x = e.getX();
}
for(Paddle p : vertPaddles) {
p.y = e.getY();
}
}
#Override public void mouseDragged(MouseEvent e) {}
}
}
Paddle Class
import java.awt.Color;
import java.awt.Graphics2D;
public class Paddle implements Drawable{
public int x, y, width, height;
public Paddle() {
super();
}
public Paddle(int x, int y, int width, int height) {
super();
setX(x);
setY(y);
setWidth(width);
setHeight(height);
}
#Override
public void draw(Graphics2D g) {
g.setColor(Color.green);
g.fillRect(x, y, width, height);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
Ball Class
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.io.IOException;
import java.io.RandomAccessFile;
import javax.swing.JPanel;
public class Ball implements Comparable<Ball>, Cloneable{
private static int count = 0;
public static final int NAME_LENGTH = 20;
public String name = "";
public int xPos=0, yPos=0, dx = 3, dy = 2;
public Color color = Color.red;
public static void resetCounter() { count = 0; }
public Ball() {name = "Rock: " + ++count;}
public Ball(RandomAccessFile file) {
load(file);
}
public void load(RandomAccessFile file) {
try {
xPos = file.readInt();
yPos = file.readInt();
dx = file.readInt();
dy = file.readInt();
color = new Color( file.readInt() );
byte[] n = new byte[NAME_LENGTH];
file.readFully(n);
name = new String(n).trim();
System.out.println(name);
} catch (IOException e) {
e.printStackTrace();
}
}
public void save(RandomAccessFile file) {
try {
file.writeInt(xPos);
file.writeInt(yPos);
file.writeInt(dx);
file.writeInt(dy);
file.writeInt(color.getRGB());
file.writeBytes( getStringBlock(name, NAME_LENGTH) );
} catch (IOException e) {
e.printStackTrace();
}
}
private String getStringBlock(String string, int len) {
StringBuilder sb = new StringBuilder(name);
sb.setLength(len);
return sb.toString();
}
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(xPos, yPos, 25, 25);
g.setColor(Color.black);
g.drawOval(xPos, yPos, 25, 25);
}
public void setColor(Color c) {
color = c;
}
public void move(int width, int height) {
xPos+=dx;
yPos+=dy;
if(xPos + 50 > width) {
xPos = width - 50;
dx = -dx;
}
if(yPos + 50 > height) {
yPos = height - 50;
dy = -dy;
}
if(xPos < 0) {
xPos = 0;
dx = -dx;
}
if(yPos < 0) {
yPos = 0;
dy = -dy;
}
}
#Override
public int compareTo(Ball arg0) {
return 0;
}
public int getxPos() {
return xPos;
}
public int getyPos() {
return yPos;
}
}
Thanks again...
For the Paddle-Ball collisions, I think calling this method on a timer might suffice:
public void checkPaddleCollisions(){
Rectangle a = new Rectangle(pTop.getX(), pTop.getY(), pTop.getWidth(), pTop.getHeight());
Rectangle b = ... //Do this for all the paddles.
Rectangle ball = new Rectangle(ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight());
if(a.intersects(ball) || b.intersects(ball) || c.intersects(ball) || d.intersects(ball)){
//Increment score and bounce ball.
}
}
As for collisions with the edge, I think you could do something similar, just create 4 rectangles representing the edges of the screen.
A little rough with java but can someone tell me how I take a draw method from a list of objects, say there's more than 1 box, and put it in the actionPerform so I could modify the getter of X and Y to repaint() them and make them move?
From Box Class:
public void draw(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect((int) (getX() - (width/2)), (int) (getY() - (height/2)), getWidth(), getHeight());
}
actionPerform method: (This is in another class)
public void actionPerformed(ActionEvent e){
timer.start();
}
The basic idea is...
When actionPerformed is called...
Iterate through the list of objects and update them in some meaningful way
Call repaint...
Then within your components paintComponent method, iterate the list and paint them
The following is a very basic concept...
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.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FlyingBoxes {
public static void main(String[] args) {
new FlyingBoxes();
}
public interface Drawable {
public void update(JComponent comp);
public void draw(Graphics g);
}
public class Box implements Drawable {
private int x;
private int y;
private int width = 10;
private int height = 10;
private int xDelta;
private int yDelta;
public Box(int x, int y) {
this.x = x;
this.y = y;
xDelta = random();
yDelta = random();
}
#Override
public void update(JComponent comp) {
x += xDelta;
y += yDelta;
if (x < 0) {
x = 0;
xDelta *= -1;
} else if (x + width > comp.getWidth()) {
x = comp.getWidth() - width;
xDelta *= -1;
}
if (y < 0) {
y = 0;
yDelta *= -1;
} else if (y + height > comp.getHeight()) {
y = comp.getHeight() - height;
yDelta *= -1;
}
}
#Override
public void draw(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect(x, y, width, height);
}
protected int random() {
int value = 0;
do {
value = -2 + (int)(Math.random() * 4);
} while (value == 0);
return value;
}
}
public FlyingBoxes() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<Drawable> drawables;
public TestPane() {
drawables = new ArrayList<>(25);
for (int index = 0; index < 25; index++) {
int x = (int) (Math.random() * 190);
int y = (int) (Math.random() * 190);
drawables.add(new Box(x, y));
}
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Drawable d : drawables) {
d.update(TestPane.this);
}
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Drawable d : drawables) {
d.draw(g);
}
}
}
}
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();
}
}
}
I am trying to create JPanel with draggable crosses which appear after mouse clicking. Everything works fine but when I resize the JPanel the crosses disappear. I tried to override the paintComponent method in my JPanel but then all crosses are at coordinates (0,0). How can I fix it?
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CrossPanel extends JPanel implements MouseListener {
private int orderOfCross = 0;
private ArrayList<Cross> crosses;
private int defaultSizeOfCrosses = 10;
CrossPanel() {
setOpaque(false);
addMouseListener(this);
crosses = new ArrayList<Cross>();
}
#Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
Cross cross = new Cross(orderOfCross++, defaultSizeOfCrosses);
crosses.add(cross);
cross.setLocation(x - defaultSizeOfCrosses, y - defaultSizeOfCrosses);
add(cross);
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// for (int i = 0; i < crosses.size(); i++) {
// crosses.get(i).paint(g);
// }
}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CrossPanel crossPane = new CrossPanel();
f.getContentPane().add(crossPane);
f.setSize(600, 500);
f.setLocation(200, 200);
f.setVisible(true);
}
}
class Cross extends JComponent {
private int order;
protected Cursor draggingCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
private volatile int draggedAtX, draggedAtY;
int size;
public Cross(int order, int size) {
this.order = order;
this.size = size;
this.setBounds(0, 0, 4 * size, 3 * size + 10);
addDragListeners();
setCursor(draggingCursor);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.setStroke(new BasicStroke(3));
g2.drawLine(0, size, size + size, size);
g2.drawLine(size, 0, size, size + size);
Font f = new Font("Monospaced", Font.BOLD, size + 10);
g2.setFont(f);
g2.drawString(String.valueOf(order), size - size / 2, 3 * size + 10);
}
private void addDragListeners() {
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
draggedAtX = e.getX();
draggedAtY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
Point newLocation = new Point(e.getX() - draggedAtX + getLocation().x, e.getY() - draggedAtY + getLocation().y);
setLocation(newLocation);
}
});
}
}
I very rarely see a use for a null layout, for all the perceived benefits, there are simply to many draw backs.
The entire Swing API has been designed around the use of layout managers so you'd be crazy (IMHO) to simply throw all that work away.
If you find yourself in a position where the available layout managers don't seem to do what you want, it might be more worth while to write you own.
Here, I've presented a PropertionalLayoutManager whose intention is to provide layout capabilities that will place components on a container based an percentage of the width/height of the parent component. This means, as the parent component is resized, the child components will reposition themselves at a percentage of the parent size.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CrossPanel extends JPanel implements MouseListener {
private int orderOfCross = 0;
private ArrayList<Cross> crosses;
private int defaultSizeOfCrosses = 10;
CrossPanel() {
setOpaque(false);
addMouseListener(this);
crosses = new ArrayList<Cross>();
setLayout(new PropertionalLayoutManager());
}
#Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
Cross cross = new Cross(orderOfCross++, defaultSizeOfCrosses);
float xPos = (float)x / (float)getWidth();
float yPos = (float)y / (float)getHeight();
crosses.add(cross);
add(cross, new PropertionalConstraints(xPos, yPos));
revalidate();
}
public static String format(float value) {
return NumberFormat.getNumberInstance().format(value);
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CrossPanel crossPane = new CrossPanel();
f.getContentPane().add(crossPane);
f.setSize(600, 500);
f.setLocation(200, 200);
f.setVisible(true);
}
public class Cross extends JComponent {
private int order;
protected Cursor draggingCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
private volatile int draggedAtX, draggedAtY;
int size;
public Cross(int order, int size) {
this.order = order;
this.size = size;
// this.setBounds(0, 0, 4 * size, 3 * size + 10);
addDragListeners();
setCursor(draggingCursor);
Font f = new Font("Monospaced", Font.BOLD, size + 10);
setFont(f);
}
#Override
public Dimension getPreferredSize() {
// This is dangrous, you are making assumptions about platforms
// that you have no eviednce to support.
FontMetrics fm = getFontMetrics(getFont());
return new Dimension(Math.max(fm.stringWidth(String.valueOf(order)), size), size + fm.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.setStroke(new BasicStroke(3));
FontMetrics fm = g2.getFontMetrics();
int width = getWidth() - 1;
int height = getHeight() - 1;
int x = (width - fm.stringWidth(String.valueOf(order))) / 2;
int y = fm.getAscent();
g2.drawString(String.valueOf(order), x, y);
int crossSize = Math.min(width, height - fm.getHeight());
x = (width - crossSize) / 2;
y = fm.getHeight();
g2.drawLine(x, y, x + crossSize, y + crossSize);
g2.drawLine(x + crossSize, y, x, y + crossSize);
}
private void addDragListeners() {
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
draggedAtX = e.getX();
draggedAtY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
Point newLocation = new Point(e.getX() - draggedAtX + getLocation().x, e.getY() - draggedAtY + getLocation().y);
setLocation(newLocation);
}
});
}
}
public class PropertionalConstraints {
private float x;
private float y;
public PropertionalConstraints(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public void setX(float x) {
if (x > 1f) {
x = 1f;
} else if (x < -0f) {
x = 0f;
}
this.x = x;
}
public void setY(float y) {
if (y > 1f) {
y = 1f;
} else if (y < -0f) {
y = 0f;
}
this.y = y;
}
}
public class PropertionalLayoutManager implements LayoutManager2 {
private Map<Component, PropertionalConstraints> mapConstraints;
public PropertionalLayoutManager() {
mapConstraints = new HashMap<>(25);
}
public PropertionalConstraints getConstraintsFor(Component comp) {
return mapConstraints.get(comp);
}
public void setConstraintsFor(Component comp, PropertionalConstraints pc) {
mapConstraints.put(comp, pc);
}
#Override
public void addLayoutComponent(Component comp, Object constraints) {
if (constraints instanceof PropertionalConstraints) {
mapConstraints.put(comp, (PropertionalConstraints) constraints);
} else {
throw new IllegalArgumentException("Constraints must be PropertionalConstraints");
}
}
#Override
public Dimension maximumLayoutSize(Container target) {
return preferredLayoutSize(target);
}
#Override
public float getLayoutAlignmentX(Container target) {
return 0.5f;
}
#Override
public float getLayoutAlignmentY(Container target) {
return 0.5f;
}
#Override
public void invalidateLayout(Container target) {
}
#Override
public void addLayoutComponent(String name, Component comp) {
}
#Override
public void removeLayoutComponent(Component comp) {
mapConstraints.remove(comp);
}
#Override
public Dimension preferredLayoutSize(Container parent) {
return parent.getSize();
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
#Override
public void layoutContainer(Container parent) {
int width = parent.getWidth();
int height = parent.getHeight();
for (Component comp : parent.getComponents()) {
PropertionalConstraints con = mapConstraints.get(comp);
if (con != null) {
int x = (int)(width * con.getX());
int y = (int)(height * con.getY());
comp.setSize(comp.getPreferredSize());
comp.setLocation(x, y);
} else {
comp.setBounds(0, 0, 0, 0);
}
}
}
}
}
On some side notes, you are using "magic" numbers to determine the size and rendering position of certain elements. This is a very bad idea. You should, especially when painting or printing, base all these values on empirical values.
In this example, I've reverted to using FontMertrics to provide the required information to more accurately calculate the size and positions of various elements. This will allow for better cross platform support, as not all fonts are rendered the same across all platforms ;)
I'm starting to learn java programming and I think it's cool to learn java through game development. I know how to draw image and listen to a keypress then move that image. But is it possible to make the image move back and forth to the window while the window is listening to a keypress? Like for example, while the image or object(like spaceship) is moving left to right in the window, then if I press space key, a laser will fire at the bottom of the screen( cool huh :D ). But basically I just want to know how to make the image move left to right while the window is listening to a keypress.
I'm thinking that I will add a key listener to my window then fire an infinite loop to move the image. Or do I need to learn about threading so that another thread will move the object?
Please advise.
Many thanks.
Yep, a Swing Timer and Key Bindings would work well. Here's another example (mine) :)
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class AnimationWithKeyBinding {
private static void createAndShowUI() {
AnimationPanel panel = new AnimationPanel(); // the drawing JPanel
JFrame frame = new JFrame("Animation With Key Binding");
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
#SuppressWarnings("serial")
class AnimationPanel extends JPanel {
public static final int SPRITE_WIDTH = 20;
public static final int PANEL_WIDTH = 400;
public static final int PANEL_HEIGHT = 400;
private static final int MAX_MSTATE = 25;
private static final int SPIN_TIMER_PERIOD = 16;
private static final int SPRITE_STEP = 3;
private int mState = 0;
private int mX = (PANEL_WIDTH - SPRITE_WIDTH) / 2;
private int mY = (PANEL_HEIGHT - SPRITE_WIDTH) / 2;
private int oldMX = mX;
private int oldMY = mY;
private boolean moved = false;
// an array of sprite images that are drawn sequentially
private BufferedImage[] spriteImages = new BufferedImage[MAX_MSTATE];
public AnimationPanel() {
// create and start the main animation timer
new Timer(SPIN_TIMER_PERIOD, new SpinTimerListener()).start();
setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
setBackground(Color.white);
createSprites(); // create the images
setupKeyBinding();
}
private void setupKeyBinding() {
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inMap = getInputMap(condition);
ActionMap actMap = getActionMap();
// this uses an enum of Direction that holds ints for the arrow keys
for (Direction direction : Direction.values()) {
int key = direction.getKey();
String name = direction.name();
// add the key bindings for arrow key and shift-arrow key
inMap.put(KeyStroke.getKeyStroke(key, 0), name);
inMap.put(KeyStroke.getKeyStroke(key, InputEvent.SHIFT_DOWN_MASK), name);
actMap.put(name, new MyKeyAction(this, direction));
}
}
// create a bunch of buffered images and place into an array,
// to be displayed sequentially
private void createSprites() {
for (int i = 0; i < spriteImages.length; i++) {
spriteImages[i] = new BufferedImage(SPRITE_WIDTH, SPRITE_WIDTH,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = spriteImages[i].createGraphics();
g2.setColor(Color.red);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
double theta = i * Math.PI / (2 * spriteImages.length);
double x = SPRITE_WIDTH * Math.abs(Math.cos(theta)) / 2.0;
double y = SPRITE_WIDTH * Math.abs(Math.sin(theta)) / 2.0;
int x1 = (int) ((SPRITE_WIDTH / 2.0) - x);
int y1 = (int) ((SPRITE_WIDTH / 2.0) - y);
int x2 = (int) ((SPRITE_WIDTH / 2.0) + x);
int y2 = (int) ((SPRITE_WIDTH / 2.0) + y);
g2.drawLine(x1, y1, x2, y2);
g2.drawLine(y1, x2, y2, x1);
g2.dispose();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(spriteImages[mState], mX, mY, null);
}
public void incrementX(boolean right) {
oldMX = mX;
if (right) {
mX = Math.min(getWidth() - SPRITE_WIDTH, mX + SPRITE_STEP);
} else {
mX = Math.max(0, mX - SPRITE_STEP);
}
moved = true;
}
public void incrementY(boolean down) {
oldMY = mY;
if (down) {
mY = Math.min(getHeight() - SPRITE_WIDTH, mY + SPRITE_STEP);
} else {
mY = Math.max(0, mY - SPRITE_STEP);
}
moved = true;
}
public void tick() {
mState = (mState + 1) % MAX_MSTATE;
}
private class SpinTimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
tick();
int delta = 20;
int width = SPRITE_WIDTH + 2 * delta;
int height = width;
// make sure to erase the old image
if (moved) {
int x = oldMX - delta;
int y = oldMY - delta;
repaint(x, y, width, height);
}
int x = mX - delta;
int y = mY - delta;
// draw the new image
repaint(x, y, width, height);
moved = false;
}
}
}
enum Direction {
UP(KeyEvent.VK_UP), DOWN(KeyEvent.VK_DOWN), LEFT(KeyEvent.VK_LEFT), RIGHT(KeyEvent.VK_RIGHT);
private int key;
private Direction(int key) {
this.key = key;
}
public int getKey() {
return key;
}
}
// Actions for the key binding
#SuppressWarnings("serial")
class MyKeyAction extends AbstractAction {
private AnimationPanel draw;
private Direction direction;
public MyKeyAction(AnimationPanel draw, Direction direction) {
this.draw = draw;
this.direction = direction;
}
#Override
public void actionPerformed(ActionEvent e) {
switch (direction) {
case UP:
draw.incrementY(false);
break;
case DOWN:
draw.incrementY(true);
break;
case LEFT:
draw.incrementX(false);
break;
case RIGHT:
draw.incrementX(true);
break;
default:
break;
}
}
}
Here is another example that uses this sprite sheet:
obtained from this site.
Again it's an example of drawing within a JPanel's paintComponent method and using Key Bindings to tell which direction to move.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class Mcve3 extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 640;
private static final int TIMER_DELAY = 50;
private int spriteX = 400;
private int spriteY = 320;
private SpriteDirection spriteDirection = SpriteDirection.RIGHT;
private MySprite sprite = null;
private Timer timer = null;
public Mcve3() {
try {
sprite = new MySprite(spriteDirection, spriteX, spriteY);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
setBackground(Color.WHITE);
setKeyBindings(SpriteDirection.LEFT, KeyEvent.VK_LEFT);
setKeyBindings(SpriteDirection.RIGHT, KeyEvent.VK_RIGHT);
setKeyBindings(SpriteDirection.FORWARD, KeyEvent.VK_DOWN);
setKeyBindings(SpriteDirection.AWAY, KeyEvent.VK_UP);
timer = new Timer(TIMER_DELAY, new TimerListener());
timer.start();
}
private void setKeyBindings(SpriteDirection dir, int keyCode) {
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
KeyStroke keyPressed = KeyStroke.getKeyStroke(keyCode, 0, false);
KeyStroke keyReleased = KeyStroke.getKeyStroke(keyCode, 0, true);
inputMap.put(keyPressed, keyPressed.toString());
inputMap.put(keyReleased, keyReleased.toString());
actionMap.put(keyPressed.toString(), new MoveAction(dir, false));
actionMap.put(keyReleased.toString(), new MoveAction(dir, true));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
sprite.draw(g);
}
private class MoveAction extends AbstractAction {
private SpriteDirection dir;
private boolean released;
public MoveAction(SpriteDirection dir, boolean released) {
this.dir = dir;
this.released = released;
}
#Override
public void actionPerformed(ActionEvent e) {
if (released) {
sprite.setMoving(false);
} else {
sprite.setMoving(true);
sprite.setDirection(dir);
}
}
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (sprite.isMoving()) {
sprite.tick();
}
repaint();
}
}
private static void createAndShowGui() {
Mcve3 mainPanel = new Mcve3();
JFrame frame = new JFrame("MCVE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MySprite {
private static final String SPRITE_SHEET_PATH = "http://"
+ "orig12.deviantart.net/7db3/f/2010/338/3/3/"
+ "animated_sprite_sheet_32x32_by_digibody-d3479l2.gif";
private static final int MAX_MOVING_INDEX = 4;
private static final int DELTA = 4;
private SpriteDirection direction;
private Map<SpriteDirection, Image> standingImgMap = new EnumMap<>(SpriteDirection.class);
private Map<SpriteDirection, List<Image>> movingImgMap = new EnumMap<>(SpriteDirection.class);
private int x;
private int y;
private boolean moving = false;
private int movingIndex = 0;
public MySprite(SpriteDirection direction, int x, int y) throws IOException {
this.direction = direction;
this.x = x;
this.y = y;
createSprites();
}
public void draw(Graphics g) {
Image img = null;
if (!moving) {
img = standingImgMap.get(direction);
} else {
img = movingImgMap.get(direction).get(movingIndex);
}
g.drawImage(img, x, y, null);
}
private void createSprites() throws IOException {
URL spriteSheetUrl = new URL(SPRITE_SHEET_PATH);
BufferedImage img = ImageIO.read(spriteSheetUrl);
// get sub-images (sprites) from the sprite sheet
// magic numbers for getting sprites from sheet, all obtained by trial and error
int x0 = 0;
int y0 = 64;
int rW = 32;
int rH = 32;
for (int row = 0; row < 4; row++) {
SpriteDirection dir = SpriteDirection.values()[row];
List<Image> imgList = new ArrayList<>();
movingImgMap.put(dir, imgList);
int rY = y0 + row * rH;
for (int col = 0; col < 5; col++) {
int rX = x0 + col * rW;
BufferedImage subImg = img.getSubimage(rX, rY, rW, rH);
if (col == 0) {
// first image is standing
standingImgMap.put(dir, subImg);
} else {
// all others are moving
imgList.add(subImg);
}
}
}
}
public SpriteDirection getDirection() {
return direction;
}
public void setDirection(SpriteDirection direction) {
if (this.direction != direction) {
setMoving(false);
}
this.direction = direction;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public boolean isMoving() {
return moving;
}
public void setMoving(boolean moving) {
this.moving = moving;
if (!moving) {
movingIndex = 0;
}
}
public void tick() {
if (moving) {
switch (direction) {
case RIGHT:
x += DELTA;
break;
case LEFT:
x -= DELTA;
break;
case FORWARD:
y += DELTA;
break;
case AWAY:
y -= DELTA;
}
movingIndex++;
movingIndex %= MAX_MOVING_INDEX;
}
}
public int getMovingIndex() {
return movingIndex;
}
public void setMovingIndex(int movingIndex) {
this.movingIndex = movingIndex;
}
}
enum SpriteDirection {
FORWARD, LEFT, AWAY, RIGHT
}
As an alternative to KeyListener, consider using actions and key bindings, discussed here. Derived from this example, the program below moves a line left, down, up or right using either buttons or keys.
import java.awt.BasicStroke;
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.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
/**
* #see https://stackoverflow.com/questions/6991648
* #see https://stackoverflow.com/questions/6887296
* #see https://stackoverflow.com/questions/5797965
*/
public class LinePanel extends JPanel {
private MouseHandler mouseHandler = new MouseHandler();
private Point p1 = new Point(100, 100);
private Point p2 = new Point(540, 380);
private boolean drawing;
public LinePanel() {
this.setPreferredSize(new Dimension(640, 480));
this.addMouseListener(mouseHandler);
this.addMouseMotionListener(mouseHandler);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(8,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
private class MouseHandler extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
drawing = true;
p1 = e.getPoint();
p2 = p1;
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
drawing = false;
p2 = e.getPoint();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
if (drawing) {
p2 = e.getPoint();
repaint();
}
}
}
private class ControlPanel extends JPanel {
private static final int DELTA = 10;
public ControlPanel() {
this.add(new MoveButton("\u2190", KeyEvent.VK_LEFT, -DELTA, 0));
this.add(new MoveButton("\u2191", KeyEvent.VK_UP, 0, -DELTA));
this.add(new MoveButton("\u2192", KeyEvent.VK_RIGHT, DELTA, 0));
this.add(new MoveButton("\u2193", KeyEvent.VK_DOWN, 0, DELTA));
}
private class MoveButton extends JButton {
KeyStroke k;
int dx, dy;
public MoveButton(String name, int code, final int dx, final int dy) {
super(name);
this.k = KeyStroke.getKeyStroke(code, 0);
this.dx = dx;
this.dy = dy;
this.setAction(new AbstractAction(this.getText()) {
#Override
public void actionPerformed(ActionEvent e) {
LinePanel.this.p1.translate(dx, dy);
LinePanel.this.p2.translate(dx, dy);
LinePanel.this.repaint();
}
});
ControlPanel.this.getInputMap(
WHEN_IN_FOCUSED_WINDOW).put(k, k.toString());
ControlPanel.this.getActionMap().put(k.toString(), new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
MoveButton.this.doClick();
}
});
}
}
}
private void display() {
JFrame f = new JFrame("LinePanel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.add(new ControlPanel(), BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new LinePanel().display();
}
});
}
}
But basically I just want to know how to make the image move left to right while the window is listening to a keypress
You can use a Swing Timer to animate an image:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimerAnimation extends JLabel implements ActionListener
{
int deltaX = 2;
int deltaY = 3;
int directionX = 1;
int directionY = 1;
public TimerAnimation(
int startX, int startY,
int deltaX, int deltaY,
int directionX, int directionY,
int delay)
{
this.deltaX = deltaX;
this.deltaY = deltaY;
this.directionX = directionX;
this.directionY = directionY;
setIcon( new ImageIcon("dukewavered.gif") );
// setIcon( new ImageIcon("copy16.gif") );
setSize( getPreferredSize() );
setLocation(startX, startY);
new javax.swing.Timer(delay, this).start();
}
public void actionPerformed(ActionEvent e)
{
Container parent = getParent();
// Determine next X position
int nextX = getLocation().x + (deltaX * directionX);
if (nextX < 0)
{
nextX = 0;
directionX *= -1;
}
if ( nextX + getSize().width > parent.getSize().width)
{
nextX = parent.getSize().width - getSize().width;
directionX *= -1;
}
// Determine next Y position
int nextY = getLocation().y + (deltaY * directionY);
if (nextY < 0)
{
nextY = 0;
directionY *= -1;
}
if ( nextY + getSize().height > parent.getSize().height)
{
nextY = parent.getSize().height - getSize().height;
directionY *= -1;
}
// Move the label
setLocation(nextX, nextY);
}
public static void main(String[] args)
{
JPanel panel = new JPanel();
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().setLayout(null);
// frame.getContentPane().add( new TimerAnimation(10, 10, 2, 3, 1, 1, 10) );
frame.getContentPane().add( new TimerAnimation(300, 100, 3, 2, -1, 1, 20) );
// frame.getContentPane().add( new TimerAnimation(0, 000, 5, 0, 1, 1, 20) );
frame.getContentPane().add( new TimerAnimation(0, 200, 5, 0, 1, 1, 80) );
frame.setSize(400, 400);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
// frame.getContentPane().add( new TimerAnimation(10, 10, 2, 3, 1, 1, 10) );
// frame.getContentPane().add( new TimerAnimation(10, 10, 3, 0, 1, 1, 10) );
}
}
You can add a KeyListener to the panel and it will operate independently of the image animation.