user10000467
user10000467

Reputation:

Draw Randomly-Sized Shape from User JList Selection of Shapes in Java GUI

I have to produce a randomly-sized shape (from 50 to 300 pixels) in a java GUI. There is a JList of 3 shapes (rectangle, square, circle) that the user can choose from, and when they choose one, a randomly-sized rectangle, square, or circle should appear in the GUI.

I guess I'm just having trouble figuring out where and how to implement the list selection listeners.

Here is my code so far:

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;

public class ShapeSelectionWindow extends JPanel implements ListSelectionListener{

    public void paintComponent(Graphics g) {
        int x, y, width, height;
        super.paintComponent(g);

        width = (int)Math.floor(Math.random()*250) + 50;
        height = (int)Math.floor(Math.random()*250) + 50;
        x = (int)Math.floor((615 - width) / 2);
        y = (int)Math.floor((661 - height) / 2);

        g.fillRect(x, y, width, height);
    }

    public static void main(String[] args) {
        ShapeSelectionWindow ssw = new ShapeSelectionWindow();
        JFrame jf = new JFrame();
        JPanel shapeListPanel = new JPanel();
        shapeListPanel.setBackground(Color.WHITE);
        DefaultListModel<String> dlm = new DefaultListModel<String>();
        dlm.addElement("Rectangle");
        dlm.addElement("Square");
        dlm.addElement("Circle");
        JList<String> shapeList = new JList<String>(dlm);
        shapeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        shapeListPanel.add(shapeList);

        jf.getContentPane().setLayout(new BorderLayout());
        jf.getContentPane().add(ssw, BorderLayout.CENTER);
        jf.getContentPane().add(shapeListPanel, BorderLayout.EAST);
        jf.setTitle("Simple Drawing GUI");
        jf.setSize(700, 700);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);
    }

    @Override
    public void valueChanged(ListSelectionEvent e) {
        // TODO Auto-generated method stub

    }
}

The current paintComponent method is for painting a rectangle. Like I said, I'm not sure how to implement the list selection listeners for this project in order to produce different shapes based on the user's selection.

Upvotes: 0

Views: 252

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347194

Your current approach is placing too many eggs in a single basket. Why would ShapeSelectionWindow be responsible for managing the JList? It's sole responsibility is to draw a random shape.

Instead, you should break your design down.

I would start by defining a simple "shape" entity...

public enum Shape {
    RECTANGLE("Rectangle"), SQUARE("Square"), CIRCLE("Circle");

    private String name;

    private Shape(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return getName();
    }

}

This just provides a limit set of options which can be used.

I would then update the "shape pane" to support these options...

public class ShapePane extends JPanel {

    private Shape shape;

    public void setShape(Shape shape) {
        this.shape = shape;
        repaint();
    }

    public Shape getShape() {
        return shape;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(800, 800);
    }

    public void paintComponent(Graphics g) {
        int x, y, width, height;
        super.paintComponent(g);
        Shape shape = getShape();
        if (shape == null) {
            return;
        }

        width = (int) Math.floor(Math.random() * 250) + 50;
        height = (int) Math.floor(Math.random() * 250) + 50;
        x = (int) Math.floor((615 - width) / 2);
        y = (int) Math.floor((661 - height) / 2);

        switch (shape) {
            case RECTANGLE:
                g.fillRect(x, y, width, height);
                break;
            case SQUARE:
                break;
            case CIRCLE:
                break;
        }
    }
}

The ShapePane doesn't care "how" the Shape is specified, it only cares when it changes and wants to paint it

I would then use another component to act as the primary controller between the JList and the ShapePane...

public class MainPane extends JPanel {

    private JList<Shape> list;
    private ShapePane shapePane;

    public MainPane() {
        setLayout(new BorderLayout());

        DefaultListModel<Shape> model = new DefaultListModel<>();
        model.addElement(Shape.SQUARE);
        model.addElement(Shape.RECTANGLE);
        model.addElement(Shape.CIRCLE);

        shapePane = new ShapePane();

        list = new JList<Shape>(model);
        list.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                Shape shape = list.getSelectedValue();
                shapePane.setShape(shape);
            }
        });

        add(list, BorderLayout.WEST);
        add(shapePane, BorderLayout.CENTER);
    }

}

Runnable Example...

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public enum Shape {
        RECTANGLE("Rectangle"), SQUARE("Square"), CIRCLE("Circle");

        private String name;

        private Shape(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return getName();
        }

    }

    public class MainPane extends JPanel {

        private JList<Shape> list;
        private ShapePane shapePane;

        public MainPane() {
            setLayout(new BorderLayout());

            DefaultListModel<Shape> model = new DefaultListModel<>();
            model.addElement(Shape.SQUARE);
            model.addElement(Shape.RECTANGLE);
            model.addElement(Shape.CIRCLE);

            shapePane = new ShapePane();

            list = new JList<Shape>(model);
            list.addListSelectionListener(new ListSelectionListener() {
                @Override
                public void valueChanged(ListSelectionEvent e) {
                    Shape shape = list.getSelectedValue();
                    shapePane.setShape(shape);
                }
            });

            add(list, BorderLayout.WEST);
            add(shapePane, BorderLayout.CENTER);
        }

    }

    public class ShapePane extends JPanel {

        private Shape shape;

        public void setShape(Shape shape) {
            this.shape = shape;
            repaint();
        }

        public Shape getShape() {
            return shape;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(800, 800);
        }

        public void paintComponent(Graphics g) {
            int x, y, width, height;
            super.paintComponent(g);
            Shape shape = getShape();
            if (shape == null) {
                return;
            }

            width = (int) Math.floor(Math.random() * 250) + 50;
            height = (int) Math.floor(Math.random() * 250) + 50;
            x = (int) Math.floor((615 - width) / 2);
            y = (int) Math.floor((661 - height) / 2);

            switch (shape) {
                case RECTANGLE:
                    g.fillRect(x, y, width, height);
                    break;
                case SQUARE:
                    break;
                case CIRCLE:
                    break;
            }
        }
    }

}

Upvotes: 1

Related Questions