I'm trying to figure out the behavior of my program, and that is my best theory as to why its doing what its doing. I was hoping this would use the rand variable to decide which shape to paint, but instead it seems the paintComponent method is being invoked many times in-between timer firings, causing many shapes to be painted and I'm trying to understand why.
This is the code:
public class TestPane extends JPanel {
private int yPos0;
private int yPos1;
private int boundary0=750;
private ActionEvent ae = null;
private Graphics g0 = null;
private int count=1;
public TestPane(Color foreground){
setForeground(foreground);
this.setBackground(Color.BLUE);
Timer timer = new Timer(3000,new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
ae = e;
yPos0 =yPos0+50;
repaint();
}
});
timer.start();
}
#Override
public void paintComponent(Graphics g){
g0 = g;
super.paintComponent(g);
createShape(yPos0);
repaint();
}
public void createShape(int ypos0){
//generate random number between 1 and 3 and assign to rand
int rand = (int)((Math.random()*3)+1);
System.out.println(rand);
if(rand==1){
Graphics2D g2d = (Graphics2D) g0.create();
g2d.setColor(Color.RED);
g2d.drawRect(0, ypos0, 200, 50);
}
if(rand==2){
Graphics2D g2d = (Graphics2D) g0.create();
g2d.setColor(Color.GREEN);
g2d.drawRect(0, ypos0, 150, 50);
g2d.drawRect(50, ypos0+50,50,50);
}
}
}
The reason that paintComponent is being called so many times is that you are calling repaint within that method which causes itself to be called ad infinitum. This is not needed as you're already calling repaint from your Timer.
Related
My rectangle code:
class Rectangle extends JPanel {
int x = 105;
int y= 100;
int width = 50;
int height = 100;
public void paint(Graphics g) {
g.drawRect (x, y, width, height);
g.setColor(Color.WHITE);
}
Rectangle r = new Rectangle();
and I have a button "rotate". When the user presses the button with the mouse, the rectangle must rotate 15 degrees.
This is my action code:
public void actionPerformed(ActionEvent e){
Object source = e.getSource();
if( source == rotate){
AffineTransform transform = new AffineTransform();
transform.rotate(Math.toRadians(15), r.getX() + r.getWidth()/2, r.getY() + height/2);
r.add(transform);
}
}
But the code doesn't work. I don't know why? What do you think?
My edited-action-code part:
public void actionPerformed(ActionEvent e){
Object source = e.getSource();
if( source == rotate){
Paint p = new Paint();
panel1.add(r);
repaint();
}
}
class Paint extends JPanel {
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.WHITE);
g2d.translate(r.getX()+(r.WIDTH/2), r.getY()+(r.HEIGHT/2));
g2d.rotate(Math.toRadians(15));
r.equals(g2d);
repaint();
}
}
Custom painting is done by overriding the paintComponent() method, not paint(). Don't forget the super.paintComponent() at the start.
The paintComponent() method is where the painting is done so that is were you need the rotation code. So you could set a variable to indicate if you need to do the rotation or not. So all the ActionListener does is set the variable and then invoke repaint().
Or, I've never tried applying a rotation directly to the Rectangle (I've always applied it to the Graphics object in the painting method). Maybe you just need to invoke repaint() on the panel in your ActionListener. The panel won't know you've changed the Rectangle, so you need to tell it to repaint itself.
I'm trying to figure out if the repaint method does something that we can't do ourselves.
I mean,how are these two versions different?
public class Component extends JComponent {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle r = new Rectangle(0,0,20,10);
g2.draw(r);
r.translate(5,5);
g2.draw(r);
}
}
and
public class Component extends JComponent {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle r = new Rectangle(0,0,20,10);
g2.draw(r);
r.translate(5,5);
repaint();
}
}
The 2nd version can result in a very risky and poor animation since it can result in repaints being called repeatedly, and is something that should never be done. If you need simple animation in a Swing GUI, use a Swing Timer to drive the animation.
i.e.,
public class MyComponent extends JComponent {
private Rectangle r = new Rectangle(0,0,20,10);
public MyComponent() {
int timerDelay = 100;
new Timer(timerDelay, new ActionListener(){
public void actionPerformed(ActionEvent e) {
r.translate(5, 5);
repaint();
}
}).start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.draw(r);
}
}
The use of repaint() is to suggest to the JVM that the component needs to be painted, but it should never be called in a semi-recursive fashion within the paint or paintComponent method. An example of its use can be seen above. Note that you don't want to call the painting methods -- paint or paintComponent directly yourselves except under very unusual circumstances.
Also avoid calling a class Componenet since that name clashes with a key core Java class.
Like in a topic, I've readed the most of all solutions for repaint() but for my code their are not working. I'm a begginer so forgive me a mess in my code..
class View.java
public class View extends JFrame{
public void make(){
setSize(640,480);
setVisible(true);
setTitle("Parking");
}
double x_ = MyFrame.x;
double y_ = MyFrame.y;
double odchylenie_ = MyFrame.odchylenie;
int szerokosc = 50;
int wysokosc = 30;
public void paint(Graphics g){
Rectangle2D rect = new Rectangle2D.Double(-szerokosc / 2., -wysokosc / 2., szerokosc, wysokosc);
AffineTransform transform = new AffineTransform();
transform.translate(x_, y_);
transform.rotate(Math.toRadians(odchylenie_));
Shape rotatedRect = transform.createTransformedShape(rect);
Graphics2D g2 = (Graphics2D)g;
g2.draw(rotatedRect);
}
All I want to do to re-paint this rotatedRect with new values of x,y and odchylenie (sorry for polish variable names).
I'm calculating new variable values and using Jbutton to redraw it.
Here is my MyFrame.class
public class MyFrame extends javax.swing.JFrame {
static double x,y,odchylenie,kat;
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
View v = new View();
v.make();
Fuzzy f = new Fuzzy();
kat = f.wyjscie(x, odchylenie);
jLabel5.setText("Kąt: " + Double.toString(kat));
odchylenie = Fuzzy.wyliczOdchylenie(odchylenie,kat);
jLabel8.setText("Nowe odchylenie: " + Double.toString(odchylenie));
x = Fuzzy.wyliczX(x, 10, kat,odchylenie);
jLabel6.setText("Nowy x: " + Double.toString(x));
y = Fuzzy.wyliczY(y,x, 10, kat,odchylenie);
jLabel7.setText("Nowy y: " + Double.toString(y));
v.repaint(); //Not works
}
Instead of doing repaint(), the new window appears, and old one stays...
I have tried to declare View v outside the button function body, but it not worked too(nothing is painting).
Whenever you override one of the paint() methods, you need to make a call to the super's method:
public void paint(Graphics g) {
super.paint(g);
// your code goes here
}
Further, you should really be using paintComponent(), not paint().
public void paintComponent(Graphics g) {
super.paintComponent(g);
// your code goes here
}
Instead of using paint, use paintComponent:
public void paintComponent(Graphics g){
super.paintComponent(g);
Rectangle2D rect = new Rectangle2D.Double(-szerokosc / 2., -wysokosc / 2., szerokosc, wysokosc);
AffineTransform transform = new AffineTransform();
transform.translate(x_, y_);
transform.rotate(Math.toRadians(odchylenie_));
Shape rotatedRect = transform.createTransformedShape(rect);
Graphics2D g2 = (Graphics2D)g;
g2.draw(rotatedRect);
}
i have this code:
public class Intersect extends JFrame {
private boolean collision = false;
public Intersect() {
add(new JPanel() {
#Override
protected void paintComponent(Graphics g) {
Shape oval = new Ellipse2D.Double(50, 50, 200, 200);
Shape rect = new Rectangle2D.Double(200, 200, 200, 200);
Graphics2D g2 = (Graphics2D) g;
g2.draw(oval);
g2.draw(rect);
if(oval.intersects(rect.getBounds())) {
System.out.println("contact");
collision = true;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
});
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
public static void main(String[] args) {
Intersect i = new Intersect();
i.setVisible(true);
if(i.collision == true)
System.out.println("boom");
else System.out.println("no boom");
}
}
result in console:"
no boom
contact
contact
contact"
program keep false value in variable collision for all the time, but why it print "contact" if it dont change variable collision to true? (in condition if(oval.intersects(rect.getBounds())))
Painting happens asynchronously in response to requests from the operating system to paint the window. It doesn't happen immediately when you call setVisible(true);.
So it does set the collision variable to true. It just hasn't happened yet at the time the code in main runs. This is why "contact" is printed after "no boom".
Edit: The way I'd suggest fixing it is to separate the collision logic from the painting code. E.g., declare the Shapes as fields on the frame, so they are available outside the paint method:
class Intersect extends JFrame {
private Shape oval = new Ellipse2D.Double(50, 50, 200, 200);
private Shape rect = new Rectangle2D.Double(200, 200, 200, 200);
The panel's painting method becomes simply:
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.draw(oval);
g2.draw(rect);
}
Then remove the collision variable and make it a method so you can call it at any time:
boolean collision() {
return oval.intersects(rect.getBounds());
}
public static void main(String[] args) {
Intersect i = new Intersect();
i.setVisible(true);
if (i.collision())
System.out.println("boom");
else System.out.println("no boom");
}
Note: There is another (potential) problem with this code. All GUI-related activity is supposed to happen on a dedicated thread, the event dispatch thread. The main method should switch to the event dispatch thread before creating the GUI. To do this, change the beginning of main to this:
public static void main(final String[] args) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
main(args);
}
});
return;
}
Intersect i = new Intersect();
...
That will re-call main on the GUI thread.
here is first class
// extending class from JPanel
public class MyPanel extends JPanel {
// variables used to draw oval at different locations
int mX = 200;
int mY = 0;
// overriding paintComponent method
public void paintComponent(Graphics g) {
// erasing behaviour – this will clear all the
// previous painting
super.paintComponent(g);
// Down casting Graphics object to Graphics2D
Graphics2D g2 = (Graphics2D) g;
// changing the color to blue
g2.setColor(Color.blue);
// drawing filled oval with blue color
// using instance variables
g2.fillOval(mX, mY, 40, 40);
now i want to use the method g2.setColot(Colot.blue) in the following where the question marks are.
// event handler method
public void actionPerformed(ActionEvent ae) {
// if ball reached to maximum width of frame minus 40 since diameter of ball is 40 then change the X-direction of ball
if (f.getWidth() - 40 == p.mX) {
x = -5;
????? set the color as red ????????
}
Add a Color member to your class. When you want to change the color, change to value of the member and call repaint():
public class MyPanel extends JPanel {
int mX = 200;
int mY = 0;
Color myColor = Color.blue; //Default color is blue,
//but make it whatever you want
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(myColor);
g2.fillOval(mX, mY, 40, 40);
}
public void actionPerformed(ActionEvent ae) {
if (f.getWidth() - 40 == p.mX) {
x = -5;
myColor = Color.red;
repaint();
}
}
If I understand what you need is to make Graphics2D g2 a class attribute. This way all the methods in your class can access that "global" variable:
public class MyPanel extends JPanel {
Graphics2D g2;
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2 = (Graphics2D) g;
...
}
public void actionPerformed(ActionEvent ae) {
g2.setColor(...);
}
}