Working with JButtons (extra help) - java

I've recently been working on putting together a program that can track one's success during a basketball game. I have a court diagram set up, and my idea is that after clicking a "make" or "miss" button, you can click a spot on the court and it will chart your makes and misses while keeping tallies of both off to the side. I was thinking the easiest way to do this was to fill the court with a huge grid of buttons (20x20), and when you click one it would change the text to an "x" or an "o" depending on if it was a made shot. I have no problems for creating listeners for the various buttons, but the buttons show up over top of the graphics of the court lines. Making the buttons transparent (which I tried) makes it look a little better, but my ideal solution would be to make the buttons in the grid invisible, yet clickable and able to change its text after being clicked.
I am yet to find such a method or other way to make this happen, so if anyone has any experience or input in creating something that could make it function in this way would help. I guess my ultimate question would be is there a way to make buttons invisible, yet clickable? If there is no simple way to do this (which I fear), are there any other ideas that you have that could make this program function effectively that might not involve buttons?
Thank you very much and any ideas would help me out a lot.
I also think I might note that I have a separate driver from the code, even though it probably does not make a difference.

You could do something like this
For the two buttons, just change the boolean make. You'll see why later
boolean make = false;
makeButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent){
make = true;
}
});
missButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent){
make = false;
}
});
Then you have your paintComponent
protected void paintComponent(Graphics g){
super.paintComponent(g);
if (make){
drawOval(whataver are your point requirements)
} else {
// draw an x at whatever points
}
}
You can see from above that I made use of the made variable
Now to get the location you can do something like this
Point p;
courtPanel.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
p = e.getLocationOnScreen();
repaint();
}
});
You paint component will paint based off those point coordinates.
SO basically, what all the thing I listed above does is:
1) When the makeButton is pressed, it changes the setting to made so when the panel is painted, it gets painted with a circle and an X when the missButtton is pressed.
2) I add a mouseListener to thecourtPanelbecuase everytime the panel is clicked somewhere, that's the point on the floor where is it either painted anxor acircle`
If you want multiple X and circle painted you do something like this
private boolean make = false;
private HashMap<Boolean, Point> points = new HaspMap<>();
makeButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent){
make = true;
}
});
missButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent){
make = false;
}
});
courtPanel.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
if (make) {
points.put(true, e.getLocationOnScreen());
repaint();
} else {
points.put(false, e.getLocationOnScreen());
repaint();
}
});
protected void paintComponent(Graphics g){
super.paintComponent(g);
for (Map.Entry<Boolean, Point> entry : points.entrySet()) {
Boolean key = entry.getKey();
Point point = entry.getValue();
if (key) {
g.grawOval(point.getX(), point.getY(), 10, 20);
} esle {
g.drawLine(.., .., .., ..); //draws one half of `X`
g.drawLine(.., .., .., ..); //draws other half
}
}
}

The problem with transparent components is, basically, it's next to near impossible to actually click them ;)
Another solution might be to use a MouseListener on the component rendering the map and simple make the translation from click point to "virtual grid", which you can then renderer over the top, for example...
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.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class BaseBallMap {
public static void main(String[] args) {
new BaseBallMap();
}
public BaseBallMap() {
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 static class TestPane extends JPanel {
public static final int GRID_COUNT = 20;
private BufferedImage map;
private List<Point> cells;
public TestPane() {
cells = new ArrayList<>(400);
try {
map = ImageIO.read(new File("Map.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
Point p = e.getPoint();
if (getMapBounds().contains(p)) {
p.x -= getXOffset();
p.y -= getYOffset();
int col = p.x / getColumnWidth();
int row = p.y / getRowHeight();
System.out.println(col + "x" + row);
Point cell = new Point(col, row);
if (cells.contains(cell)) {
cells.remove(cell);
} else {
cells.add(cell);
}
repaint();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return map == null ? new Dimension(200, 200) : new Dimension(map.getWidth(), map.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (map != null) {
Graphics2D g2d = (Graphics2D) g.create();
int xOffset = getXOffset();
int yOffset = getYOffset();
int x = xOffset;
int y = yOffset;
g2d.drawImage(map, x, y, this);
int colWidth = getColumnWidth();
int rowHeight = map.getHeight() / GRID_COUNT;
g2d.setColor(new Color(255, 0, 0, 128));
for (Point p : cells) {
x = xOffset + (p.x * colWidth);
y = yOffset + (p.y * rowHeight);
g2d.fillRect(x, y, colWidth, rowHeight);
}
g2d.setColor(new Color(128, 128, 128, 64));
for (int col = 0; col < GRID_COUNT; col++) {
x = xOffset + (col * colWidth);
g2d.drawLine(x, yOffset, x, yOffset + map.getHeight());
}
for (int row = 0; row < GRID_COUNT; row++) {
y = yOffset + (row * rowHeight);
g2d.drawLine(xOffset, y, xOffset + map.getWidth(), y);
}
g2d.drawRect(xOffset, yOffset, map.getWidth(), map.getHeight());
g2d.dispose();
}
}
protected int getColumnWidth() {
return map == null ? 0 : map.getWidth() / GRID_COUNT;
}
protected int getRowHeight() {
return map == null ? 0 : map.getHeight() / GRID_COUNT;
}
protected int getXOffset() {
return map == null ? 0 : (getWidth() - map.getWidth()) / 2;
}
protected int getYOffset() {
return map == null ? 0 : (getHeight() - map.getHeight()) / 2;
}
protected Rectangle getMapBounds() {
return map == null ? new Rectangle(0, 0, 0, 0) : new Rectangle(getXOffset(), getYOffset(), map.getWidth(), map.getHeight());
}
}
}

Related

How do I set a well functioning JFrame to be inside another JFrame as a internal JFrame?

Now I know how JInternalFrame works but what I am trying to do is give an already well-functioning JFrame with a space in a place where I have placed an empty Internal Frame.
I want it to grab what I have in the already existing JFrame in the package and place it in that Internal JFrame. Here is the JFrame I want to be placed into another JFrame as an internal frame.
Why I wanna do it this way because the inner frame has a lot of functionality and the container Jframe would be too big to do it all in itself.
What it does is not much of an interest to the thing I wanna do but here it is: It takes images and makes them pure b/w and takes 2 clicks on the screen and stores every pixel between them in a 2d array with their coordinates.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
public class imageFilt {
public static void main(String[] args) {new imageFilt();}
//--basic initialization
int[] x= new int[3], y= new int[3];
static int[] black= new int[3]; //---------------- if black is 0, then the pixel is black
int clr;int flag=0;
//-----------------------------initialize the screen as runnable. dont disturb the fit
public imageFilt() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());} catch (Exception ex) {}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage blackWhite;
public TestPane() {
//----------------------try/catch for (pure black || pure white)
try {
master = ImageIO.read(new File("D:\\colz\\java\\1Aakansh thapa\\1_1_2.jpg"));
blackWhite = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
Graphics2D g2d = blackWhite.createGraphics();
g2d.drawImage(master, 0, 0, this);
g2d.dispose();
}catch (IOException ex) {ex.printStackTrace();}
//--------------------------1st and 2nd click point data and color
this.addMouseListener(new MouseListener() {
int[] isFristEmpty;
#Override
public void mouseClicked(MouseEvent e1) {
int[] temp =new int[3]; //external container so i can get 1st and 2nd separately
temp[0] = (int) e1.getX();
temp[1] = (int) e1.getY();
clr = blackWhite.getRGB(temp[0], temp[1]);
temp[2] = (clr & 0x00ff0000) >> 16;//--------------------bit map to find if red is there or not.
//-------------------------------------------------------since its pure b/w, if red 0, its white.
if(isFristEmpty==null) {
isFristEmpty=temp;
x[0] = temp[0]; y[0] = temp[1]; black[0]=temp[2];//------1st click
}else {
x[1] = temp[0]; y[1] = temp[1]; black[1]=temp[2];//-----2nd click
isFristEmpty=null; //so the 3rd click is considered 1st click again
flag=1;
}
if (flag==1) {
System.out.print("X1: "+x[0]+" & "+"Y1: "+y[0]+" "+"(225 if white): "+black[0]+"\t");
System.out.println("X2: "+x[1]+" & "+"Y2: "+y[1]+" "+"(225 if white): "+black[1]);
counter(x,y);
}
}
#Override public void mousePressed(MouseEvent e) {}
#Override public void mouseReleased(MouseEvent e) {}
#Override public void mouseEntered(MouseEvent e) {}
#Override public void mouseExited(MouseEvent e) {}
});
}
//--------------------------------------------DDA block
private void counter(int x[],int y[]) {
if(flag!=1) return;//-------------------to only go to counter method after it takes that 2nd click
int dx = (x[1] - x[0]);
int dy = (y[1] - y[0]);//--------------makes it applicable for both inclinations (we do not have math.abs implies-> -ve goes as -ve)
int step = Math.abs(dx) > Math.abs(dy) ? Math.abs(dx) : Math.abs(dy);
System.out.println("Steps: "+step);
float Xinc = dx / (float) step;
float Yinc = dy / (float) step;
int[][] tog= new int[step][3];
tog[0][0]=x[0]; tog[0][1]=y[0];
//---------------------------------------------------------------send value of x1 and y1 to listOfCoordinates
float xt=x[0],yt=y[0]; int i=0, j=1; int a=0 ,b=0;
while (a!=x[1] && b!=y[1]){
xt += Xinc;
yt += Yinc;
a=(int) xt; b=(int) yt;
tog[j][i] = a;
tog[j][i+1] = b;
//System.out.println(tog[j][i]+" "+tog[j][i+1]); //*------------to print all that is saved
if(i==1) i=0;
}
}
//------------image size and such stuff. don't touch it
#Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if (master != null) {
size = new Dimension(master.getWidth(), master.getHeight());
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (master != null) {
int x = (getWidth() - (master.getWidth())) / 2;
int y = (getHeight() - master.getHeight()) / 2;
g.drawImage(blackWhite, x, y, this);
}
}
}
}
Hope what I wanna do makes sense.
Just imported the frame that I want into the JFrame I want it to be in and did this.
JInternalFrame printImg = new JInternalFrame(inTitle);
JPanel inLabel= new JPanel();
inLabel.add(new TestPane());
printImg.add(inLabel);
printImg.setVisible(true);
just for people who want to know when they stumble upon the post. Wouldnt want them to stay unanswered.
might also work if u copy-paste the Testpane (as the example) part and do the same thing for the rest instead of importing.

Problems with BufferedImage in Java

I am making a game (like Civilization) that has different tile types that I want to render as images. I have 9 different 16x16 png images to load in (called Con1, Con2, etc.), and here is my image loading code: (img[] is my BufferedImage array)
public void loadImages(){
for(int i = 0; i < 9; i++){
try {
img[i] = ImageIO.read(this.getClass().getResource("Con"+i+".png"));
}catch (Exception ex) {
System.out.println("Missing Image");
ex.printStackTrace();
}
}
}
I then paint these images with this code: (t[][] is my tile type array)
public void paint(Graphics g){
if(loop){
BufferedImage B = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics r = B.getGraphics();
for (int x = 0; x < WIDTH; x++){
for (int y = 0; y < HEIGHT; y++){
if(i[x][y] == 0){
if (t[x][y] == 0){
g.drawImage(img[0], x, y, this);
}
else if(t[x][y] == 1){
g.drawImage(img[1], x, y, this);
}
else if(t[x][y] == 3){
g.drawImage(img[3], x, y, this);
}
else if(t[x][y] == 4){
g.drawImage(img[4], x, y, this);
}
else if(t[x][y] == 5){
g.drawImage(img[5], x, y, this);
}
}
r.fillRect(x*SCALE, y*SCALE, SCALE, SCALE);
}
}
g.drawImage(B, 0, 22, this);
}
}
My problem is that it doesn't show up correctly when I run it. I get this image:
that flashes on and off in the top-left corner of the window. What I am supposed to see is an image similar to the top-left portion of the above one (landmasses surrounded by ocean) except large enough to fill the window. Here is some runnable code: (I don't think the code will run without the required images but I would appreciate some help with getting the images to you all.)
//imports
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class MCVCon extends JFrame implements KeyListener, MouseListener{
//setting up variables
public BufferedImage[] img = new BufferedImage[9];
private final int WIDTH = 50, HEIGHT = 50;
private boolean loop = false;
private int SCALE = 16;
int t[][] = new int[WIDTH][HEIGHT]; //terrain type (since I took out the terrain generation it is set to 0 or ocean)
public MCVCon(){
//creating the window
super("Conqueror");
setSize(SCALE*WIDTH, SCALE*HEIGHT+22);
setVisible(true);
requestFocusInWindow();
setDefaultCloseOperation(EXIT_ON_CLOSE);
loadImages();
loop = true;
while(true){
this.repaint();
//delay for repaint
try{
Thread.sleep(50);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
//load images
public void loadImages(){
for(int i = 0; i < 9; i++){
try {
img[i] = ImageIO.read(this.getClass().getResource("Con"+i+".png"));
}catch (Exception ex) {
System.out.println("Missing Image");
ex.printStackTrace();
}
}
}
//paint the images
public void paint(Graphics g){
if(loop){
BufferedImage B = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics r = B.getGraphics();
for (int x = 0; x < WIDTH; x++){
for (int y = 0; y < HEIGHT; y++){
if (t[x][y] == 0){
g.drawImage(img[0], x, y, this);
}
else if(t[x][y] == 1){
g.drawImage(img[1], x, y, this);
}
r.fillRect(x*SCALE, y*SCALE, SCALE, SCALE);
}
}
g.drawImage(B, 0, 22, this);
}
}
//run the program
public static void main(String[] args) {
new MCVCon();
}
//necessary overrides
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
I was wondering what the problem might be. Thanks in advance.
So, I had a look at your code, there's no easy way to say, but it's a mess, with compounding issues which would make it very difficult to isolate the origin of any one problem, other than to say, they all feed into each other.
Let's start with the painting...
You're painting directly to the frame. This is generally discouraged for a number of reasons.
Let's start with the fact that JFrame isn't a single component, it's made up of a number compounding components
This makes it inherently dangerous to paint directly to, as any one of the child components could be painted without the frame's paint method been called.
Painting directly to a frame also means you're painting without consideration to the frame's borders/decorations, which are added into the visible area of the window, but wait...
setSize(SCALE*WIDTH, SCALE*HEIGHT+22);
suggests that you've tried to compensate for this, but this is "guess" work, as the decorations could take up more or less space depending on the configuration of the system
And, finally, top level containers aren't actually double buffered.
"But I'm painting to my own buffer" you say - but you're not
You create a BufferdImage and assign it's Graphics context t r
BufferedImage B = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics r = B.getGraphics();
But when you paint anything, you're using g, which is the Graphics context passed to the paint method
g.drawImage(img[0], x, y, this);
This is also woefully inefficient, as you're creating a new BufferedImage each time paint is called, which takes time to create, takes up memory and puts extra strain on the garbage collection process as the local object becomes eligible for disposal almost immediately
Don't even get me started on the "main paint loop"
The next problem you have, is you have no concept of virtual and real world space.
You make a virtual map of your world using t, which maintains information about which tile should be used for a given x/y coordinate, but you never map this to the real world, instead, you paint each tile exactly at the same pixel x/y position, which means they now overlap, tiles have width and height, which means they need to be offset when painted onto the real world.
And finally, which I think is your actually question, is about scaling. There are a number of ways you could apply scaling, you could pre-scale the tiles when you load them, this gives you a lot of control over "how" they are scaled, but locks you into a single scale.
You could instead maintain a list of the scaled tiles, generated from a master list, which can be updated if the scale changes
Or you could simply scale the Graphics context directly.
Now, I've create a simple example, based on your code, correcting for most of the above. It creates a series of randomly colored rectangles at 10x10 pixels, instead of tiles, but the concept is the same.
import java.awt.Color;
import java.awt.Dimension;
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.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class MCVCon extends JFrame {
//setting up variables
public MCVCon() {
//creating the window
super("Conqueror");
add(new GamePane());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MCVCon frame = new MCVCon();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
//necessary overrides
public class GamePane extends JPanel {
public BufferedImage[] img = new BufferedImage[9];
private final int width = 5, height = 5;
private int scale = 16;
int t[][] = new int[width][height]; //terrain type (since I took out the terrain generation it is set to 0 or ocean)
Color[] colors = new Color[]{
Color.RED,
Color.BLUE,
Color.CYAN,
Color.DARK_GRAY,
Color.GRAY,
Color.GREEN,
Color.LIGHT_GRAY,
Color.MAGENTA,
Color.ORANGE,
Color.PINK,
Color.YELLOW
};
int tileHeight = 10;
int tileWidth = 10;
public GamePane() {
loadImages();
Random rnd = new Random();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int value = rnd.nextInt(9);
System.out.println(value + "- " + colors[value]);
t[x][y] = value;
}
}
Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width * tileWidth * scale, height * tileHeight * scale);
}
public void loadImages() {
for (int i = 0; i < 9; i++) {
try {
img[i] = new BufferedImage(tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img[i].createGraphics();
g2d.setColor(colors[i]);
g2d.fill(new Rectangle(0, 0, tileWidth, tileHeight));
g2d.dispose();
} catch (Exception ex) {
System.out.println("Missing Image");
ex.printStackTrace();
}
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setTransform(AffineTransform.getScaleInstance(scale, scale));
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
g2d.drawImage(img[t[x][y]], x * tileWidth, y * tileHeight, this);
}
}
g2d.dispose();
}
}
}

How to move graphics based on input from arrow keys? [duplicate]

I'm trying to make a program in java that involves making an object move constantly from a single key press. Think Pacman, where you press up once and Pacman continues to go up until you press another key. I want to keep the code simple if possible. My original movement (one keypress = one movement) is like this:
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_A){
x -= 5;
}
if(keyCode == e.VK_D){
x += 5;
}
if(keyCode == e.VK_W){
y -= 5;
}
if(keyCode == e.VK_S){
y += 5;
}
}
The x and y in values are the position of an oval. This works perfectly, but I want it to keep moving after I press the key only once, instead of having to hold it to keep the movement going. I tried a while loop with a boolean parameter that moves while true and doesn't while false, but as soon as I activate the loop, it freezes the program. Here's an example of that bit of code:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT && moveL==false){
moveL=true;
moveR=false;
moveU=false;
moveD=false;
while(moveL){
x--;
}
}
Please help me figure this out, I've been trying and looking around for days now. I appreciate any help you guys can give. Thanks.
The basic concept revolves around this idea of a "delta" or "change" value. This value is then applied to the state you want to change by either incrementing or decrementing the state value by it.
Because of the nature of Swing, you can't block the Event Dispatching Thread, otherwise you end up preventing from processing incoming events (such as paint and key events).
Equally, you should never try and update any UI component (or state variable that might effect the UI) from any thread other then the EDT.
While there are tricks you can apply to facilitate these requirements, the simplest is to use a javax.swing.Timer, which triggers a actionPerformed event on a regular bases within the EDT.
When this occurs you "update" all the elements by the prescribed amount and repaint the screen.
import java.awt.BorderLayout;
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.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PacManTest {
public static void main(String[] args) {
new PacManTest();
}
public PacManTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new MazePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PacMan {
private int x;
private int y;
private int deltaX;
private int deltaY;
private BufferedImage sprite;
public PacMan() {
try {
sprite = ImageIO.read(new File("PacMan.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void move(int x, int y) {
deltaX = x;
deltaY = y;
}
public void update(MazePane pane) {
x += deltaX;
y += deltaY;
if (x + sprite.getWidth() > pane.getWidth()) {
x = pane.getWidth() - sprite.getWidth();
} else if (x < 0) {
x = 0;
}
if (y + sprite.getHeight() > pane.getHeight()) {
y = pane.getHeight() - sprite.getHeight();
} else if (y < 0) {
y = 0;
}
}
public void paint(MazePane pane, Graphics2D g2d) {
Graphics2D g = (Graphics2D) g2d.create();
float angle = 0;
if (deltaX != 0) {
angle = deltaX > 0 ? 0 : 180;
} else if (deltaY != 0) {
angle = deltaY > 0 ? 90 : 270;
}
AffineTransform t = new AffineTransform();
t.translate(x, y);
t.rotate(Math.toRadians(angle), sprite.getWidth() / 2, sprite.getHeight() / 2);
g.setTransform(t);
g.drawImage(sprite, 0, 0, pane);
g.dispose();
}
}
public class MazePane extends JPanel {
private PacMan pacMan;
public MazePane() {
pacMan = new PacMan();
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pacMan.update(MazePane.this);
repaint();
}
});
timer.start();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");
am.put("left", new MoveAction(pacMan, -4, 0));
am.put("right", new MoveAction(pacMan, 4, 0));
am.put("up", new MoveAction(pacMan, 0, -4));
am.put("down", new MoveAction(pacMan, 0, 4));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
pacMan.paint(this, g2d);
g2d.dispose();
}
public class MoveAction extends AbstractAction {
private int deltaX;
private int deltaY;
private PacMan pacMan;
public MoveAction(PacMan pacMan, int deltaX, int deltaY) {
this.deltaX = deltaX;
this.deltaY = deltaY;
this.pacMan = pacMan;
}
#Override
public void actionPerformed(ActionEvent e) {
pacMan.move(deltaX, deltaY);
}
}
}
}
I would also recommend that you take the time to learn about Key Bindings, KeyListener suffer from focus issues, which key bindings are capable of addressing...
You need to process the move in a separate thread. I.e.:
public class Pacman implements Runnable
{
public void run(){
//moving code, i.e. in a while loop
//every move will notify the EDT:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
//update the Swing here - i.e. move Pacman
}
}
}
public void startMoving(){
new Thread(this).start();
}
//more methods to set speed, direction, etc...
}
Then you keep a reference to an instance of Pacman class in your Gui class and respond to various key presses by changing pacman's parameters:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT){
pacman.newDirection(LEFT); //for exmaple, enum with direction LEFT, RIGHT, UP, DOWN...
}
//etc... more logic
}

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();
}
}
}

Continuous movement with a single key press?

I'm trying to make a program in java that involves making an object move constantly from a single key press. Think Pacman, where you press up once and Pacman continues to go up until you press another key. I want to keep the code simple if possible. My original movement (one keypress = one movement) is like this:
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_A){
x -= 5;
}
if(keyCode == e.VK_D){
x += 5;
}
if(keyCode == e.VK_W){
y -= 5;
}
if(keyCode == e.VK_S){
y += 5;
}
}
The x and y in values are the position of an oval. This works perfectly, but I want it to keep moving after I press the key only once, instead of having to hold it to keep the movement going. I tried a while loop with a boolean parameter that moves while true and doesn't while false, but as soon as I activate the loop, it freezes the program. Here's an example of that bit of code:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT && moveL==false){
moveL=true;
moveR=false;
moveU=false;
moveD=false;
while(moveL){
x--;
}
}
Please help me figure this out, I've been trying and looking around for days now. I appreciate any help you guys can give. Thanks.
The basic concept revolves around this idea of a "delta" or "change" value. This value is then applied to the state you want to change by either incrementing or decrementing the state value by it.
Because of the nature of Swing, you can't block the Event Dispatching Thread, otherwise you end up preventing from processing incoming events (such as paint and key events).
Equally, you should never try and update any UI component (or state variable that might effect the UI) from any thread other then the EDT.
While there are tricks you can apply to facilitate these requirements, the simplest is to use a javax.swing.Timer, which triggers a actionPerformed event on a regular bases within the EDT.
When this occurs you "update" all the elements by the prescribed amount and repaint the screen.
import java.awt.BorderLayout;
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.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PacManTest {
public static void main(String[] args) {
new PacManTest();
}
public PacManTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new MazePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PacMan {
private int x;
private int y;
private int deltaX;
private int deltaY;
private BufferedImage sprite;
public PacMan() {
try {
sprite = ImageIO.read(new File("PacMan.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void move(int x, int y) {
deltaX = x;
deltaY = y;
}
public void update(MazePane pane) {
x += deltaX;
y += deltaY;
if (x + sprite.getWidth() > pane.getWidth()) {
x = pane.getWidth() - sprite.getWidth();
} else if (x < 0) {
x = 0;
}
if (y + sprite.getHeight() > pane.getHeight()) {
y = pane.getHeight() - sprite.getHeight();
} else if (y < 0) {
y = 0;
}
}
public void paint(MazePane pane, Graphics2D g2d) {
Graphics2D g = (Graphics2D) g2d.create();
float angle = 0;
if (deltaX != 0) {
angle = deltaX > 0 ? 0 : 180;
} else if (deltaY != 0) {
angle = deltaY > 0 ? 90 : 270;
}
AffineTransform t = new AffineTransform();
t.translate(x, y);
t.rotate(Math.toRadians(angle), sprite.getWidth() / 2, sprite.getHeight() / 2);
g.setTransform(t);
g.drawImage(sprite, 0, 0, pane);
g.dispose();
}
}
public class MazePane extends JPanel {
private PacMan pacMan;
public MazePane() {
pacMan = new PacMan();
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pacMan.update(MazePane.this);
repaint();
}
});
timer.start();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");
am.put("left", new MoveAction(pacMan, -4, 0));
am.put("right", new MoveAction(pacMan, 4, 0));
am.put("up", new MoveAction(pacMan, 0, -4));
am.put("down", new MoveAction(pacMan, 0, 4));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
pacMan.paint(this, g2d);
g2d.dispose();
}
public class MoveAction extends AbstractAction {
private int deltaX;
private int deltaY;
private PacMan pacMan;
public MoveAction(PacMan pacMan, int deltaX, int deltaY) {
this.deltaX = deltaX;
this.deltaY = deltaY;
this.pacMan = pacMan;
}
#Override
public void actionPerformed(ActionEvent e) {
pacMan.move(deltaX, deltaY);
}
}
}
}
I would also recommend that you take the time to learn about Key Bindings, KeyListener suffer from focus issues, which key bindings are capable of addressing...
You need to process the move in a separate thread. I.e.:
public class Pacman implements Runnable
{
public void run(){
//moving code, i.e. in a while loop
//every move will notify the EDT:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
//update the Swing here - i.e. move Pacman
}
}
}
public void startMoving(){
new Thread(this).start();
}
//more methods to set speed, direction, etc...
}
Then you keep a reference to an instance of Pacman class in your Gui class and respond to various key presses by changing pacman's parameters:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT){
pacman.newDirection(LEFT); //for exmaple, enum with direction LEFT, RIGHT, UP, DOWN...
}
//etc... more logic
}

Categories

Resources