0

I'm trying to create a program that generates rectangles using a slider. The user should be able to move the slider and rectangles should appear on the JPanel above the slider with random positions. I have tried running the program but I'm still unable to display anything, I move the slider but nothing appears on screen. I have tried coding this program using examples from the book but im stuck when it comes to actually drawing the rectangles. I am able to create and change the layouts as well as to display the slider and a few labels but i'm unable to get the rectangles to appear on the JPanel. Here is my code:

import java.util.*;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JLabel;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Dimension;
import java.lang.Object;

public class RectangleFrame extends JFrame
{
    private static final int FRAME_WIDTH = 600;
    private static final int FRAME_HEIGHT = 500;
    
    private JPanel RectanglePanel;
    private JSlider RectangleSlider;
    
    int x = 0;
    int y = 0;
    
    /**Creates a new Rectangle frame objects.
     Creates control panel and sets the size.*/
    public RectangleFrame()
    {
        RectanglePanel = new JPanel();
        RectanglePanel.setPreferredSize(new Dimension(600, 300));
        
        add(RectanglePanel, BorderLayout.CENTER);
        createControlPanel();
        setRectangles();
        setSize(FRAME_WIDTH,FRAME_HEIGHT);
    }
    
    
    class RectangleListener  implements ChangeListener
    {
        public void stateChanged(ChangeEvent event)
        {
            setRectangles();
        }
    }
    
    
    /**Creates the Panel where the user can slide and generate rectangles. */
    public void createControlPanel()
    {
        ChangeListener listener = new RectangleListener();
        
        RectangleSlider = new JSlider(JSlider.HORIZONTAL, 1, 20, 1);
        RectangleSlider.addChangeListener(listener);
        
        JPanel controlPanel = new JPanel();
        controlPanel.setLayout(new GridLayout(1,3));
        
        controlPanel.add(new JLabel("Fewer"));
        controlPanel.add(RectangleSlider);
        controlPanel.add(new JLabel("More"));
        
        add(controlPanel, BorderLayout.SOUTH);
        
    }
    
    public void setRectangles()
    {
        
        
        Random random = new Random();

        
        //Read slider value
        int numberOfRectangles = RectangleSlider.getValue();
        
        for(int i = 0; i < numberOfRectangles; i++)
        {
            x = random.nextInt(540);
            y = random.nextInt(290);
            
            
        }

    }
    
    
    protected void paintComponent(Graphics g) 
    {
        super.paintComponents(g);
        
        g.setColor(Color.BLACK);
        g.drawRect(x, y, 60, 10);
    }  
}

I have tried drawing one simple rectangle but not even that appears on the JPanel, let alone multiple. Any resources to further look into this would also bee highly appreciated.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 1
    One way is to create an ArrayList of objects to be painted. Then the paintComponent() method of the JPanel will simply iterate through the ArrayList and paint each object. See [Custom Painting Approaches](https://tips4java.wordpress.com/2009/05/08/custom-painting-approaches/) for a working example demonstrating the concept. – camickr Jul 11 '20 at 23:05

1 Answers1

1

You cannot draw directly on top of a JFrame. For "custom painting" (as this is called) you need to create a subclass of a component that overrides the paintComponent method. For example a JPanel:

class RectanglePanel extends JPanel {

    int numberOfRectangles = 2;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.setColor(Color.BLACK);
        Random random = new Random(42);

        for (int i = 0; i < numberOfRectangles; i++) {
            x = random.nextInt(540);
            y = random.nextInt(290);
            g.drawRect(x, y, 60, 10);
        }

    }
}

You use this custom component the same way you would use a JPanel:

    rectanglePanel = new RectanglePanel();
    rectanglePanel.setPreferredSize(new Dimension(600, 300));
    add(rectanglePanel, BorderLayout.CENTER);

To draw fewer or more rectangles, the simplest thing you can do is change the numberOfRectangles of the custom component and then ask it to repaint itself.

int numberOfRectangles = RectangleSlider.getValue();
rectanglePanel.numberOfRectangles = numberOfRectangles;
rectanglePanel.repaint();

Note that this is a simplified demo and does not demonstrate "good practices" such as encapsulation. A more advanced technique is to using the model-view-controller pattern, and create a "model" object that encapsulates what is supposed to be drawn. You can read more about how that works for example here: The MVC pattern and Swing

Joni
  • 108,737
  • 14
  • 143
  • 193
  • @camickr That worked well. Now the only problem is that i need to read the values of the JSlider that i have there so i can draw "fewer" or "many" rectangles. – Angel Torres Jul 12 '20 at 06:36
  • @AngelTorres, this is not my answer. This only shows how to do basic custom painting. If it helped, then don't forget to "accept" the answer by clicking on the check mark. My comment, shows how to display multiple rectangles. – camickr Jul 12 '20 at 14:15
  • @AngelTorres I've added a hint for how you might draw more than one rectangle, and change the number based on the slider value. – Joni Jul 12 '20 at 15:38