0

I have a question about Swing and the paintComponent method. I have three classes. One of them is the class Clock. When I want to draw one clock there is no problem, but if i try to draw two clocks only the second clock shows up.

Does paint only draw the last object? I created to Instances of the class clock but it doesnt work? How can I solve the problem so both clocks will be shown?

My Code:

import java.awt.Dimension;
import java.awt.Toolkit;

import javax.swing.JFrame;


public class Hour 
{
    JFrame frm;
    Dimension dim;

    // Clock(x, y, angle, length)
    Clock u1 = new Clock(50, 50, 1, 50);
    Clock u2 = new Clock(100, 100, 15, 15);

    public Hour()
    {
        dim = Toolkit.getDefaultToolkit().getScreenSize();

        frm = new JFrame();
        frm.setSize(200, 200);
        frm.setLocation(dim.width/2 - frm.getSize().width/2, dim.height/2 - frm.getSize().height/2);
        frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frm.setVisible(true);

        frm.add(u1);
        frm.add(u2);
    }

    public static void main(String[] args)
    {
        new Hour();
    }
}

Clock-class:

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JPanel;


public class Clock extends JPanel
{
    Calc c;

    private long clockspd = 50; 

    private int x = 50 ,y = 50;
    private int nx = 50 ,ny = 50;

    double angle = 0, length = 0;

    public Clock(int px, int py, double pangle, double plength)
    {
        x = px;
        y = py;
        angle = pangle;
        length = plength;

        Thread thread = new Thread()
        {
            public void run()
            {
                action();
            }
        };
        thread.start();
    }

    public void action()
    {
        for(int i=0; i<360/angle+1; i++)
        {
             c = new Calc(this, angle*i, length);
            nx = (int)c.getBx();
            ny = (int)c.getBy();
            try {
                Thread.sleep(clockspd);
            } 
            catch(InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
            repaint();
        }
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D)g;
        g2.setStroke(new BasicStroke(2));

        g2.drawLine(x, y, x+nx, y+ny); //0, -30
        g2.drawArc(x-(int)length, y-(int)length, (int)length*2, (int)length*2, 0, 360);
    }

    public int getXCoor()
    {
        return x;
    }

    public int getYCoor()
    {
        return y;
    }
}

Calc:

public class Calc 
{
    double bx = 0;
    double by = 0;

    public Calc(Clock u, double angle, double length)
    {
        if(angle <= 180)
        {
            by = -length * Math.cos(Math.toRadians(angle));
            bx = Math.sqrt(Math.pow(length, 2)-Math.pow(by, 2));
        }
        if(angle > 180)
        {
            by = -length * Math.cos(Math.toRadians(angle));
            bx = -Math.sqrt(Math.pow(length, 2)-Math.pow(by, 2));
        }
    }

    public double getBx()
    {
        return bx;
    }

    public double getBy()
    {
         return by;
    }
}

Hope someone can help me

Edit: I tried using different Layouts but everytime I use a Layoutmanager there is nothing on the frame, so paint doesnt seem to work with Layoutmanager.

H2O2
  • 34
  • 6
  • 1) N.B. Have a close look at the duplicate to see why only one clock paints. More generally, painting multiple objects in a single `JPanel` works. Just keep an `List` where `Clock` extends nothing and simply knows how/where to paint itself when required. In the `paintComponent(Graphics)` method of the `JPanel` that is used to paint the clocks, iterate the array list and paint each one. 2) `frm.setLocation(dim.width/2 - frm.getSize().width/2, dim.height/2 - frm.getSize().height/2);` easier, `frm.setLocationRelativeTo(null;)` but it should be called after the frame size is set. .. – Andrew Thompson Jul 22 '16 at 18:42
  • .. 3) But better then (2) is probably `frm.setLocatioByPlatform(true);` which is where the OS would typically stack the next opened app. 4) `frm.setVisible(true); frm.add(u1); frm.add(u2);` should be `frm.add(u1); frm.add(u2); frm.setVisible(true);` since setting the frame visible, should be last. 5) `Thread.sleep(clockspd);` not the way to do animation in Swing. Instead use a Swing based `Timer` to trigger the `action()` method. – Andrew Thompson Jul 22 '16 at 18:47
  • How can I make clock extends nothing if there is a paintcomponent method? I dont get the reason why paint doesnt draw both clocks :/ thx for the advises. already changed my code in that points – H2O2 Jul 22 '16 at 19:02
  • Did you carefully read the duplicate Q&A? No custom painting there at all, yet there is only one color drawn on the GUI.. Figure our why (though I've taken pains to explain it in the answer) & you should be part of the way to solving this dilemma & possibly understanding the comments above. – Andrew Thompson Jul 22 '16 at 19:13
  • *"I tried using different Layouts but everytime I use a Layoutmanager there is nothing on the frame, so paint doesnt seem to work with Layoutmanager."* Oh right, I forgot to mention. 6) Any custom painted component needs to return a value from `getPreferredSize()` (override the method) that is sufficient for painting the content. Then if the layout honors that size, it will appear that big. Otherwise, without components inside it, it will return a preferred size of 0x0. – Andrew Thompson Jul 22 '16 at 19:16
  • "Any custom painted component needs to return a value from getPreferredSize() (override the method) that is sufficient for painting the content." Thank you that worked. `@Override public Dimension getPreferredSize() { return new Dimension(200, 200); }` I still dont get what those numbers exactly do. Will try to find out – H2O2 Jul 22 '16 at 19:29

0 Answers0