I am having a problem with the following code. My intent is to store the coordinates of a mouse click into an arraylist using getPoint, and then draw a rectangle at each location that the user has clicked. I have searched high and low for how to extract the x and y coordinates individually from a getPoint object to no avail. I am new to java, the line that is giving me trouble at compile time is:
g2.drawRect(coordinateList(j).getHeight(),coordinateList(j.getWidth(),3,3);
I know that I am probably way off, but how can I extract the x and y coordinates of a point individually from an array list, one item of the array by one in order to repaint a rectangle at the new click point and also all the previous clicks as well?
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.event.MouseListener;
import java.awt.Point;
import java.util.*;
public class ClickCloud extends JPanel
{
private int pointxy;
//private Rectangle2D.Double r1;
private boolean mouseClick;
private int count;
//private Point[] points;
private Point coordinates = new Point(0, 0);
private ArrayList<Point> coordinateList = new ArrayList<Point>();
public ClickCloud() {
this.setPreferredSize(new Dimension(500,500));
this.addMouseListener(new MyMouseListener());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (int j = 0; j < count; j++) {
g2.setStroke(new BasicStroke(1.0f));
g2.setPaint(Color.BLUE);
g2.drawRect(coordinateList(j).getHeight(),coordinateList(j.getWidth(),3,3);
}
}
private class MyMouseListener implements MouseListener {
public void mouseClicked(MouseEvent me) {
count++;
coordinates.setLocation(me.getPoint());
coordinateList.add(coordinates.getLocation());
repaint();
}
public void mousePressed(MouseEvent me) { }
public void mouseReleased(MouseEvent me) { }
public void mouseEntered(MouseEvent me) { }
public void mouseExited(MouseEvent me) { }
}
public static void main(String[] args) {
JFrame f = new JFrame("ClickCloud demo");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLayout(new FlowLayout());
f.add(new ClickCloud());
f.pack();
f.setVisible(true);
}
}
Thanks,
T
Forget all the getLocation and setLocation. It's redundant. Just store me.getPoint() in your coordinateList.
Then you can get the x and y coordinates with point.getX() and point.getY() respectively.
In paintComponent, there is an easier way to iterate over a list of points:
for (Point coordinate : coordinateList) { //"for each coordinate in coordinateList"
//do something with coordinate.getX() and coordinate.getY()
}
You are not getting properly the points from the ArrayList.
g2.drawRect(coordinateList(j).getHeight(),coordinateList(j.getWidth(),3,3);
To get the item at index j with an ArrayList, you simply use the method get():
Point point = coordinateList.get(j);
Then the problem is that pointonly represents, well, points... They only have X and Y coordinates, not width and height. If I try to guess what you want to do and assume that you want to draw 3x3 rectangles where the user has clicked, you would call drawRect() like this:
g2.drawRect(point.getX(), point.getY(), 3, 3);
Also:
You don't need to handle a count variable to know the number of points you have in your ArrayList. Just use the size() method of coordinateList or even better, use an enhanced for loop.
You can use MouseAdapter instead of MouseListener to only override the events you need.
You don't need the coordinates member and the get/setLocation stuff. Just write coordinateList.add(me.getPoint());
Related
I created this java program and I wanted an output of which if int x and int y are above 100, it would draw a rectangle. But it doesn't. How can I make it work?Is there another line of code I need to add?
Here's my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class GameSetup extends JPanel implements MouseMotionListener{
public static JFrame njf = new JFrame("Test");
public static int x, y;
public static void main(String[] args){
GameSetup gs = new GameSetup();
njf.add(gs);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(Color.BLACK);
g.setColor(Color.GREEN);
g.fillRect(150, 75, 200, 100);
g.setColor(Color.ORANGE);
g.drawString("Play", 239, 123);
njf.addMouseListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
}
});
if(x > 100 && y > 100){
g.drawRect(10, 10, 100, 100);
}
}
public GameSetup(){
njf.setSize(500,500);
njf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
njf.setResizable(false);
njf.setLocationRelativeTo(null);
njf.setVisible(true);
}
#Override
public void mouseDragged(MouseEvent arg0) {
}
#Override
public void mouseMoved(MouseEvent e) {
}
}
Okay, there are several things wrong with the code that you included above.
The first that stood out to me was the way that you are adding the mouse action listener to frame. There are multiple things that are wrong with this.
First of all, you are doing this in the paintComponent method, which, if it works, is still considered to be bad practice because the paintComponent method may be called multiple times. Do that, as pointed out by the comments, in the constructor of the panel.
The second is that you are adding the mouse listener to the frame, not the panel, which doesn't work because the panel is "above" the frame, so the mouse event will only be recognized within the panel. Your best bet here is to add a MouseMotionListener directly to the panel itself.
The third is that you are implementing the MouseMotionListenerinterface in the GameSetup class, but never actually doing anything with this implementation. So what I did was that I got rid of the inner class, and just had the panel be its own MouseMotionListnener
The second thing that is wrong with the code is that the paintComponent method is only called at certain points in time (see this). That means that even though the mouse might have moved within the zone, your paintComponent method isn't being called to update the screen accordingly. For this, you need to call the repaint method for your panel.
The third is that you didn't set a size for your panel, and the default one is 0x0, so you need to set a size of your panel (which should be the same as the frame itself) (if you want to keep the default layout).
All of that being said, here is your code that I fixed up. I added a variable called enteredZone to keep track of if the mouse had previously entered the zone, so that the rectangle would stay up even if the mouse left the zone after entering it (its your choice if you want to keep it). Note that there are other things with this code that might be considered bad practice, but this is enough to get you started:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class GameSetup extends JPanel implements MouseMotionListener {
public static JFrame njf = new JFrame("Test");
public static int x = 0, y = 0;
public static boolean enteredZone = false;
public static void main(String[] args) {
GameSetup gs = new GameSetup();
gs.addMouseMotionListener(gs);
njf.add(gs);
njf.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.BLACK);
g.setColor(Color.GREEN);
g.fillRect(150, 75, 200, 100);
g.setColor(Color.ORANGE);
g.drawString("Play", 239, 123);
if (x > 100 && y > 100 || enteredZone){
g.drawRect(10, 10, 100, 100);
enteredZone = true;
}
}
public GameSetup() {
super();
setSize(500, 500);
njf.setSize(500,500);
njf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
njf.setResizable(false);
njf.setLocationRelativeTo(null);
}
#Override
public void mouseDragged(MouseEvent arg0) {
}
#Override
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
if (x > 100 && y > 100) repaint();
}
}
I create this to draw a fish when the mouse is pressed at the mouse's x and y coordinate. but i seems then that the drawfish method is not being called. I can't find the reason why is it is not working. I would be me very grateful for any help.
/*FishTank*/
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
/*FishTank class-contains a frame and the WinstonCanvas.*/
public class FishTank{
public static void main ( String[] args ){
javax.swing.SwingUtilities.invokeLater(new Runnable(){
public void run(){
JFrame window = new JFrame();
window.setTitle("Fish Tank");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setBounds(30, 30, 700, 430);
window.getContentPane().add(new FishTankCanvas());
window.setVisible(true);
}
});
}
}
/*FishTankCanvas is a component that allows drawing shapes.*/
class FishTankCanvas extends JComponent {
static Graphics2D g;
int x = 11;
Timer myTimer;
public FishTankCanvas(){
myTimer = new Timer (2, new ActionListener(){
public void actionPerformed (ActionEvent evt){
repaint();
}
});
myTimer.start();
}
public void paint(Graphics graphics) {
g = (Graphics2D)graphics;
//makes the background white
Color backgroundColor = new Color(89, 216, 255);//light blue
g.setColor(backgroundColor);
g.fillRect(0,0,this.getWidth(),this.getHeight());
// drawfish (Graphics graphics, int bodyX, int bodyY, int bodyLength,int bodyHeight, int tailwidth, int eyesize,int tailcolor, int bodycolor)
// Mouselistener and mouseadapter
this.addMouseListener (new MouseAdapter() {
public void mousePressed(MouseEvent e) {
//call drawfish method
drawfish(FishTankCanvas.g,e.getX(), e.getY(),118,74,1,((int) (Math.random()*(4 - 0))));
repaint();
}
});
// x coordinate plus 1 of fish (animate)
x= x + 1;
}
// drawfish method
public void drawfish(Graphics graphics, int bodyX, int bodyY, int bodyLength,int bodyHeight,int tailcolor, int bodycolor ){
Graphics2D g = (Graphics2D)graphics;
bodyX +=x;
//colours
Color[] colours= new Color[5];
colours[0] = new Color(0, 0, 0);//black
colours[1] = new Color(162, 0, 255);//purple
colours[2] = Color.red;//red
colours[3] = new Color(255,255,0);// yellow
colours[4] = new Color(60,179,113);//green
//draw fish
// body
g.setColor(colours[bodycolor]);
g.fillOval(bodyX, bodyY, bodyLength, bodyHeight);
// tail
g.setColor(colours[tailcolor]);
int tailWidth = bodyLength/4;
int tailHeight = bodyHeight/2;
int[] tailPointx = new int[3];
int[] tailPointy = new int[3];
tailPointx[0]=bodyX;
tailPointy[0]=bodyY+bodyHeight/2;
tailPointx[1]=bodyX-tailWidth;
tailPointy[1]=bodyY+bodyHeight/2-tailHeight;
tailPointx[2]=bodyX-tailWidth;
tailPointy[2]=bodyY+tailHeight+tailHeight;
g.fillPolygon(tailPointx, tailPointy, 3);
// eye
g.setColor(colours[0]);
g.fillOval(bodyX+3*bodyLength/4, bodyY+bodyHeight/2-bodyHeight/5, bodyHeight/5, bodyHeight/5);
}
}
i seems then that the drawfish method is not being called.
Well that is easy enough to verify. All you need to do is add debug code to the method to determine if this is true or not. Then you can tell us if that is the problem instead of guessing.
Other problems:
Don't add the MouseListener to the component in a painting method. The listener should be added in the constructor of your class.
Don't override paint(). Custom painting is done by overriding the paintComponent() method. And don't forget to invoke super.paintComponent(...).
Extend JPanel instead of JComponent. Then you can just use the setBackground() method to paint the background.
However, the real problem is that when you click the mouse the fish might get drawn, but then the Timer does a repaint which will clear the panel 2ms later, so you never really see the fish. Get rid of the Timer. There is no need for the Timer to draw a fish.
Assuming you want to paint multiple fish you need to keep track of every place you click and then paint all the fish. The two way of doing this are:
Keep an ArrayList of the points where you want to paint the fish and then iterate through this list in your painting method
Paint the fish on a BufferedImage when the mouse click happens, and then just paint the image.
See Custom Painting Approaches for working examples of both of these approaches.
I have an array list that keeps track of the "dots" and am using an array to keep track of the different sizes. The size is changed via a mouseWheelListener and the change is saved in that array. However for some reason ALL of the dots are resized which is not what I want. After running through it a few times everything looks like it should work but I must be missing something simple. My code as follows.
//********************************************************************
// DotsPanel.java
// Represents the primary panel for the Dots program.
//********************************************************************
import java.util.ArrayList;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
public class DotsPanel extends JPanel
{
private int SIZE = 10; // radius of each dot
private int[] dotSizes = new int[10000];
int i = 0;
private ArrayList<Point> pointList;
//-----------------------------------------------------------------
// Constructor: Sets up this panel to listen for mouse events.
//-----------------------------------------------------------------
public DotsPanel()
{
pointList = new ArrayList<Point>();
addMouseListener (new DotsListener());
addMouseMotionListener(new DotsListener());
addMouseWheelListener(new DotsListener());
setBackground(Color.red);
setPreferredSize(new Dimension(300, 200));
}
//-----------------------------------------------------------------
// Draws all of the dots stored in the list.
//-----------------------------------------------------------------
public void paintComponent(Graphics page)
{
super.paintComponent(page);
page.setColor(Color.cyan);
for (Point spot : pointList)
//change size to sizes[n]
page.fillOval(spot.x-dotSizes[pointList.size()-1], spot.y-dotSizes[pointList.size()-1], dotSizes[pointList.size()-1]*2, dotSizes[pointList.size()-1]*2);
page.drawString("Count: " + pointList.size(), 5, 15);
}
//*****************************************************************
// Represents the listener for mouse events.
//*****************************************************************
private class DotsListener implements MouseListener, MouseMotionListener, MouseWheelListener
{
//--------------------------------------------------------------
// Adds the current point to the list of points and redraws
// the panel whenever the mouse button is pressed.
//--------------------------------------------------------------
public void mousePressed(MouseEvent event)
{
pointList.add(event.getPoint());
repaint();
}
//--------------------------------------------------------------
// Provide empty definitions for unused event methods.
//--------------------------------------------------------------
public void mouseClicked(MouseEvent event) {}
public void mouseReleased(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
#Override
public void mouseDragged(MouseEvent event)
{
pointList.add(event.getPoint());
dotSizes[pointList.size()-1] = SIZE;
//store size of dot here
repaint();
}
#Override
public void mouseMoved(MouseEvent event) {}
#Override
public void mouseWheelMoved(MouseWheelEvent event)
{
SIZE -= event.getWheelRotation();
repaint();
}
}
}
In this code:
for (Point spot : pointList)
//change size to sizes[n]
page.fillOval(spot.x-dotSizes[pointList.size()-1], spot.y-dotSizes[pointList.size()-1], dotSizes[pointList.size()-1]*2, dotSizes[pointList.size()-1]*2);
you are using a single dot size for all the dots: the size of the last dot that was added. (There's even a comment there to fix the problem!) You need to iterate with an index so you can index into the dotSizes array as well as the pointList ArrayList:
for (int i = 0; i < pointList.size(); ++i) {
Point spot = pointList.get(i);
int size = dotSizes[i];
page.fillOval(spot.x-size, spot.y-size, size*2, size*2);
}
It would be much better to define your own "point with size" class that encapsulates a Point and a size:
class Spot extends Point {
public int size;
public Spot(int x, int y, int size) {
super(x, y);
this.size = size;
}
}
Then change your pointList to an ArrayList<Spot> and you can go back to iterating over a single list:
for (Spot spot : pointList)
page.fillOval(spot.x-spot.size, spot.y-spot.size, 2*dot.size, 2*dot.size);
Of course, you'll also have to update the code that adds points to the list accordingly.
As an aside, it seems to me that your mousePressed handler has a bug: it does not add a size when it adds a point. Switching to a Spot class would also help avoid that kind of problem.
for (Point spot : pointList)
//change size to sizes[n]
page.fillOval(spot.x-dotSizes[pointList.size()-1], spot.y-dotSizes[pointList.size()-1], dotSizes[pointList.size()-1]*2, dotSizes[pointList.size()-1]*2);
Here is your problem. You aren't changing the size to size[n] but you are changing the size of every one to size[pointList.size()-1] or in other words, the last one. You will probably have to use a regular for loop unless you want to find the index of the current point.
I have started developing Tetris Game. Everything is working fine but how to retain rectangles at the bottom?
This is the Comp1 class in which the random shape is retrieved and move down with the timer
package buildblock;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import buildblock.tetris;
public class Comp1 extends JPanel implements ActionListener {
int curx=10;
int cury=30;
int nx=0;
int ny=0;
int p=1;
Timer t;
boolean EndofLine=false;
JLabel l1=new JLabel("");
int value=0;
int coords[][][]=new int[3][3][2];
int shape[][][][]={
{{{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0}}},
{{{0,0},{100,20},{0,0}},{{0,0},{100,40},{0,0}},{{80,60},{100,60},{0,0}}},
{{{0,0},{100,20},{0,0}},{{80,40},{100,40},{120,40}},{{0,0},{0,0},{0,0}}},
{{{0,0},{100,20},{0,0}},{{0,0},{100,40},{0,0}},{{0,0},{100,60},{0,0}}},
{{{80,20},{100,20},{0,0}},{{0,0},{100,40},{0,0}},{{0,0},{100,60},{0,0}}},
{{{0,0},{100,20},{0,0}},{{80,40},{100,40},{0,0}},{{80,60},{0,0},{0,0}}},
{{{80,20},{0,0},{0,0}},{{80,40},{100,40},{0,0}},{{0,0},{100,60},{0,0}}},
{{{80,20},{100,20},{0,0}},{{80,40},{100,40},{0,0}},{{0,0},{0,0},{0,0}}},
};
Comp1(tetris Parent)
{
setVisible(true);
setSize(400,900);
curx=(400-curx)/2;
setLayout(new BorderLayout());
timer();
}
public void getShape(int a)
{
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
for(int k=0;k<2;k++)
{
coords[i][j][k]=shape[a][i][j][k];
repaint();
}
}
}
}
public void paint(Graphics g)
{
super.paint(g);
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
for(int k=0;k<2;k++)
{
if(coords[i][j][k]!=0)
{
if(k==0)
{
curx=coords[i][j][k]+nx;
}
else
{
cury=coords[i][j][k]+ny;
drawRec(g,curx,cury,20,20);
}
}
}
}
}
}
public void drawRec(Graphics g,int newx,int newy,int w,int h)
{
g.drawRect(newx, newy, 20, 20);
g.drawLine(curx+1,cury+20-1,curx+20-1,cury+20-1);
}
public void timer()
{
t=new Timer(150,this);
t.start();
}
public int Random()
{
Random r=new Random();
int n=Math.abs(r.nextInt()%7+1);
return n;
}
public void lineDown()
{
ny=ny+10;
repaint();
}
public void actionPerformed(ActionEvent e)
{
if(value!=250&&!EndofLine)
{
value=value+5;
if(p==0)
{
p=Random();
}
getShape(p);
lineDown();
}
else
{
p=Random();
ny=0;
EndofLine=false;
value=0;
}
}
}
The shape is a 4 dimensional array from which the width and height of particular rectangle is retrieved which collectively form a desired shape.Through random function we choose the particular shape with getShape() method and using drawRect function we draw the Rectangles.
Now the lineDown function move down the particular shape with increment of 10,and after reaching at the last line the repaint() method is called and new Random shape is falling down from top,The Problem is now how to retain the particular shape at bottom so that next operations can be carried out.
I would create a List of "shapes" that have already fallen down to the bottom of the Tetris board. This List would be held within your Tetris class and when the current falling item hits the bottom of the board or one of the already falled shapes then it should be stopped and added to the fallen list.
Other general tips:
From personal experience, try to stay away from arrays of size > 2 unless its necessary; they are bloated, confusing and hard to maintain. In your case there's a perfect interface to use called Shape. Check out this code
// java.awt.geom.Path2D implements java.awt.Shape
java.awt.geom.Path2D path = new Path2D.Double();
path.moveTo(0, 0);
path.lineTo(2, 0);
path.lineTo(2, 2);
path.lineTo(2, 0);
path.closePath();
path.transform(AffineTransform.getScaleInstance(20, 20));
This creates a Shape that is your basic square! You then have access to great features that you wont have to implement yourself.
PS: As Andrew suggests in the comments, "Also look at Shape based collision detection. It uses Java 2D Area objects to test for intersection."
Hey guys I need help I am trying to make a program where I can draw in a window with the mouse. So far I have it to where when I click a dot appears but I need to add a drag method so that when I drag the mouse across the page it draws stuff. Can someone look at my code and help me out where you can?
Here is my code:
import javax.swing.*;
import java.awt.event.*;
public class mouse {
private static int x,y;
private static draw object = new draw ();
public static void main(String[] args){
JFrame frame = new JFrame ("Mouse");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.add(object);
object.addMouseListener(new AL());
}
static class AL extends MouseAdapter{
public void mousePressed(MouseEvent e){
x = e.getX();
y = e.getY();
object.drawing(x, y);
}
public void mouseDragged( MouseEvent e) {
x= e.getX();
y= e.getY();
object.drawing(x, y);
}
}
}
and
import javax.swing.*;
import java.awt.*;
public class draw extends JPanel {
private static int x,y;
public void drawing (int xx, int yy){
x=xx;
y=yy;
repaint();
}
public void paintComponent (Graphics g){
g.setColor(Color.black);
g.fillOval(x, y, 10, 10);
}
}
One idea that I have is to add your mouse coordinates each to a separate list whenever the mouse is clicked and draw based on the size of the lists, however since you are using mouse dragged you could just use Path2D.lineTo(x, y) and use e.getX() and e.getY() for the x and y coords. After this use Path2D.moveTo(x, y) to make sure line path is appended for each pixel the mouse moves (this makes sure that each movement doesn't look like a straight line, but rather like a line moving whatever direction you're "drawing" in). Also, a few tips:
The void mouseDragged usually works better when used in mouseMotionAdapter because from my experience it usually doesn't register the event in just mouseAdapter.
Since this is a drawing program, personally I'd set a variable for the size of your circle to be used in the future if you actually are planning to expand this into something bigger (example: g.fillOval(x, y, brushSize, brushSize)).