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();
}
}
}
Related
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.
How to make a list or an array of 10 coins appear on the game? It is the same coin image. I want my sprite (Mario) to pick up all 10 coins, but I want them next to each other } maybe I could manually type out the x locations.
Mainly I am not sure how to make the coins appear on the screen.
UPDATE: The coins appear when I manually type out each coin (exp. coins[0]=tool.kit..). It does not work with the for loop though.
public class Action extends JPanel implements ActionListener, KeyListener {
Timer t = new Timer(5, this);
private Image man;
int x=0, y=490, a=(int) (Math.random() * 450 + 1), b=500; // make a random num
Image img;
Image [] coins = new Image [10];
public Action() {
super.setDoubleBuffered(true);
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
img = Toolkit.getDefaultToolkit().createImage("background.png");
}
#Override
public void paintComponent (Graphics g) {
super.paintComponent(g);
ImageIcon ii = new ImageIcon("realmario.png");
man = ii.getImage();
g.drawImage(img,0, 0, null);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(man, x, y, this);
g2d.drawImage(coins[1], a, b, this);
for (int i = 0; i<coins.length; i++) {
coins[i] = Toolkit.getDefaultToolkit().createImage("coin.png");
}
}
If you want to place objects one linked to other you have to work with x-axis and adjust properly.
Eg. img have (3,7) pixels and first will be at (10,10). You need to grab x = 3 and made adjustments in loop.
1: img at 10,10 (initial)
2: img at 10+3,10
3: img at 10+3+3,10 ; etc
//image dimension on x
int image_x = 3;
//initial placement on x,y
int x=10,y=10;
for(int i=0;i<coins.length; i++)
{
//if same image is enough one coin
g2d.drawImage(coin[7],x,y,this);
x=x+image_x;
}
Just check first the coordinates system.
Draw the same image 10 times, each with different coordinates:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class SwingTest extends JFrame {
public SwingTest() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(new ImagePanel());
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> new SwingTest());
}
}
class ImagePanel extends JComponent {
BufferedImage coin = getImage();
private static final int GAP =2;
public ImagePanel() {
setPreferredSize(new Dimension( 300, 200));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
int x=0, y= GAP;
for (int i = 0; i <3 ; i++) {
g.drawImage(coin,x,y, this);
x= x+ GAP + coin.getWidth();
}
}
public static BufferedImage getImage() {
try {
URL url = new URL("http://www.btcwmx.ru/admin/uploads/img/bitcoin-gold.png");
return ImageIO.read(url);
} catch ( IOException ex) { ex.printStackTrace();}
return null;
}
}
I am painting vehicle objects that I defined using the paintComponent().
Because the vehicles can move, I implement ActionListener and set a Timer() to trigger.
As a result, my vehicles can move. But it is kind of "shaking". When I keep resizing the window to call the paintComponent(), the movement becomes smooth. When I do not resize the window (not calling paintComponent), it gets skaking again. Why? How to fix it?
public class VehiclesComponent extends JComponent implements ActionListener{
private Vehicle[] vehicles;
private Timer timer;
public VehiclesComponent(int n){
vehicles = Vehicle.generateVehicle(n);
timer = new Timer(5,this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for (int i=0; i<vehicles.length; i++) {
vehicles[i].draw(g2);
}
// may change later
timer.start();
}
#Override
public void actionPerformed(ActionEvent e){
//check collision in here
for (Vehicle v : vehicles) {
if (Vehicle.intersectsOther(v, vehicles)) {
v.collisionSideEffect();
}
}
//move all in here
for (Vehicle v : vehicles ) {
v.move();
}
repaint();
//?? repaint slower than paintComponent
}
}
Start by taking a look at Painting in AWT and Swing. Remember, repaint is only a suggest made to the RepaintManager, the RepaintManager may choose to consolidate multiple repaint calls into a smaller number of actual paint events.
Make sure you are calling super.paintComponent, otherwise you will end up with no end of strange paint artifacts.
Don't, directly or indirectly, modify the state of the component or ant other components from within any paint method, this will result in a new repaint request been made, which could lead to a cycle of paint events which could consume your CPU cycles. This means, don't call timer.start()!
Without a runable example to go by, I hobbled this together. Now this is animating 10, 000 individual Vehicles (rectangles), so it's massively over kill, but it should provide the point...
(the gif is only running at 7fps, not your 200fps)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
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 VehiclesComponent(10000));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class VehiclesComponent extends JComponent implements ActionListener {
private Vehicle[] vehicles;
private Timer timer;
public VehiclesComponent(int n) {
vehicles = Vehicle.generateVehicle(n, getPreferredSize());
timer = new Timer(5, this);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i < vehicles.length; i++) {
vehicles[i].draw(g2);
}
}
#Override
public void actionPerformed(ActionEvent e) {
//check collision in here
// for (Vehicle v : vehicles) {
// if (Vehicle.intersectsOther(v, vehicles)) {
// v.collisionSideEffect();
// }
// }
//move all in here
for (Vehicle v : vehicles) {
v.move(this.getSize());
}
repaint();
//?? repaint slower than paintComponent
}
}
public static class Vehicle {
protected static final int SIZE = 5;
protected static final Color[] COLORS = new Color[]{
Color.BLACK,
Color.BLUE,
Color.CYAN,
Color.DARK_GRAY,
Color.GREEN,
Color.MAGENTA,
Color.ORANGE,
Color.PINK,
Color.RED,
Color.WHITE,
Color.YELLOW
};
private int x = 0;
private int y = 0;
private int xDelta;
private int yDelta;
private Shape car;
private Color color;
public static Vehicle[] generateVehicle(int count, Dimension bounds) {
Vehicle[] vehicles = new Vehicle[count];
for (int index = 0; index < vehicles.length; index++) {
vehicles[index] = new Vehicle(bounds);
}
return vehicles;
}
public Vehicle(Dimension size) {
x = (int)(Math.random() * (size.width - SIZE));
y = (int)(Math.random() * (size.height - SIZE));
xDelta = (int)(Math.random() * 3) + 1;
yDelta = (int)(Math.random() * 3) + 1;
car = new Rectangle(SIZE, SIZE);
color = COLORS[(int)(Math.random() * COLORS.length)];
}
public void move(Dimension size) {
x += xDelta;
y += yDelta;
if (x < 0) {
x = 0;
xDelta *= -1;
} else if (x + SIZE > size.width) {
x = size.width - SIZE;
xDelta *= -1;
}
if (y < 0) {
y = 0;
yDelta *= -1;
} else if (y + SIZE > size.height) {
y = size.height - SIZE;
yDelta *= -1;
}
}
public void draw(Graphics2D g2) {
g2.translate(x, y);
g2.setColor(color);
g2.fill(car);
g2.translate(-x, -y);
}
}
}
You could also take a look at this example which renders upwards of 4500 images in random directions and demonstrates some optimisation techniques.
You can also take a look at this example which is capable of animating both in direction and rotation, upwards of 10, 000 images
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());
}
}
}
I have a thread which drops a circle in the y direction. I want to now create several circles on screen dropping at the same time with random x positions.
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Goo
{
protected GooPanel gooPanel;
private boolean loop = true;
protected int width , height;
private int frameTimeInMillis = 50;
private RenderingHints renderingHints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING , RenderingHints.
VALUE_ANTIALIAS_ON);
#SuppressWarnings("serial")
class GooPanel extends JPanel
{
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHints(renderingHints);
draw(g2d);
}
}
public Goo()
{
this (800, 500);
}
public Goo(int w, int h)
{
width = w;
height = h;
JFrame frame = new JFrame ();
frame.setSize(width , height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gooPanel = new GooPanel ();
gooPanel.setPreferredSize(new Dimension(w, h));
frame.getContentPane ().add(gooPanel);
frame.pack();
frame.setVisible(true);
}
public void go()
{
while (loop)
{
gooPanel.repaint();
try
{
Thread.sleep(frameTimeInMillis);
} catch (InterruptedException e) {}
}
}
public void draw(Graphics2D g) {}
public void setFrameTime(int millis)
{
frameTimeInMillis = millis;
}
public Component getGooPanel ()
{
return gooPanel;
}
}
My FallingDrop class:
import java.awt.*;
public class FallingDrops extends Goo
{
double x, y, r;
int red, green, blue = 0;
Color a;
FallingDrops()
{
x = width / 2;
r = 10;
y = -r;
}
FallingDrops(double x)
{
this.x = x;
r = 10;
y = -r;
}
public void draw(Graphics2D g)
{
g.setColor(Color.GRAY);
g.fillRect(0, 0, width , height);
g.setColor(Color.WHITE);
g.fillOval ((int) (x - r), (int) (y - r), (int) (2 * r),
(int) (2 * r));
y++;
if (y - r > height)
y = -r;
}
public static void main(String [] args)
{
int num = 10;
Goo gooDrop [] = new FallingDrops[num];
for(int i = 0; i < gooDrop.length; i++)
{
double x = Math.random()*800;
gooDrop[i] = new FallingDrops(x);
System.out.println(x);
gooDrop[i].go();
}
}
}
At current, the loop fails to complete when the go() method is executed; thus only painting ONE object on screen, and not several as indicated in my loop. This is a simple fix I am sure. Any ideas what I am doing wrong?
The method go() never returns. when it is called on the first object in the array, it continues working infinitely. you should either make the repainting in a separate thread that is constantly repainting. or if you want repainting only when drops are added, then remove the while in your go method
public void go()
{
gooPanel.repaint();
try
{
Thread.sleep(frameTimeInMillis);
} catch (InterruptedException e) {}
}
this way it will returns after it had made a repaining and a pause.
while (loop) .. gooPanel.repaint();
Not the way to do custom painting. Establish a Swing Timer and call repaint() in the actionPerformed() method of the listener.
See the Custom Painting lesson in the tutorial for details and working examples.