简体   繁体   中英

Can't repaint JPanel from another class

Following my previous Question about Drawing rectangle within the loop?

Now I want to draw the Rectangle from another class, inside the for-loop. Here is the class of the loop:

public class FaceDetect extends SwingWorker {
    
    IntegralCalc3 ic3 = new IntegralCalc3();
    MainFrame mf = new MainFrame();
  
    Rectangle R;

       protected FaceDetect doInBackground() throws Exception {
       //Initial width and height is 60, 60
       outerloop:
       for(int w = 50; w <= ic3.integral.length && w <= ic3.integral[0].length; w = (int) Math.round(w*1.2)  ) {  
            int h = w;

            for(int x = 0; x <= ic3.integral.length-w; x+=5 ) { 
            for(int y = 0; y <= ic3.integral[0].length-w; y+=5 ) {
            
             R = new Rectangle (x, y, w, h);
             mf.lm.add(R);
             mf.lm.revalidate();
             mf.lm.repaint();
            } 
            }             
        } 
        return null;
    }

}

Here is my rectangle class:

public class Rect extends JComponent {
    public int x;
    public int y;
    public int w;
    public int h;
    
    public Rect (int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        repaint();
    }

    @Override
    public void paintComponent(Graphics g)  {
        Graphics2D g2 = (Graphics2D) g;
        super.paintComponent(g);
        g2.setColor(Color.green);
        g2.drawRect(x+15, y+15, w, h);
    }
}

And finally here is my button inside the JFrame class:

public class MainFrame extends JFrame {
    Rect R = new Rect(15, 15, 50, 50);
    JPanel lm = new JPanel();
    LayoutManager lay = new OverlayLayout(lm);
    JButton animate = new JButton("animate");

    public MainFrame () {
        setSize(1200, 700);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        lm.setLayout(lay);
        lm.add(R);
}
        animate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) { 
               try {   
               new FaceDetect().execute();
                } catch (Exception ex) {
                    Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
                }
               }   
      });

    public static void main(String[] args) {
            EventQueue.invokeLater(() -> new MainFrame());
        }
    }

But nothing happened when I click the animate button. Where is the flaw of my codes?

Where is the flaw of my codes?

You create an instance of the MainFrame in your main() method:

public static void main(String[] args) {
        EventQueue.invokeLater(() -> new MainFrame());
    }
}

Then you create another instance in your FaceDetect class:

public class FaceDetect extends SwingWorker {
    IntegralCalc3 ic3 = new IntegralCalc3();
    MainFrame mf = new MainFrame();

You can't just keep creating new instances of an object. You need to pass a reference of the MainFrame class to the FaceDetect class.

However I would suggest that is still not the proper design since your SwingWorker logic is incorrect. You are using the SwingWorker incorrectly! The doInBackground logic should NOT update the state of the Swing component!

Following my previous question...

The suggestion was to use a Swing Timer for animation. That is how your code should be designed. All the Swing Timer does is generate an event at a regular interval. You then respond to the event.

So in your case you would want to create a move() method in your Rect class, which would update the x/y location and repaint() the component. The logic for the Timer would be to simply invoke the move() method.

See: How to make JScrollPane (In BorderLayout, containing JPanel) smoothly autoscroll for a basic example of using a Swing Timer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM