Search code examples
javaswinggrid-layoutpaintcomponent

Adding a drawn (and editable) rectangle to a grid array containing sliders and textFields


Disclaimer: This code is for an assignment. Granted, the question I'm asking doesn't have anything to do with the assignment's requirements (it doesn't specify needing any sort of layout), but I wanted to mention that.

My assignment is to create a GUI displaying a rectangle with it's color able to be changed through three sliders (RGB), as well as three text fields displaying each slider's current value (0-255). I've managed to find a way to set up the sliders and textFields in the positions I want them through an array, but I have no idea how to add the rectangle to a slot on that array (or if I even can). The code I have currently also draws the rectangle as two intersecting lines rather than a solid block. Would that have something to do with my layout?

package ExercisePackage;


import java.awt.Graphics;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;

import javax.swing.JFrame;

public class MyColorChooser extends JPanel {

    // Holds int values
    private int red = 255;
    private int green = 255;
    private int blue = 255;
    // Holds color sliders
    private JSlider redSlider;
    private JSlider greenSlider;
    private JSlider blueSlider;
    // Holds slider text numbers
    private JTextField redText;
    private JTextField greenText;
    private JTextField blueText;

    // Create rectangle
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(new Color(red, green, blue));
        g.fillRect(15, 25, 100, 20);
    }

    public MyColorChooser()
    {
        // Create and set layout array for specific cell placement
        int rows = 3;
        int columns = 3;
        JPanel[][] panelHolder = new JPanel[rows][columns];
        setLayout(new GridLayout(rows, columns, 5, 5));
        // Formula for cell placement
        for(int m = 0; m < rows; m++) {
            for(int n = 0; n < columns; n++) {
                panelHolder[m][n] = new JPanel();
                add(panelHolder[m][n]);
            }
        }

        // Create sliders
        redSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 255, 0);
        redSlider.addChangeListener(new SliderListener());
        greenSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 255, 0);
        greenSlider.addChangeListener(new SliderListener());
        blueSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 255, 0);
        blueSlider.addChangeListener(new SliderListener());

        // Create text fields
        redText = new JTextField("0", 3);
        redText.setEditable(false);
        greenText = new JTextField("0", 3);
        greenText.setEditable(false);
        blueText = new JTextField("0", 3);
        blueText.setEditable(false);

        // Add sliders and text fields
        panelHolder[0][0].add(redSlider);
        panelHolder[0][1].add(greenSlider);
        panelHolder[0][2].add(blueSlider);
        panelHolder[1][0].add(redText);
        panelHolder[1][1].add(greenText);
        panelHolder[1][2].add(blueText);   
    }

    // Inner class to handle event changes when the slider is moved
    private class SliderListener implements ChangeListener {

        public void stateChanged(ChangeEvent e)
        {
            // Link color values to slider
            red = redSlider.getValue();
            green = greenSlider.getValue();
            blue = blueSlider.getValue();

            // Link text field values to slider
            redText.setText(Integer.toString(red));
            greenText.setText(Integer.toString(green));
            blueText.setText(Integer.toString(blue));

            // Link rectangle color to sliders
            repaint();
        }
    }

    public static void main(String[] args){
        JFrame frame = new JFrame();
        frame.setContentPane( new MyColorChooser() );
        frame.pack();
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

Solution

  • It's not clear why you have the JPanel[][] at all your issue appears to be that you adding a bunch of components to a JPanel, that also paints a color box. So the you want to make a new JPanel that paints the color box, and add that to your component.

    The first change is to replace your paintComponent with a JPanel.

    JPanel colorPanel = new JPanel(){
        // Create rectangle
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(new Color(red, green, blue));
            g.fillRect(15, 25, 100, 20);
        }
        @Override
        public Dimension getPreferredSize(){
             //should be fixed.
             return new Dimension(115, 45);
        }
    }
    

    Then add that component to your layout in the constructor (I am not a fan of doing so much gui work in the constructor.)

        //... continuing of constructor.
        panelHolder[1][0].add(redText);
        panelHolder[1][1].add(greenText);
        panelHolder[1][2].add(blueText);
        panelHolder[2][0].add(colorPanel);
    }
    

    I have now made a component that draws a rectangle and added it to the original layout. Some issues.

    • the new components size.
    • the position of painting the rectangle is possibly not where you want it.
    • the location in the grid layout is probably off.