package getcm;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class test {
public static void main( String[] args ) {
tpanel panel = new tpanel();
JFrame app = new JFrame();
app.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
app.add(panel);
app.setSize(250, 250);
app.setVisible(true);
}
}
class tpanel extends JPanel {
int st = 0;
public void paintComponent(Graphics g) {
for (int h = 0; h < 2; h++) {
System.out.println(st);
st += 1;
}
}
}
I think this result should be 0, 1 but in Eclipse, the data that printed is 0, 1 ,2 ,3.
I have a reason that variable st can not produce inside the fuction paintComponent, and I have to get result 0, 1. (getting paintComponent only one time)
Please help me to get result 0, 1.
I have no idea about why this code print 0, 1 ,2 ,3 not 0, 1.
It is happening only on frame resize.
When resizing the frame, your paintComponent is called again with the old value of variable "st".
It is because, for the class "tpanel", "st" is a global variable and until your JPanel remains open, control will not exit from the "tpanel" class.
So simply it is only printing the value of global variable which is called between different function calls of paintComponent.
Hope this will help. :-)
Because
paintComponent
get called multiple times, everytime the panel get painted
it'll print a couple of number 0,1 for the frist paint and 2,3 for the second
If you edit the code like this it will print
class tpanel extends JPanel {
int st = 0;
public void paintComponent(Graphics g) {
for (int h = 0; h < 2; h++) {
System.out.println(st);
st += 1;
}
Systen.out.println("paintComponent completed");
}
}
Output:
0
1
paintComponent completed
2
3
paintComponent completed
Related
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?
// DrawPanelTest.java
// Application to display a DrawPanel.
import javax.swing.JFrame;
public class DrawPanelTest {
public static void main( String[] args ) {
// create a panel that contians our drawing
DrawPanel panel = new DrawPanel();
// create a new frame to hold the panel
JFrame application = new JFrame();
// set the frame to exit when it is close
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
application.add( panel ); // add the panel to the frame
application.setSize( 250, 250 ); // set tje size of the frame
application.setVisible( true ); // make the frame visible
} // end main\
} // end class DrawPanelTest
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawPanel extends JPanel {
//int for whole class
private int N;
// constructor
public DrawPanel(int numLines)
{
N = numLines;
} // end constructor
// draws an numLines from the corners of the panel
public void paintComponent(Graphics g)
{
// call paintComponent to ensurethe angle displays
super.paintComponent(g);
int width = getWidth(); // total width
int height = getHeight(); // total height
// draws (N + 1) lines with equal spacing
if (N > 0) {
for (int counter = 0; counter <= N; counter++) {
g.drawLine(0, height / 2, width, counter * height / N);
}
}
}
}
having difficulty with an error and not sure what to do or how to approach the error need help thanks
Microsoft Windows [Version 10.0.17134.1006]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Users\MAC>cd desktop
C:\Users\MAC\Desktop>javac DrawPanel.java
C:\Users\MAC\Desktop>javac DrawPanelTest.java
DrawPanelTest.java:11: error: constructor DrawPanel in class DrawPanel cannot be applied to given types;
DrawPanel panel = new DrawPanel();
^
required: int
found: no arguments
reason: actual and formal argument lists differ in length
1 error
C:\Users\MAC\Desktop>
Either create a no parameter constructor or pass a parameter while calling class like below:-
public DrawPanel()
{
N = 1;// if you want to assign some default value
}
Run with parameter like below:-
javac Arguments.java
java Arguments arg0 arg1 arg2
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?
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();
}
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.