For loop(s) not working as intended with graphics - java

I've been trying to make a for loop that horizontally replicates vertical lines across the screen, each the same distance apart from its precedent; however, my code doesn't seem to work despite appearing to be syntactically correct. I've posted my code below, hopefully someone can identify the problem.
class HVLines
{
public static void Lines(Graphics g)
{
int k;
int x=0;
for (k = 1; k <= 50; k++)
{
g.drawLine(20+x,150,20+x,525);
for (x = 1; x <= 50; x+=20)
{
}
}
}
}

It should look like this. I can't ensure it will work since I don't know how you use it. Also, in your loops, you use x twice, but don't use k. Change one of those, or , if you don't need it, erase one of the loops.
I am prett sure this one creates a diagonal line, not horizontal.
for (k = 1; k <= 50; k++) {
for (x = 1; x <= 50; x+=20) {
// Choose one of the following
g.drawLine(20+k,150,20+x,525);
g.drawLine(20+x,150,20+k,525);
}
}
This one creates a straight line:
for (x = 1; x <= 50; x+=20) {
g.drawLine(20+x,150,20+x,525);
}

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import javax.swing.JApplet;
import javax.swing.JFrame;
public class DrawLine extends JApplet {
public void init() {
setBackground(Color.white);
setForeground(Color.white);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.gray);
for (int y = 0; y <= 300; y += 30) {
g2.draw(new Line2D.Double(0, y, 300, y));
}
}
public static void main(String s[]) {
JFrame f = new JFrame("Line");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
JApplet applet = new DrawLine();
f.getContentPane().add("Center", applet);
applet.init();
f.pack();
f.setSize(new Dimension(300, 300));
f.setVisible(true);
}
}

Related

Why arent the squares being painted?

I started a Chess Project reusing some older code to paint a map everything basically has been copy pasted. The problem is the squares dont show up? I tried fixing it for a while now and got to no solution. Here are probably the three most important methods and a zip with the whole project. Some of it is in German.
https://drive.google.com/file/d/1nnZHLB0Ycy04eMyYbEmduMwbGhVLZ2VB/view?usp=sharing
public SchachFrame() {
super();
contentPane = new JPanel();
setContentPane(contentPane);
setBounds(0, 0, window.width, window.height);
contentPane.setBackground(Color.darkGray);
contentPane.setVisible(true);
ge = new GameEnvironment(this);
ge.setBounds(window.width/2 - 500, window.height/2 - 500, 1000, 1000);
ge.setVisible(true);
contentPane.add(ge);
Thread gameEnvironment = new Thread(ge);
gameEnvironment.start();
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void createMap(int width, int length, GameEnvironment ge) {
map = new Spielfeld[length][width];
Spielfeld.width = 1000/width;
Spielfeld.height = 1000/length;
for(int i = 0; i < length; i++) {
for(int j = 0; j < width; j++) {
this.map[i][j] = new Spielfeld(j, i, null);
this.map[i][j].setBounds(ge.getX() + j * Spielfeld.width, ge.getY() + i * Spielfeld.height, Spielfeld.width, Spielfeld.height);
this.map[i][j].setVisible(true);
ge.add(this.map[i][j]);
}
}
}
public void paintComponent(Graphics g) {
if((this.px + this.py) % 2 == 0) {
g.setColor(Color.blue);
} else {
g.setColor(Color.cyan);
}
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
repaint();
}
Do not call repaint() in paintComponent. Otherwise you will never exit the EDT and lock up your code. And the first statement in paintComponent(Graphics g) should be super.paintComponent(g);
Updated to include an example
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawSquareComponent extends JPanel {
static int WIDTH = 600;
static int HEIGHT = 600;
JFrame frame = new JFrame();
public static void main(String[] args) {
new DrawSquareComponent().start();
}
public void start() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
setBackground(Color.white);
MyComponent my =new MyComponent();
add(my); // add my component to panel
Random r = new Random();
for (int i = 0; i < 20; i++) {
int size = r.nextInt(50)+50;
int x = r.nextInt(WIDTH-size)+1;
int y = r.nextInt(HEIGHT-size)+1;
my.setBounds(x,y,size,size);
frame.repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
}
}
}
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
}
}
class MyComponent extends JPanel {
#Override
public void paintComponent(Graphics g) {
Graphics gg = g.create();
super.paintComponent(gg);
// location relative to parent's.
// used to check location in parent's coordinate space.
Point p = getLocation();
if ((p.x + p.y) % 2 == 0) {
gg.setColor(Color.blue);
} else {
gg.setColor(Color.cyan);
}
// paint this component so location is always 0,0.
// all you're doing is painting this squares background
gg.fillRect(0,0, this.getWidth(), this.getHeight());
gg.dispose();
}
}

How to draw objects from an ArrayList in Java

Okay, so I'm trying to make a program that draws a bunch of rectangles that move around the screen randomly. I have a Dot class where each dot holds its x and y values, and in my paint class I randomly change the x and y values and then repaint(). What I have right now doesn't load any thing other than a blank JFrame. I suspect that I'm drawing each dot wrong. The following is my code:
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Movement extends JFrame {
public ArrayList<Dot> dots = new ArrayList<Dot>();
Random rn = new Random();
DrawPanel drawPanel = new DrawPanel();
public Movement() {
for(int i = 0; i < 100; i ++) {
Dot dot = new Dot(5, 5);
dots.add(dot);
}
ActionListener listener = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
for(int i = 0; i < dots.size();i++) {
dots.get(i).setX(dots.get(i).getX() + rn.nextInt(20)-10);
dots.get(i).setY(dots.get(i).getY() + rn.nextInt(20)-10);
}
drawPanel.repaint();
}
};
Timer timer = new Timer(100, listener);
timer.start();
add(drawPanel);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
setBounds(100, 100, 500, 500);
}
private class DrawPanel extends JPanel {
protected void paintComponent(Graphics g) {
for(int i = 0; i < dots.size(); i ++) {
g.fillRect(dots.get(i).getX(), dots.get(i).getY(), 5, 5);;
super.paintComponent(g);
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new Movement();
}
});
}
}
Dot class:
public class Dot {
private int x, y;
public Dot(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
Any and all help is appreciated.
If you call super.paintComponent(g); after you paint your own components you have wiped out your own painting. So,
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
for(int i = 0; i < dots.size(); i ++) {
g2d.fillRect(dots.get(i).x, dots.get(i).y, 5, 5);
}
}
Also,
// don't repeat type in constructor
// use built in point instead of custom class
public ArrayList<Point> dots = new ArrayList<>();
and
ActionListener listener = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
for(int i = 0; i < dots.size();i++) {
dots.get(i).x = dots.get(i).x + rn.nextInt(20)-10;
dots.get(i).y = dots.get(i).y + rn.nextInt(20)-10;
}
drawPanel.repaint();
}
};
and it probably doesn't make any difference, but
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Movement mf = new Movement();
}
});
You appear to be calling super.paintComponent after you paint dots. Not only that, you appear to be calling it inside the loop, calling it every time you paint a dot, after you paint it.
So you keep painting a dot, letting super.paintComponent paint a clear panel, then painting another dot, then undoing it again, paint another, undo... and so on.
Call super.paintComponent one time, and do it before you do your custom painting.

G2D updating with lists of coordinates

I want to make a program to simulate ants.Let's say I have 100 ants and every one of them has coordinates (2 integers). I use the Java Graphics (Graphics2D).
Now I want a class that reads a list like that:
List<List<Integer>> list = new ArrayList();
This list has for example:
[100,200],[200,100]
as coordinates in it. Now I want the class to update al the time and delete all "dots" (ants) and after that draw them new with the coordinates out of the List.
Right now this won't work.
public class FrameHandler {
Panel panel = new Panel();
public FrameHandler() {
//initialize frame
frame.repaint();
List<List<Integer>> test = new ArrayList();
List<Integer> t1 = new ArrayList();
t1.add(100);
t1.add(200);
test.add(gunther);
frame.add(panel);
panel.setList(test);
//the thread sleeps for 5 seconds
List<Integer> t2 = new ArrayList();
t2.add(100);
t2.add(100);
test.add(gunther2);
panel.removeAll();
panel.setList(olaf);
}
public void setList(List<Integer> list) {
panel.setList(list);
}
public void setSize(int width, int height) {
frame.setSize(width, height);
}
private class Panel extends JPanel {
List<List<Integer>> antList = new ArrayList();
private void doDrawing(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
for(int i = 0; i < antList.size(); i++) {
g2d.fillRect(antList.get(i).get(0), antList.get(i).get(1), 2, 2);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
public void setList(List<List<Integer>> list) {
antList = list;
}
}
}
If you have another idea how to solve the problem, maybe with an API or another method of doing graphics I would be happy to hear it.
Now I want the class to update al the time and delete all "dots" (ants) and after that draw them new with the coordinates out of the List.
This is basically how painting works in Swing, on each paint cycle, you are expected to repaint the entire state of the component from scratch. See Painting in AWT and Swing for more details.
So the question becomes, how do you update the List. While there are a number ways you might do this, using a Swing Timer might be the simplest (and generally the safest). See How to use Swing Timers for more details.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FrameHandler {
public static void main(String[] args) {
new FrameHandler();
}
public FrameHandler() {
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 TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
protected static final Random RANDOM_DELTA = new Random();
private List<List<Integer>> ants;
public TestPane() {
Random rnd = new Random();
ants = new ArrayList<>(25);
for (int index = 0; index < 10; index++) {
List<Integer> ant = new ArrayList<>(2);
// You should also have a look at the java.awt.Point class :P
ant.add(rnd.nextInt(200 - 2)); //x
ant.add(rnd.nextInt(200 - 2)); //y
ants.add(ant);
}
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (List<Integer> ant : ants) {
int xDelta = randomDelta();
int yDelta = randomDelta();
int x = ant.get(0) + xDelta;
int y = ant.get(1) + yDelta;
if (x < 0) {
x = 0;
} else if (x + 2 > getWidth()) {
x = getWidth() - 2;
}
if (y < 0) {
y = 0;
} else if (y + 2 > getHeight()) {
y = getHeight() - 2;
}
ant.set(0, x);
ant.set(1, y);
}
repaint();
}
});
timer.start();
}
protected int randomDelta() {
int delta = 0;
do {
double rnd = Math.random();
delta = rnd < 0.5d ? -1 : 1;
} while (delta == 0);
return delta;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (List<Integer> ant : ants) {
g2d.fillRect(ant.get(0), ant.get(1), 2, 2);
}
g2d.dispose();
}
}
}
This example basically generates a random delta (change in direction) for each ant's x & y coordinate. I suspect you might need to have something a little more sophisticated

Why isn't my JFrame object animating as I would expect?

I'm trying to animate a circle as per a Head First Java exercise. The original exercise calls for using an internal "MyDrawPanel" class within the "AnimatedBall" class, but I'm trying to do an external MyDrawPanel class. I have no errors, but there also is no animation. I'm assuming it has something to do with me passing values to the MyDrawPanel constructor that don't update when I run my for loop, but I'd like to know why this is.
AnimatedBall2.java:
import javax.swing.JFrame;
public class AnimatedBall2 {
JFrame frame = new JFrame();
int height = 300;
int width = 300;
int x = 70;
int y = 70;
public static void main(String[] args){
AnimatedBall2 gui = new AnimatedBall2();
gui.go();
}
public void go(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel panel = new MyDrawPanel(x, y, height, width);
frame.getContentPane().add(panel);
frame.setSize(height,width);
frame.setVisible(true);
for(int i = 0; i < 100; i++){
x++;
y++;
panel.repaint();
try{
Thread.sleep(50);
} catch(Exception ex){}
}
}
}
MyDrawPanel.java:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class MyDrawPanel extends JPanel{
int x;
int y;
int height;
int width;
public MyDrawPanel(int x1, int y1, int z1, int z2){
x = x1;
y = y1;
height = z1;
width = z2;
}
public void paintComponent(Graphics g){
g.setColor(Color.white);
g.fillRect(0, 0, height, width);
g.setColor(Color.orange);
g.fillOval(x, y, 100, 100);
}
}
Swing is a single threaded framework, that is, there is a single thread which is responsible for processing all events within the system and scheduling painting.
Anything that blocks this thread, will prevent it from processing new events or paint requests.
This is a very bad idea...
public void go(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel panel = new MyDrawPanel(x, y, height, width);
frame.getContentPane().add(panel);
frame.setSize(height,width);
frame.setVisible(true);
for(int i = 0; i < 100; i++){
x++;
y++;
panel.repaint();
try{
Thread.sleep(50);
} catch(Exception ex){}
}
}
Add could potentially lock up your application...
Take a look at Concurrency in Swing for more details. You should also have a look at Initial Threads
In this case, I would recommended using a javax.swing.Timer, see How to use Swing Timers for more details.
The main problem is, you've decarled x and y in your AnimatedBall2 class...
public class AnimatedBall2 {
//...
int x = 70;
int y = 70
And in your MyDrawPanel class...
public class MyDrawPanel extends JPanel{
int x;
int y;
But your loop is updating the values in the AnimatedBall2 class, meaning that the values in MyDrawPanel never change
You will need to add an "update" method of some kind which can tell the MyDrawPanel that it should update it's x/y values accordingly...
Which brings us to...Swing is not thread safe, all modifications or interactions with the UI should be done within the context of the Event Dispatching Thread...This is why I'd recommend using a Swing Timer, as it triggers it's notifications within the context of the EDT.
When performing custom painting, you should call super.paintComponent before performing any custom painting of your own. You should also not relay on "magic" numbers
g.fillRect(0, 0, height, width);
The size of the component can be changed by the layout manager depending on it's needs, instead, you should be using getWidth and getHeight which will tell you exactly what the size of the current component is.
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class AnimatedBall2 {
public static void main(String[] args) {
new AnimatedBall2();
}
public AnimatedBall2() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
final MyDrawPanel panel = new MyDrawPanel();
JFrame frame = new JFrame("I'm a banana");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel.update();
}
});
timer.start();
}
});
}
public class MyDrawPanel extends JPanel {
int x;
int y;
int deltaX = 0;
int deltaY = 1;
public MyDrawPanel() {
x = 150;
y = 150;
setBackground(Color.WHITE);
}
public void update() {
x += deltaX;
y += deltaY;
if (x < 0) {
x = 0;
deltaX *= 1;
} else if (x > getWidth()) {
x = getWidth();
deltaX *= 1;
}
if (y < 0) {
y = 0;
deltaY *= -1;
} else if (y > getHeight()) {
y = getHeight();
deltaY *= -1;
}
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.orange);
g.fillOval(x - 50, y - 50, 100, 100);
}
}
}
for(int i = 0; i < 100; i++){
x++;
y++;
panel.repaint();
try{
Thread.sleep(50);
} catch(Exception ex){}
}
x and y are int types, not pointers. so when you do x++ and y++. it is actually not updating the x, y values which you passed in in the constructor

Java hide images

I'm trying to make a simple program that shows that lets an image bob across the screen.
Now iv'e succeded to make an image to go form left to right but now I have like 20 images on the screen.
What I need to get is that when the next image is printed that te previous image is hidden. Also if someone could help me out with printing with a timer it would be great.
Here is my code
package imagemove;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public class imagemove extends Component {
private int x;
private int y;
BufferedImage img;
public imagemove() {
try {
img = ImageIO.read(new File("F:/JAVA/workspace/Tutorials/src/imagemove/1.jpg"));
} catch (IOException e) {
}
}
public void paint(Graphics g) {
x = 0;
y = 50;
for (int number = 1; number <= 15; number++) {
g.drawImage(img, x, y, this);
if (x > 1000) {
x = 0;
} else {
x += 100;
}
if(y > 100) {
y -= 100;
} else {
y += 25;
}
repaint();
}
}
public static void main(String[] args) {
JFrame f = new JFrame("Boot");
f.setSize(1000,1000);
f.add(new imagemove());
f.setVisible(true);
}
}
you should put your for-loop in another method, which is called from the main method. (the draw image instruction should remain in the paint mathod obviously)
use paintComponent instead of paint
put super.paintComponent(g) as the first line in paintComponent(). and your previous images should be cleared
Edit:
extend JComponent instead of Component. Component is AWT, JComponent is Swing
It works this way; it tested it:
public class imagemove extends Component {
private int x;
private int y;
BufferedImage img;
public imagemove() {
try {
img = ImageIO.read(new File("F:/JAVA/workspace/Tutorials/src/imagemove/1.jpg"));
} catch (IOException e) {
}
x = 0;
y = 50;
}
#Override
public void paint(Graphics g) {
g.drawImage(img, x, y, this);
if (x > 1000) {
x = 0;
} else {
x += 100;
}
if(y > 100) {
y -= 100;
} else {
y += 25;
}
}
public static void main(String[] args) {
JFrame f = new JFrame("Boot");
f.setSize(1000,1000);
f.add(new imagemove());
f.setVisible(true);
for (int number = 1; number <= 15; number++) {
f.repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
}
}
}
You can't call repaint from within the paint() method.

Categories