Java drawing to JPanel Graphics, using byte array, blinking white - java

So I am trying to update a JPanel using a byte array with a specified byte/color
This is a very simple version.
When I start the program it's white for half a second, then becomes the right color, and then after 1 second it's going back to being white, I tried to print out the current color, and sometimes it's changing to '0'.
What am I doing wrong?
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static Random ran = new Random();
public static byte[] buffer;
public static int num = 0;
public static JFrame frame = new JFrame();
public static JPanel panel = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
public void paint(Graphics g) {
num = 0;
byte[] current_buffer = buffer.clone();
for (int y = 0; y < panel.getHeight(); y++) {
for (int x = 0; x < panel.getWidth(); x++) {
g.setColor(new Color(current_buffer[num], current_buffer[num], current_buffer[num]));
g.fillRect(x, y, 1, 1);
num++;
}
}
}
};
public static void main(String[] args) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1200, 800);
frame.setLocationRelativeTo(null);
frame.setContentPane(panel);
frame.setResizable(false);
frame.setVisible(true);
engine.run();
}
public static boolean running = true;
public static Thread engine = new Thread() {
#Override
public void run() {
buffer = new byte[panel.getWidth() * panel.getHeight()];
for (int i = 0; i < buffer.length; i++) {
buffer[i] = (byte) 34;
}
while (running) {
panel.repaint(10L);
}
}
};
}

Not really understanding your logic:
for (int i = 0; i < buffer.length; i++) {
buffer[i] = (byte) 34;
}
You assign the same value to the buffer.
Then you create a Color object using the same value.
g.setColor(new Color(current_buffer[num], current_buffer[num], current_buffer[num]));
So every pixel will be the same Color.
And since the buffer is always built with the same values, the color won't change.
Also, why would you use
byte[] current_buffer = buffer.clone();
You are just using the values in the buffer, not updating the values in the buffer so I see no reason for the clone.
Don't use a Thread with a while loop. For animation you should be using a Swing Timer. When the Timer fires you update the values in the buffer and then invoke repaint().
When I start the program it's white for half a second, then becomes the right color, and then after 1 second it's going back to being white,
I don't see that behaviour.
it blinks a light color
it stays painted at a darker color
The above makes sense because:
Your paintCompnent() method does not invoke super.paintComponent(...) to make sure the background is cleared
The array is not initialized to any values when it is created so the default value will be 0.
After the Thread takes over the array will alway contain the same value so the same color will be painted.
What do you expect it to do?

Related

How to draw multiple squares in a specific pattern in Java?

I am trying to draw 8 red squares in a specific pattern in java.
And I am expecting an output like this:
Alteration.java
And this is what I have tried so far:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Alteration {
private int xGrid;
private int yGrid;
public static void main(String[] args) {
Alteration a = new Alteration();
a.display();
}
public void display() {
JFrame frame = new JFrame("Alteration");
Background bg = new Background();
frame.setSize(400, 200);
frame.getContentPane().add(bg);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
for (int i = 0; i < 2; i++) {
for (int s = 0; s < 4; s++) {
bg.repaint();
xGrid += 50;
yGrid += 50;
}
yGrid = 0;
}
}
class Background extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.RED);
g.fillRect(xGrid, yGrid, 50, 50);
}
}
}
However, when I compile the code and run it, I only see one red square at the position of (400, 0)
That was not what I expected to output and I dont know why. I've done plenty of research and I still cannot find the correct answer to my problem, can anyone help?
EDIT: I added a code in the paintComponent method.
public void paintComponent(Graphics g) {
g.setColor(Color.RED);
g.fillRect(xGrid, yGrid, 50, 50);
System.out.println(xGrid+" "+yGrid);
}
Output (in the command prompt): 400 0
The double for loop runs 8 loops in total.
so bg.repaint() is called 8 times.
However the command prompt prints only 1 line.
I'm confused by this, why does the command prompt only print 1 line despite the fact that the paintComponent method was called 8 times?

Why isn't JFrame displaying the entire image?

Recently I have been experimenting with java graphics and decided to make a program that can print a Collage of images. The constructor for this program takes in an array of Images and the width that each image will be displayed at.
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public class CollageTest extends JComponent
{
private Image [][] board; //Holds images within it.
private int pixel;//width of image.
public CollageTest(Image x[][], int pixel)
{
board = x;
this.pixel = pixel;
}
public int getPixel()
{
return pixel;
}
public void paint(Graphics g)
{
for (int i = 0; i < board.length; i++)
{
for (int j = 0; j < board[0].length; j++)
{
g.drawImage(board[i][j], (i * pixel) , (j * pixel), pixel, pixel, null);
}
}
}
public static void main(String args[])
{
BufferedImage[][] images = new BufferedImage[20][20];
BufferedImage img = null;
try {
img = ImageIO.read(new File("gorge3.jpg"));
} catch (IOException e) {
}
for (int i = 0; i < images.length; i++)
{
for (int j = 0; j < images[0].length; j++)
{
images[i][j] = img;
}
}
CollageTest test = new CollageTest(images, 20);
JFrame frame = new JFrame("MyCollage");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(test);
frame.setSize(test.getPixel() * images.length,test.getPixel() * images[0].length);
frame.setVisible(true);
test.repaint();
}
}
To test the I initialized a CollageTest using an 20 x 20 array filled entirely with this Image.
When I ran the program originally I used The following to set the size of the JFrame's window:
frame.setSize(test.getPixel() * images.length,test.getPixel() * images[0].length);
Unfortunately the JFrame did display part of the image. The JFrame window did not go low enough down to display all of the window.
To double double check that my math wasn't off, I tested using the following line in replacement:
frame.setSize(400, 400);//Math 20 images * 20 pixels = 400 pixels
The same problem occured.
It was not until I used the following line that the entire image was displayed:
frame.setSize(400, 437);
So my question is, why is my JFrame misbehaving and is their a better way to fix it?
The problem lies in here:
frame.setSize(test.getPixel() * images.length,test.getPixel() * images[0].length);
You are manually setting the frame size according to the image size. However the frame size takes the title-bar and possibly borders into considerations. If the title-bar takes up 37 pixels, it leaves you 37 pixels lesser for the image.
What I would do is:
Add the image to a JPanel. You may set the size of the panel according to the image. pack() your JFrame after adding the panel containing your image so that it will determine the preferred size of the JFrame by itself.

Moving Black and White Balls

I'm kind of new to Java and OO programming, here is the code of moving black and white balls problem. First let me explain the program that I want in the output: there are n balls(for example 6 balls) on the window, one black and one white, in each move we only are allowed to move just one ball and this movement should be shown on the screen, and at the end all the white balls should be on one side and all the black balls should be on the other side. Here is an example of six balls:
I have written the program and it seems working good and no flaws in the algorithm, but my problem is that I can't show animation of the movement of the balls, in each movement one ball should swap its place with its neighbor ball, but all I get is the final arrangements of the balls. Please someone help me with the animation part. I would be really thankful for that.
code:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
public class DrawPanel extends JPanel implements ActionListener
{
Timer myTimer = new Timer(2000, this);
public static final int NUMBER_OF_CIRCLES = 10; //number of circles which are to moved
static int[] circles = new int[NUMBER_OF_CIRCLES];
public void paintComponent(Graphics g)
{
int x = 0; //start point of circles;
int length = 40; //diagonal of the circles
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D circle;
//painting n circles based on the array
for(int index = 0; index<10; index++)
{
if(circles[index] == 0){ //if the element of the arrayy is 0 then draw a void circle
circle = new Ellipse2D.Double(x, 120, length, length);
g2.draw(circle);
}
else if(circles[index] == 1){ //if the element of the array is 1 them draw a filled circle
circle = new Ellipse2D.Double(x, 120, length, length);
g2.fill(circle);
}
x += 45; //increas start pont of the next circle 45 pixles
}
myTimer.start();
}
public void actionPerformed(ActionEvent e)
{
int tmp; //template for swaping elements
int condition; //condition of the forS
arrayFill(circles); //fills the array based on the writen method, one 1 and one 0 like: 0 1 0 1 0 1 0 1
//here is the part which works good, it changes palces of an elemen at time.
//at the end of this part the array would be like: 1 1 1 1 0 0 0 0
if(NUMBER_OF_CIRCLES % 2 == 0)
condition = circles.length/2 -1;
else
condition = circles.length/2;
for(int i = circles.length-1, k = 1; i>condition; i--, k++)
{
for(int j = i - k; j<i ;j++)
{
tmp = circles[j];
circles[j] = circles[j+1];
circles[j+1] = tmp;
//if we call arrayPrint method it will print the array but I don't know why repaint is not working here
//arrayPrint(circles);
repaint();
}
}
}
//fills the array, one 1 and one 0. Example: 0 1 0 1 0 1 0 1 0 1
public static void arrayFill(int[] array)
{
for(int i = 0; i<array.length; i++)
{
if( i%2 == 0)
array[i] = 0;
else
array[i] = 1;
}
}
}//end of class
And the main Class:
import javax.swing.JFrame;
public class BlackAndWhiteBallsMoving {
public static void main(String[] args)
{
DrawPanel myPanel = new DrawPanel();
JFrame myFrame = new JFrame();
myFrame.add(myPanel);
myFrame.setSize(600, 500);
myFrame.setTitle("Black And White Balls Moving");
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}//end of class
The events triggered by the Timer are performed on the same event thread as the repaints. Calling repaint does not actively perform a paint event, rather it queues one for later. When you call your repaints from within the timer event, they will only get executed once the timer event is completed.
What you need to do is refactor your loop so that only a single swap is performed each time the timer triggers. I've done this for you as an example:
public class DrawPanel extends JPanel implements ActionListener {
public static final int NUMBER_OF_CIRCLES = 10;
Timer myTimer = new Timer(500, this);
int[] circles = new int[NUMBER_OF_CIRCLES];
public DrawPanel() {
arrayFill(circles);
if(NUMBER_OF_CIRCLES % 2 == 0) {
condition = circles.length/2 -1;
} else {
condition = circles.length/2;
}
i = circles.length - 1;
k = 1;
myTimer.start();
}
int i, j, k;
int condition;
boolean outer = true;
#Override
public void actionPerformed(ActionEvent e) {
if(outer) {
if(i > condition) {
j = i - k; // set j
outer = false; // and move to the inner loop swap
} else {
myTimer.stop(); // the outer loop is done so stop the timer
}
}
if(!outer) {
int tmp = circles[j];
circles[j] = circles[j+1];
circles[j+1] = tmp;
repaint();
j++;
if(j >= i) {
i--;
k++;
outer = true; // move to the outer condition
} // next time the timer triggers
}
}
#Override
protected void paintComponent(Graphics g) {
int x = 0;
int length = 40;
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D circle;
for(int index = 0; index<10; index++) {
if(circles[index] == 0){
circle = new Ellipse2D.Double(x, 120, length, length);
g2.draw(circle);
} else if(circles[index] == 1){
circle = new Ellipse2D.Double(x, 120, length, length);
g2.fill(circle);
}
x += 45;
}
//myTimer.start();
}
public static void arrayFill(int[] array) {
for(int i = 0; i<array.length; i++) {
if( i%2 == 0) {
array[i] = 0;
} else {
array[i] = 1;
}
}
}
}
(I'm sure it could be factored another way.)
Also:
I added #Override annotations which you should use. Doing so will warn you when you make certain mistakes. (Like misspelling a method name or incorrectly declaring its signature.)
I moved circles to an instance variable because I don't see a reason it should be static. It is part of the state of the DrawPanel instance.
I created a constructor which initializes variables such as circles.
paintComponent is a protected method and it should remain so unless there is a reason to promote it to public.
(I removed your comments and changed the bracing style just to condense the code for my answer.)
As a side note, you should read the tutorial Initial Threads. You are not creating your GUI on the Swing event thread. Basically you need to wrap your code in main inside a call to invokeLater:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// create and show your GUI
}
});
}
The basic problem is in your actionPerformed method. Your two for loops are rearranging the array to its final arrangement very quickly. Each loop iteration will take a matter of nanoseconds to milliseconds to complete (it depends on how the repaint() method works). The entire process is finished in less than 50 milliseconds or so. That's too fast for your eyes to keep up.
Basically, the repaint() method is working, but it's working too fast for human eyes to keep up.
If you break up the for loops into something that does one step of the algorithm each time it's called, you can trigger that from a timer and see the animation at a human-detectable speed.
add a paint thread. it should always call repaint() like,
new Thread(){ // this can be started on main or constructor of object
public void run(){
while(true){
repaint();
try {
Thread.sleep(50);
} catch(Exception e){ } 
}
  }
}.start();
and then, on action performed, mark moving objects like movingObjects, keep a animate_x = 0 and keep a boolean variable like existAnimation
then on paintComponent, increase animate_x
animate_x = animate_x + 1;
if (animate_x >= MAX_WIDTH_OF_ANIMATION){
existAnimation = false;
}
and use this existAnimation, animate_x and movingObjects
like,
public void paintComponent(Graphics g)
{
int x = 0; //start point of circles;
int length = 40; //diagonal of the circles
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D circle;
//painting n circles based on the array
for(int index = 0; index<10; index++)
{
int paint_x = x;
if (movingObjects.has(circles[index])){
paint_x += animate_x;
}
if(circles[index] == 0){ //if the element of the arrayy is 0 then draw a void circle
circle = new Ellipse2D.Double(paint_x, 120, length, length);
g2.draw(circle);
}
else if(circles[index] == 1){ //if the element of the array is 1 them draw a filled circle
circle = new Ellipse2D.Double(paint_x, 120, length, length);
g2.fill(circle);
}
x += 45; //increas start pont of the next circle 45 pixles
}
myTimer.start();
}

Java - I want to draw multiple 2D Ellipses using a timer, but it's not working

Already tried searching, but couldn't find anything.
I'm trying to draw multiple 2D Ellipses using an array, and a for loop, I'm repainting the frame every second. The thing is, I only get one Ellipse everytime I repaint, can somebody tell me what's wrong with me code, please?
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class MovingDot extends JFrame{
static int posX = (int)Math.round(Math.random()*780);
static int posY = (int)Math.round(Math.random()*780);
static int width = (int)Math.round(Math.random()*780);
static int height = (int)Math.round(Math.random()*780);
static int dots = 0;
public static Timer timer;
public MovingDot(){
super("Moving Dot");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(800, 800);
Dot2 dot = new Dot2();
add(dot);
setVisible(true);
timer = new Timer((int)Math.round((1000)), timerAction);
timer.start();
}
private ActionListener timerAction = new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae){
posX = (int)Math.round(Math.random()*780);
posY = (int)Math.round(Math.random()*780);
width = (int)Math.round(Math.random()*780);
height = (int)Math.round(Math.random()*780);
float r = (float)Math.random();
float g = (float)Math.random();
float b = (float)Math.random();
Color col = new Color(r,g,b);
setBackground(col);
dots++;
repaint();
}
};
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run()
{
new MovingDot();
}
});
}
}
class Dot2 extends JPanel{
#Override
public void paintComponent(Graphics c2){
int x = MovingDot.posX;
int y = MovingDot.posY;
int w = MovingDot.width;
int h = MovingDot.height;
float r,g,b;
Color col;
Graphics2D c = (Graphics2D) c2;
c.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Ellipse2D.Float[] e = new Ellipse2D.Float[10];
for (int i = 0; i < 10; i++) {
if (i == 0)
r = (float)Math.random();
else
r = 0.163F;
g = (float)Math.random();
b = (float)Math.random();
col = new Color(r,g,b);
c.setColor(col);
e[i] = new Ellipse2D.Float(x, y, w, h);
c.fill(e[i]);
}
}
}
Found out what was wrong myself, I had to make x, y, w and h random in my paintComponent. And no, this is not for a school assignment, I'm trying to teach myself Java using a book.
And about making my methods static, I was planning on using them in my JPanel, but I realised I don't need them, so I'm going to delete them. Thanks for your advice!
You shouldn't be creating your Ellipse array inside of paintComponent, makes no sense.
Instead create the array in the class.
Your JPanel's paintComponent method should not have any program logic in it. It should only have code that paints the ellipses. That is, it should iterate through your array with a for loop, and if the item in the array is not null draw it.
You'd be even better off using an ArrayList<Ellipse2D> and not an array. That way you wouldn't have to check for nulls.
In the Timer's ActionListener, if your counter is < 10, you'd add an Ellipse2D to the array and call repaint.
If the counter >= 10 you'd stop the Timer
Also, none of your static variables should be static, and having them as static suggests that the program design is off. If this is for a school assignment, that could lead to deduction of your grade.

Animation supposed to change according to a variable in another java file

So basically I have my main code (TuringSimLS.java) and my animation code (Animation.java)
Animation.java creates a number of boxes (dependent on the length of an array in my TuringSimLS.java. The length of this array does not change). Now there is a variable in my TuringSimLS.java which has a variable pointer (this one changes). This pointer decides which box in my animation is in the middle. For example if there are 7 boxes, and the pointer is 6, the box in the middle will have one box to it's right and five to it's left (making it the 6th of boxes). When the pointer changes all the boxes move until the required box is in the middle. The problem is that my method (which changes the value of pointer) finishes running and then my animation starts. So no animation ends up happening (as the pointer's value returns to the value it initially was in the beginning). I need my animation to happen as soon as the variable pointer's value changes.
Part of my main code (TuringSimLS.java)
public static int[] POINTER = new int[1]; // My global variable. How i tell my Animation.java
// What the current value of pointer is
static String[] processTape(String[][] Quints, String[] Tape, int TapeInitial) {
int pointer = TapeInitial;
POINTER[0] = pointer;
...
...
Animation.main(Quints, Tape, TapeInitial); // <- animation started here
while (!currentDir.equals("H")) { // <- IMPORTANT WHILE LOOP as mentioned below
for (String[] Quint : Quints) {
if (Quint[0].equals(currentState) && Quint[1].equals(Tape[pointer])) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(TuringSimLS.class.getName()).log(Level.SEVERE, null, ex);
}
Tape[pointer] = Quint[3];
...
...
if (currentDir.equals("R")) {pointer += 1;} // pointer changes here
if (currentDir.equals("L")) {pointer -= 1;}
symbolFound = true;
startFound = true;
POINTER[0] = pointer;
//Here is where i want the animation to start as in
//moving of the already drawn boxes
//System.out.println(POINTER[0]);
break;
}
}
}
return Tape;
}
Here is my Animition.java:
package turingsimls;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.*; // Imports ActionEvent, ActionListener
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Animation extends JPanel implements ActionListener
{
Timer tm = new Timer(5, this);
int x = 0;
int xtri = 300;
int ytri = 30;
public static int[] C = new int[1];
public static int[] Number = new int[1];
public static int[] POINTER2 = new int[1];
public void paintComponent(Graphics g) {
super.paintComponent(g); //9
g.setColor(Color.WHITE);
for (int i = 0; i < Number[0]; i++)
g.fillRect((280 + (40 + 20)*i) + C[0], 50, 40, 30);
int xpoly[] = {xtri , xtri + 10, xtri - 10 };
int ypoly[] = {ytri, ytri - 10, ytri - 10};
g.drawPolygon(xpoly, ypoly, xpoly.length);
tm.start();
}
public void actionPerformed (ActionEvent e) {
//Here C changes according to the pointer
//Which in turn changes the XPos of the rectangles
if (!(C[0] == -60 * TuringSimLS.POINTER[0])){
if ((C[0] < -60 * TuringSimLS.POINTER[0]))
C[0] += 10;
if ((C[0] > -60 * TuringSimLS.POINTER[0]))
C[0] -= 10;
}
System.out.println(C[0]);
System.out.println(TuringSimLS.POINTER[0]);
repaint();
}
public static void main(String[][] Quints, String[] Tape, int TapeInitial) {
Animation t = new Animation(); //2
JFrame jf = new JFrame();
jf.setTitle("Animation");
jf.setSize(600, 400);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(t);
Number[0] = Tape.length - 1;
C[0] = -60 * TapeInitial;
}
}
processTape() starts the animation and produces the first rectangles correctly. The problem is the entire "Important while loop" runs before actionPerformed() runs for the second time. So the animation doesnt process the changes of pointer.

Categories