0

I've been trying all day long to make this happen with no success. What can be going wrong?

I want 2 threads printing simultaneously in my JFrame:
Thread-1: Prints Squares
Thread-2: Prints Circles
I'am ending up with only one thread printing on the JFrame. The other get executed but don't print in the JFrame.
Look, only squares are getting printed:
enter image description here

This is my main class:

public class Main {

    public static void main(String[] args) {

        FigurePlacer circle = new FigurePlacer("circle");
        FigurePlacer square = new FigurePlacer("square");

        JFrame window = new JFrame();
        window.add(circle);
        window.add(square);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setTitle("Task");
        window.setSize(700, 700);
        window.setLocationRelativeTo(null);
        window.setVisible(true);
     }
}

This is the Threading Class:

import java.awt.Graphics;
import javax.swing.JPanel;
import java.awt.Color;
import java.util.Random;

public class FigurePlacer extends JPanel implements Runnable{

    String figure;
    final int width = 700;
    final int height = 700;
    int x_pos = 0;
    int y_pos = 0;
    int x_width = 50;
    int y_height = 50;

    public FigurePlacer(String str){
        figure = str;
        randomCoord();
        Thread th = new Thread (this);
        th.start();
    }

    private void randomCoord(){ //this ramdomize x,y coord to place a new object
        Random random = new Random();
        x_pos = random.nextInt(width);
        y_pos = random.nextInt(height);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLACK); //sets the black color in background
        g.fillRect(0, 0, 700, 700);
        System.out.println(figure);
        switch (figure){
            case "square":     
            g.setColor(Color.GREEN);
            g.fillRect(x_pos, y_pos, x_width, y_height);
            break;

            case "circle":
            g.setColor(Color.BLUE);
            g.fillOval(x_pos, y_pos, x_width, y_height);
            break;
        }
    }

    @Override
    public void run(){ //paints the objects
        while (true){
            randomCoord();
            paintImmediately(x_pos, y_pos, x_width, y_height);
            try{
                Thread.sleep (50);
            }
            catch (InterruptedException ex){}
        }
    }  

}
  • 1
    It has nothing to do with threading (although your threading is broken) and all to do with layout managers. JFrames use BorderLayout -- look that up and you'll see. Better to delete the threading and instead use a Swing timer (which uses threading *indirectly*, but in a way that is thread-safe with Swing GUI's), and to abstract the sprites from your Swing component code -- meaning the squares and circles are separate non-JPanel classes, all drawn in a single JPanel. – Hovercraft Full Of Eels Sep 18 '17 at 01:34
  • The thing is: My professor put the condition that this has to be done with threading. Two threads that prints independantly Squares and Circles. And yes, I know it can be done with other methods very EASYLY :( – Rodrigo Formighieri Sep 18 '17 at 01:38
  • The suggestion of @HovercraftFullOfEels **is** using threading. But any which way you go, create a list of shapes to be painted, then when either thread adds a shape to the list, `repaint()` the GUI and (in a single panel) draw all the shapes in the list. – Andrew Thompson Sep 18 '17 at 07:42

1 Answers1

1
    JFrame window = new JFrame();
    window.add(circle);
    window.add(square);

The default layout manager for a JFrame is the BorderLayout. When you add a component to a panel using the BorderLayout and don't specify a constraint then the component goes to the CENTER. However only one component can ever be displayed in the CENTER, so only the last component added is painted.

You could use the OverlayLayout, which allows you to stack two panels on top of one another. Of course you will need to make the top panel non-opaque.

The easier solution is to not attempt to use two panels, just create on panel that can display circles or squares.

Also, your painting code is wrong. You should not be using paintImmediately(...) to do painting. The paintComponent() method should paint every object every time the method is invoked. Try resizing your frame and you will see that all your object disappear since the paintComponent() method will clear all the old paintings.

See Custom Painting Approaches for the two common approaches for this kind of painting.

camickr
  • 321,443
  • 19
  • 166
  • 288