Swing GUI application to change colour of circle with JSlider











up vote
1
down vote

favorite












The below code works as intended and I'm generally happy with it - the sliders each change an RGB value to modify the color of the circle in circlePanel.
Likewise the diameter slider changes the size.



Could the code be refactored/restructured to make it better/more readable?
The CircleSlider constructor is quite long - I'm wondering could some of it be removed to separate methods/classes.



CircleSlider.java



//import statements
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;

//CircleSlider class to setup GUI and main logic
public class CircleSlider extends JFrame{
//instantiate GUI components
private final JPanel circlePanel;
private final JSlider diameterSlider, redSlider, greenSlider, blueSlider;
private final JLabel diameterLabel, redLabel, greenLabel, blueLabel;
private final JTextArea displayArea;
private final GridBagLayout layout;
private final GridBagConstraints constraints;

//circle properties
private int diameter = 75;

private Color circleColor;

//constructor to set up GUI
public CircleSlider(){
//call to JFrame constructor to set title
super("Circle Slider");

//create new layout
layout = new GridBagLayout();
constraints = new GridBagConstraints();
setLayout(layout);

//add calculation display area
displayArea = new JTextArea(6,10);
displayArea.setText("Adjust the diameter slider to see information on the circle");
addComponent(displayArea, 14, 0, 20, 8, 1, 1,
GridBagConstraints.BOTH, GridBagConstraints.CENTER);

//add JPanel to house the circle
circlePanel = new JPanel(){
@Override
protected void paintComponent(Graphics g){
super.paintComponent(g);

//set color of drawn graphics
g.setColor(circleColor);
//Draw circle in centre of circlePanel
g.fillOval((circlePanel.getWidth() - diameter) / 2, (circlePanel.getHeight() - diameter) / 2,
diameter, diameter);
}
};
addComponent(circlePanel, 1, 3, 16, 11, 1, 1,
GridBagConstraints.BOTH, GridBagConstraints.CENTER);

//add label for diameter slider
diameterLabel = new JLabel("Diameter");
addComponent(diameterLabel, 1, 1, 1, 1, 0, 1,
GridBagConstraints.NONE, GridBagConstraints.WEST);

//add the slider to control diameter of circle
diameterSlider = new JSlider(0, 150, 50);
//add listener as anonymous inner class
diameterSlider.addChangeListener(
new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
double radius = diameter / 2.0;
setDiameter(diameterSlider.getValue());
String message = String.format(
"Diameter: %d%nArea: %.2f%nCircumference: %.2f",
diameter, getArea(radius), getCircumference(radius));
displayArea.setText(message);
}
}
);
addComponent(diameterSlider, 2, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
GridBagConstraints.WEST);

//create listener for color sliders
SliderListener sliderListener = new SliderListener();

//add redSlider and label
redLabel = new JLabel("RGB: Red");
addComponent(redLabel, 4, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
GridBagConstraints.WEST);

redSlider = new JSlider(0, 255, 0);
redSlider.addChangeListener(sliderListener);
addComponent(redSlider, 5, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
GridBagConstraints.WEST);

//add greenSlider and label
greenLabel = new JLabel("RGB: Green");
addComponent(greenLabel, 7, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
GridBagConstraints.WEST);

greenSlider = new JSlider(0, 255, 0);
greenSlider.addChangeListener(sliderListener);
addComponent(greenSlider, 8, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
GridBagConstraints.WEST);

//add blueSlider and label
blueLabel = new JLabel("RGB: Blue");
addComponent(blueLabel, 11, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
GridBagConstraints.WEST);

blueSlider = new JSlider(0, 255, 0);
blueSlider.addChangeListener(sliderListener);
addComponent(blueSlider, 12, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
GridBagConstraints.WEST);
}

//ChangeListener for color sliders - implemented as private inner class as
//all color sliders perform same method, setColor()
class SliderListener implements ChangeListener{
@Override
public void stateChanged(ChangeEvent e){
setColor(redSlider.getValue(), greenSlider.getValue(), blueSlider.getValue());
}
}

//helper method to add a component to JPanel or JFrame
private void addComponent(Component component, int row, int column, int width, int height,
int weightx, int weighty, int fillConstraint, int anchorConstraint) {
constraints.gridx = column;
constraints.gridy = row;
constraints.gridwidth = width;
constraints.gridheight = height;
constraints.weightx = weightx;
constraints.weighty = weighty;
constraints.fill = fillConstraint;
constraints.anchor = anchorConstraint;
layout.setConstraints(component, constraints);
add(component);
}

//set the diameter of the circle
private void setDiameter(int newDiameter){
//if new diameter is negative, set to 10
diameter = newDiameter >= 0 ? newDiameter : 10;
repaint();
}

//set the color of the circle
private void setColor(int newRed, int newGreen, int newBlue){
circleColor = new Color(
//if any given color is negative, set to 10
newRed >= 0 ? newRed : 10,
newGreen >= 0 ? newGreen : 10,
newBlue >= 0 ? newBlue : 10);
getGraphics().setColor(circleColor);
repaint();
}

//Find the area of a circle given the radius
private double getArea(double radius){
return Math.PI * Math.pow((radius), 2);
}

//find circumference of circle given the radius
private double getCircumference(double radius){
return 2 * Math.PI * radius;
}
}


CircleSliderTest.java



import javax.swing.*;

public class CircleSliderTest {
public static void main(String args){
CircleSlider app = new CircleSlider();

app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
app.setSize(600,400);
app.setVisible(true);
}
}









share|improve this question














bumped to the homepage by Community 9 hours ago


This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.



















    up vote
    1
    down vote

    favorite












    The below code works as intended and I'm generally happy with it - the sliders each change an RGB value to modify the color of the circle in circlePanel.
    Likewise the diameter slider changes the size.



    Could the code be refactored/restructured to make it better/more readable?
    The CircleSlider constructor is quite long - I'm wondering could some of it be removed to separate methods/classes.



    CircleSlider.java



    //import statements
    import javax.swing.*;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    import java.awt.*;

    //CircleSlider class to setup GUI and main logic
    public class CircleSlider extends JFrame{
    //instantiate GUI components
    private final JPanel circlePanel;
    private final JSlider diameterSlider, redSlider, greenSlider, blueSlider;
    private final JLabel diameterLabel, redLabel, greenLabel, blueLabel;
    private final JTextArea displayArea;
    private final GridBagLayout layout;
    private final GridBagConstraints constraints;

    //circle properties
    private int diameter = 75;

    private Color circleColor;

    //constructor to set up GUI
    public CircleSlider(){
    //call to JFrame constructor to set title
    super("Circle Slider");

    //create new layout
    layout = new GridBagLayout();
    constraints = new GridBagConstraints();
    setLayout(layout);

    //add calculation display area
    displayArea = new JTextArea(6,10);
    displayArea.setText("Adjust the diameter slider to see information on the circle");
    addComponent(displayArea, 14, 0, 20, 8, 1, 1,
    GridBagConstraints.BOTH, GridBagConstraints.CENTER);

    //add JPanel to house the circle
    circlePanel = new JPanel(){
    @Override
    protected void paintComponent(Graphics g){
    super.paintComponent(g);

    //set color of drawn graphics
    g.setColor(circleColor);
    //Draw circle in centre of circlePanel
    g.fillOval((circlePanel.getWidth() - diameter) / 2, (circlePanel.getHeight() - diameter) / 2,
    diameter, diameter);
    }
    };
    addComponent(circlePanel, 1, 3, 16, 11, 1, 1,
    GridBagConstraints.BOTH, GridBagConstraints.CENTER);

    //add label for diameter slider
    diameterLabel = new JLabel("Diameter");
    addComponent(diameterLabel, 1, 1, 1, 1, 0, 1,
    GridBagConstraints.NONE, GridBagConstraints.WEST);

    //add the slider to control diameter of circle
    diameterSlider = new JSlider(0, 150, 50);
    //add listener as anonymous inner class
    diameterSlider.addChangeListener(
    new ChangeListener() {
    @Override
    public void stateChanged(ChangeEvent e) {
    double radius = diameter / 2.0;
    setDiameter(diameterSlider.getValue());
    String message = String.format(
    "Diameter: %d%nArea: %.2f%nCircumference: %.2f",
    diameter, getArea(radius), getCircumference(radius));
    displayArea.setText(message);
    }
    }
    );
    addComponent(diameterSlider, 2, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
    GridBagConstraints.WEST);

    //create listener for color sliders
    SliderListener sliderListener = new SliderListener();

    //add redSlider and label
    redLabel = new JLabel("RGB: Red");
    addComponent(redLabel, 4, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
    GridBagConstraints.WEST);

    redSlider = new JSlider(0, 255, 0);
    redSlider.addChangeListener(sliderListener);
    addComponent(redSlider, 5, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
    GridBagConstraints.WEST);

    //add greenSlider and label
    greenLabel = new JLabel("RGB: Green");
    addComponent(greenLabel, 7, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
    GridBagConstraints.WEST);

    greenSlider = new JSlider(0, 255, 0);
    greenSlider.addChangeListener(sliderListener);
    addComponent(greenSlider, 8, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
    GridBagConstraints.WEST);

    //add blueSlider and label
    blueLabel = new JLabel("RGB: Blue");
    addComponent(blueLabel, 11, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
    GridBagConstraints.WEST);

    blueSlider = new JSlider(0, 255, 0);
    blueSlider.addChangeListener(sliderListener);
    addComponent(blueSlider, 12, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
    GridBagConstraints.WEST);
    }

    //ChangeListener for color sliders - implemented as private inner class as
    //all color sliders perform same method, setColor()
    class SliderListener implements ChangeListener{
    @Override
    public void stateChanged(ChangeEvent e){
    setColor(redSlider.getValue(), greenSlider.getValue(), blueSlider.getValue());
    }
    }

    //helper method to add a component to JPanel or JFrame
    private void addComponent(Component component, int row, int column, int width, int height,
    int weightx, int weighty, int fillConstraint, int anchorConstraint) {
    constraints.gridx = column;
    constraints.gridy = row;
    constraints.gridwidth = width;
    constraints.gridheight = height;
    constraints.weightx = weightx;
    constraints.weighty = weighty;
    constraints.fill = fillConstraint;
    constraints.anchor = anchorConstraint;
    layout.setConstraints(component, constraints);
    add(component);
    }

    //set the diameter of the circle
    private void setDiameter(int newDiameter){
    //if new diameter is negative, set to 10
    diameter = newDiameter >= 0 ? newDiameter : 10;
    repaint();
    }

    //set the color of the circle
    private void setColor(int newRed, int newGreen, int newBlue){
    circleColor = new Color(
    //if any given color is negative, set to 10
    newRed >= 0 ? newRed : 10,
    newGreen >= 0 ? newGreen : 10,
    newBlue >= 0 ? newBlue : 10);
    getGraphics().setColor(circleColor);
    repaint();
    }

    //Find the area of a circle given the radius
    private double getArea(double radius){
    return Math.PI * Math.pow((radius), 2);
    }

    //find circumference of circle given the radius
    private double getCircumference(double radius){
    return 2 * Math.PI * radius;
    }
    }


    CircleSliderTest.java



    import javax.swing.*;

    public class CircleSliderTest {
    public static void main(String args){
    CircleSlider app = new CircleSlider();

    app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    app.setSize(600,400);
    app.setVisible(true);
    }
    }









    share|improve this question














    bumped to the homepage by Community 9 hours ago


    This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.

















      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      The below code works as intended and I'm generally happy with it - the sliders each change an RGB value to modify the color of the circle in circlePanel.
      Likewise the diameter slider changes the size.



      Could the code be refactored/restructured to make it better/more readable?
      The CircleSlider constructor is quite long - I'm wondering could some of it be removed to separate methods/classes.



      CircleSlider.java



      //import statements
      import javax.swing.*;
      import javax.swing.event.ChangeEvent;
      import javax.swing.event.ChangeListener;
      import java.awt.*;

      //CircleSlider class to setup GUI and main logic
      public class CircleSlider extends JFrame{
      //instantiate GUI components
      private final JPanel circlePanel;
      private final JSlider diameterSlider, redSlider, greenSlider, blueSlider;
      private final JLabel diameterLabel, redLabel, greenLabel, blueLabel;
      private final JTextArea displayArea;
      private final GridBagLayout layout;
      private final GridBagConstraints constraints;

      //circle properties
      private int diameter = 75;

      private Color circleColor;

      //constructor to set up GUI
      public CircleSlider(){
      //call to JFrame constructor to set title
      super("Circle Slider");

      //create new layout
      layout = new GridBagLayout();
      constraints = new GridBagConstraints();
      setLayout(layout);

      //add calculation display area
      displayArea = new JTextArea(6,10);
      displayArea.setText("Adjust the diameter slider to see information on the circle");
      addComponent(displayArea, 14, 0, 20, 8, 1, 1,
      GridBagConstraints.BOTH, GridBagConstraints.CENTER);

      //add JPanel to house the circle
      circlePanel = new JPanel(){
      @Override
      protected void paintComponent(Graphics g){
      super.paintComponent(g);

      //set color of drawn graphics
      g.setColor(circleColor);
      //Draw circle in centre of circlePanel
      g.fillOval((circlePanel.getWidth() - diameter) / 2, (circlePanel.getHeight() - diameter) / 2,
      diameter, diameter);
      }
      };
      addComponent(circlePanel, 1, 3, 16, 11, 1, 1,
      GridBagConstraints.BOTH, GridBagConstraints.CENTER);

      //add label for diameter slider
      diameterLabel = new JLabel("Diameter");
      addComponent(diameterLabel, 1, 1, 1, 1, 0, 1,
      GridBagConstraints.NONE, GridBagConstraints.WEST);

      //add the slider to control diameter of circle
      diameterSlider = new JSlider(0, 150, 50);
      //add listener as anonymous inner class
      diameterSlider.addChangeListener(
      new ChangeListener() {
      @Override
      public void stateChanged(ChangeEvent e) {
      double radius = diameter / 2.0;
      setDiameter(diameterSlider.getValue());
      String message = String.format(
      "Diameter: %d%nArea: %.2f%nCircumference: %.2f",
      diameter, getArea(radius), getCircumference(radius));
      displayArea.setText(message);
      }
      }
      );
      addComponent(diameterSlider, 2, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      //create listener for color sliders
      SliderListener sliderListener = new SliderListener();

      //add redSlider and label
      redLabel = new JLabel("RGB: Red");
      addComponent(redLabel, 4, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      redSlider = new JSlider(0, 255, 0);
      redSlider.addChangeListener(sliderListener);
      addComponent(redSlider, 5, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      //add greenSlider and label
      greenLabel = new JLabel("RGB: Green");
      addComponent(greenLabel, 7, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      greenSlider = new JSlider(0, 255, 0);
      greenSlider.addChangeListener(sliderListener);
      addComponent(greenSlider, 8, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      //add blueSlider and label
      blueLabel = new JLabel("RGB: Blue");
      addComponent(blueLabel, 11, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      blueSlider = new JSlider(0, 255, 0);
      blueSlider.addChangeListener(sliderListener);
      addComponent(blueSlider, 12, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);
      }

      //ChangeListener for color sliders - implemented as private inner class as
      //all color sliders perform same method, setColor()
      class SliderListener implements ChangeListener{
      @Override
      public void stateChanged(ChangeEvent e){
      setColor(redSlider.getValue(), greenSlider.getValue(), blueSlider.getValue());
      }
      }

      //helper method to add a component to JPanel or JFrame
      private void addComponent(Component component, int row, int column, int width, int height,
      int weightx, int weighty, int fillConstraint, int anchorConstraint) {
      constraints.gridx = column;
      constraints.gridy = row;
      constraints.gridwidth = width;
      constraints.gridheight = height;
      constraints.weightx = weightx;
      constraints.weighty = weighty;
      constraints.fill = fillConstraint;
      constraints.anchor = anchorConstraint;
      layout.setConstraints(component, constraints);
      add(component);
      }

      //set the diameter of the circle
      private void setDiameter(int newDiameter){
      //if new diameter is negative, set to 10
      diameter = newDiameter >= 0 ? newDiameter : 10;
      repaint();
      }

      //set the color of the circle
      private void setColor(int newRed, int newGreen, int newBlue){
      circleColor = new Color(
      //if any given color is negative, set to 10
      newRed >= 0 ? newRed : 10,
      newGreen >= 0 ? newGreen : 10,
      newBlue >= 0 ? newBlue : 10);
      getGraphics().setColor(circleColor);
      repaint();
      }

      //Find the area of a circle given the radius
      private double getArea(double radius){
      return Math.PI * Math.pow((radius), 2);
      }

      //find circumference of circle given the radius
      private double getCircumference(double radius){
      return 2 * Math.PI * radius;
      }
      }


      CircleSliderTest.java



      import javax.swing.*;

      public class CircleSliderTest {
      public static void main(String args){
      CircleSlider app = new CircleSlider();

      app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      app.setSize(600,400);
      app.setVisible(true);
      }
      }









      share|improve this question













      The below code works as intended and I'm generally happy with it - the sliders each change an RGB value to modify the color of the circle in circlePanel.
      Likewise the diameter slider changes the size.



      Could the code be refactored/restructured to make it better/more readable?
      The CircleSlider constructor is quite long - I'm wondering could some of it be removed to separate methods/classes.



      CircleSlider.java



      //import statements
      import javax.swing.*;
      import javax.swing.event.ChangeEvent;
      import javax.swing.event.ChangeListener;
      import java.awt.*;

      //CircleSlider class to setup GUI and main logic
      public class CircleSlider extends JFrame{
      //instantiate GUI components
      private final JPanel circlePanel;
      private final JSlider diameterSlider, redSlider, greenSlider, blueSlider;
      private final JLabel diameterLabel, redLabel, greenLabel, blueLabel;
      private final JTextArea displayArea;
      private final GridBagLayout layout;
      private final GridBagConstraints constraints;

      //circle properties
      private int diameter = 75;

      private Color circleColor;

      //constructor to set up GUI
      public CircleSlider(){
      //call to JFrame constructor to set title
      super("Circle Slider");

      //create new layout
      layout = new GridBagLayout();
      constraints = new GridBagConstraints();
      setLayout(layout);

      //add calculation display area
      displayArea = new JTextArea(6,10);
      displayArea.setText("Adjust the diameter slider to see information on the circle");
      addComponent(displayArea, 14, 0, 20, 8, 1, 1,
      GridBagConstraints.BOTH, GridBagConstraints.CENTER);

      //add JPanel to house the circle
      circlePanel = new JPanel(){
      @Override
      protected void paintComponent(Graphics g){
      super.paintComponent(g);

      //set color of drawn graphics
      g.setColor(circleColor);
      //Draw circle in centre of circlePanel
      g.fillOval((circlePanel.getWidth() - diameter) / 2, (circlePanel.getHeight() - diameter) / 2,
      diameter, diameter);
      }
      };
      addComponent(circlePanel, 1, 3, 16, 11, 1, 1,
      GridBagConstraints.BOTH, GridBagConstraints.CENTER);

      //add label for diameter slider
      diameterLabel = new JLabel("Diameter");
      addComponent(diameterLabel, 1, 1, 1, 1, 0, 1,
      GridBagConstraints.NONE, GridBagConstraints.WEST);

      //add the slider to control diameter of circle
      diameterSlider = new JSlider(0, 150, 50);
      //add listener as anonymous inner class
      diameterSlider.addChangeListener(
      new ChangeListener() {
      @Override
      public void stateChanged(ChangeEvent e) {
      double radius = diameter / 2.0;
      setDiameter(diameterSlider.getValue());
      String message = String.format(
      "Diameter: %d%nArea: %.2f%nCircumference: %.2f",
      diameter, getArea(radius), getCircumference(radius));
      displayArea.setText(message);
      }
      }
      );
      addComponent(diameterSlider, 2, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      //create listener for color sliders
      SliderListener sliderListener = new SliderListener();

      //add redSlider and label
      redLabel = new JLabel("RGB: Red");
      addComponent(redLabel, 4, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      redSlider = new JSlider(0, 255, 0);
      redSlider.addChangeListener(sliderListener);
      addComponent(redSlider, 5, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      //add greenSlider and label
      greenLabel = new JLabel("RGB: Green");
      addComponent(greenLabel, 7, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      greenSlider = new JSlider(0, 255, 0);
      greenSlider.addChangeListener(sliderListener);
      addComponent(greenSlider, 8, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      //add blueSlider and label
      blueLabel = new JLabel("RGB: Blue");
      addComponent(blueLabel, 11, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);

      blueSlider = new JSlider(0, 255, 0);
      blueSlider.addChangeListener(sliderListener);
      addComponent(blueSlider, 12, 1, 1, 1, 0, 1, GridBagConstraints.NONE,
      GridBagConstraints.WEST);
      }

      //ChangeListener for color sliders - implemented as private inner class as
      //all color sliders perform same method, setColor()
      class SliderListener implements ChangeListener{
      @Override
      public void stateChanged(ChangeEvent e){
      setColor(redSlider.getValue(), greenSlider.getValue(), blueSlider.getValue());
      }
      }

      //helper method to add a component to JPanel or JFrame
      private void addComponent(Component component, int row, int column, int width, int height,
      int weightx, int weighty, int fillConstraint, int anchorConstraint) {
      constraints.gridx = column;
      constraints.gridy = row;
      constraints.gridwidth = width;
      constraints.gridheight = height;
      constraints.weightx = weightx;
      constraints.weighty = weighty;
      constraints.fill = fillConstraint;
      constraints.anchor = anchorConstraint;
      layout.setConstraints(component, constraints);
      add(component);
      }

      //set the diameter of the circle
      private void setDiameter(int newDiameter){
      //if new diameter is negative, set to 10
      diameter = newDiameter >= 0 ? newDiameter : 10;
      repaint();
      }

      //set the color of the circle
      private void setColor(int newRed, int newGreen, int newBlue){
      circleColor = new Color(
      //if any given color is negative, set to 10
      newRed >= 0 ? newRed : 10,
      newGreen >= 0 ? newGreen : 10,
      newBlue >= 0 ? newBlue : 10);
      getGraphics().setColor(circleColor);
      repaint();
      }

      //Find the area of a circle given the radius
      private double getArea(double radius){
      return Math.PI * Math.pow((radius), 2);
      }

      //find circumference of circle given the radius
      private double getCircumference(double radius){
      return 2 * Math.PI * radius;
      }
      }


      CircleSliderTest.java



      import javax.swing.*;

      public class CircleSliderTest {
      public static void main(String args){
      CircleSlider app = new CircleSlider();

      app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      app.setSize(600,400);
      app.setVisible(true);
      }
      }






      java swing gui






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 13 at 11:12









      colinhowlin

      61




      61





      bumped to the homepage by Community 9 hours ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.







      bumped to the homepage by Community 9 hours ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          1) Is your CircleSlider really a window? Your code says yes, but as a user, I would find that quite strange. Your CircleSlider should use JFrame as an instance. You can see that clearly in your main method. You are using three methods from it. What about the rest? JFrame has probably 30 methods or more. Can I call all of them without destroying your CircleSlider class? Do I have to call the methods you provided or can I leave them untouched? Should I be able to call them?

          - Probably not. Define your own methods.



          2) I guess you are writing this because you feel like it would waste too many lines otherwise, right?



          private final JSlider diameterSlider, redSlider, greenSlider, blueSlider;


          The problem is not the waste of lines, but the number of instance variables you need for your class. That's your state and your state consists of 14 variables.

          Personally, I would try to stay below 5. It makes reasoning much easier, it makes it more testable, it keeps your class smaller and you could probably initialize the full state through the constructor - to name a few advantages.



          3)



          //set the diameter of the circle
          private void setDiameter(int newDiameter){
          //if new diameter is negative, set to 10
          diameter = newDiameter >= 0 ? newDiameter : 10;
          repaint();
          }


          If you already write something like "This method does X with Y" then the method should be a member of Y and Y should be a class. In your case, make a circle class and put the methods with these comments inside it.



          4) Yes, your constructor is really long. It seems like your application has different parts, but all of them are inside your CircleSlider class. You should create new classes for these parts, for example, a class containing the sliders for your circle (CircleAdjustment could be a name for it).



          5)



          addComponent(greenLabel, 7, 1, 1, 1, 0, 1, GridBagConstraints.NONE, GridBagConstraints.WEST);


          It's good that you are trying to help yourself with additional methods, but this one is quite difficult to read. I could easily swap some numbers and without looking at your method I wouldn't even dare to guess what these numbers mean. You could use additional classes to get around this:



              // instead of:
          constraints.gridx = column;
          constraints.gridy = row;
          constraints.gridwidth = width;
          constraints.gridheight = height;
          // something like this:
          new Grid(column, row, width, height)


          6) All these numbers you are using... ask yourself, do they depend on each other? I am sure some of them do because you are a grid-based layout and if you enlarge one field, it would influence another. This should be visible in your code. The easiest approach (not best) would be to make constants at the beginning of the class which depends on each other:



          private static final int RED_SLIDER_Y = 1;
          private static final int GREEN_SLIDER_Y = RED_SLIDER_Y +1;
          // ...


          EDIT:



          Here is an example of how an Adjustment class and some others around it could look like. I didn't implement the layout stuff completely, but the rest should be ok. If you've further questions, I am here.



          /**
          * Offers a convenient way to initialize a slider. Note that it is final like
          * the other classes. If you don't design your class to be inherited from, make
          * it final. Careless inheritance is dangerous and leads to bad code and bugs.
          */
          public final class SliderValues {
          private final int min;
          private final int max;
          private final int value;

          /**
          * Secondary constructor. It's purpose is to offer another way to construct
          * the object. It's important that every secondary constructor has
          * only a single statement consisting of "this(...)" which calls the
          * primary constructor. Only the primary constructor sets the fields.
          */
          public SliderValues(int min, int max) {
          this(min, max, 0);
          }

          /**
          * Primary constructor. Ideally this is how a primary constructor should
          * look like: Just a simple setup without methods or calculations.
          */
          public SliderValues(int min, int max, int value) {
          this.min = min;
          this.max = max;
          this.value = value;
          }

          /**
          * Yes, you could also have just three getters, but I prefer this option,
          * because the purpose of this class is to initialize a slider and that's
          * what this method does.
          * This class is not a data container.
          */
          public JSlider initialized(JSlider slider) {
          slider.setMinimum(min);
          slider.setMaximum(max);
          slider.setValue(value);
          return slider;
          }
          }

          public final class LabeledSlider {
          private final JPanel panel;
          private final JSlider slider;
          private final JLabel label;

          /**
          * A secondary constructor again for the sake of convenience.
          */
          public LabeledSlider(String text, int min, int max, ChangeListener listener) {
          this(
          text,
          new SliderValues(min, max),
          listener
          );
          }

          /**
          * Why didn't I just use a constructor with five values instead of the
          * SliderValues class? First, three integers in a row are risky for the
          * client. He could mistaken the order. Additionally, I don't want more than
          * 4 parameters per method/constructor.
          * @param listener I replaced the ChangeListener for the Consumer. The advantage
          * is that the caller doesn't need to somehow get the value of the slider
          * but instead he just gets it from the slider. Additionally, the slider
          * can hold its encapsulation and doesn't need to provide a getValue()
          * method.
          */
          public LabeledSlider(String text, SliderValues values, Consumer<Integer> listener) {
          label = new JLabel(text);
          slider = values.initialized(new JSlider());
          slider.addChangeListener(
          e -> listener.accept(slider.getValue())
          );
          panel = new JPanel(new BorderLayout());
          panel.add(label, BorderLayout.NORTH);
          panel.add(slider, BorderLayout.SOUTH);
          }

          /**
          * Note that I am not inheriting from any class, because there is exactly
          * one thing I want this class to do: Being attached on a container.
          * Inheriting from Container would give me this possibility - and 30 other
          * methods I don't want. This is a neat alternative using only one method.
          */
          public void addOn(Container container) {
          container.add(panel);
          }
          }

          public final class Adjustment {
          private final JPanel panel;

          public Adjustment(Circle circle) {
          panel = new JPanel();
          panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
          new LabeledSlider(
          "Diameter",
          new SliderValues(0, 150, 50),
          /*
          I don't know if you've used the other syntax on purpose, but if not,
          this is a way to shorten your ChangeListener creation. It's called
          "lambda" and is usable on Interfaces with only one method
          (ChangeListener is such an Interface).

          Note that this isn't the best application for a lambda. Normally
          you use it if you have short code around 4 lines or less, because
          it tends to hurt readability if it's longer.
          */
          e -> {
          double radius = diameter / 2.0;
          setDiameter(diameterSlider.getValue());
          String message = String.format(
          "Diameter: %d%nArea: %.2f%nCircumference: %.2f",
          diameter, getArea(radius), getCircumference(radius));
          displayArea.setText(message);
          }
          ).addOn(panel);
          new LabeledSlider(
          "RGB: Red",
          0,
          255,
          value -> circle.red(value)
          ).addOn(panel);
          new LabeledSlider(
          "RGB: Green",
          0,
          255,
          circle::green // alternative syntax for the lambda called "method reference".
          // If you don't understand it, just use the normal one.

          // It works only if your lambda provides the same amount and types
          // of values as the the method you're referencing takes.
          // In this case, green takes one argument (integer) and you get
          // one integer from the lambda.
          ).addOn(panel);
          // ...
          }

          public void addOn(Container container) {
          container.add(panel);
          }
          }





          share|improve this answer























          • Thanks for your answer. The application now just creates an instance of JFrame instead of extending it. I've also created a Circle class and moved any of the logic relating to the appearance of the circle to that class. I'm confused about how to move any of the other parts to separate classes. For instance, for the CircleAdjustment class containing the sliders, how would I add these to the JFrame? Would the CircleAdjustment class implement the changeListener for the JSliders?
            – colinhowlin
            Nov 14 at 15:00










          • edit I added some code to show how the Adjustment class could look like. Note that I am using different panels and layouts because the classes represent their own area on the window and thus they should've their own panel and their own layout.
            – Synth
            Nov 14 at 23:21











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207546%2fswing-gui-application-to-change-colour-of-circle-with-jslider%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          0
          down vote













          1) Is your CircleSlider really a window? Your code says yes, but as a user, I would find that quite strange. Your CircleSlider should use JFrame as an instance. You can see that clearly in your main method. You are using three methods from it. What about the rest? JFrame has probably 30 methods or more. Can I call all of them without destroying your CircleSlider class? Do I have to call the methods you provided or can I leave them untouched? Should I be able to call them?

          - Probably not. Define your own methods.



          2) I guess you are writing this because you feel like it would waste too many lines otherwise, right?



          private final JSlider diameterSlider, redSlider, greenSlider, blueSlider;


          The problem is not the waste of lines, but the number of instance variables you need for your class. That's your state and your state consists of 14 variables.

          Personally, I would try to stay below 5. It makes reasoning much easier, it makes it more testable, it keeps your class smaller and you could probably initialize the full state through the constructor - to name a few advantages.



          3)



          //set the diameter of the circle
          private void setDiameter(int newDiameter){
          //if new diameter is negative, set to 10
          diameter = newDiameter >= 0 ? newDiameter : 10;
          repaint();
          }


          If you already write something like "This method does X with Y" then the method should be a member of Y and Y should be a class. In your case, make a circle class and put the methods with these comments inside it.



          4) Yes, your constructor is really long. It seems like your application has different parts, but all of them are inside your CircleSlider class. You should create new classes for these parts, for example, a class containing the sliders for your circle (CircleAdjustment could be a name for it).



          5)



          addComponent(greenLabel, 7, 1, 1, 1, 0, 1, GridBagConstraints.NONE, GridBagConstraints.WEST);


          It's good that you are trying to help yourself with additional methods, but this one is quite difficult to read. I could easily swap some numbers and without looking at your method I wouldn't even dare to guess what these numbers mean. You could use additional classes to get around this:



              // instead of:
          constraints.gridx = column;
          constraints.gridy = row;
          constraints.gridwidth = width;
          constraints.gridheight = height;
          // something like this:
          new Grid(column, row, width, height)


          6) All these numbers you are using... ask yourself, do they depend on each other? I am sure some of them do because you are a grid-based layout and if you enlarge one field, it would influence another. This should be visible in your code. The easiest approach (not best) would be to make constants at the beginning of the class which depends on each other:



          private static final int RED_SLIDER_Y = 1;
          private static final int GREEN_SLIDER_Y = RED_SLIDER_Y +1;
          // ...


          EDIT:



          Here is an example of how an Adjustment class and some others around it could look like. I didn't implement the layout stuff completely, but the rest should be ok. If you've further questions, I am here.



          /**
          * Offers a convenient way to initialize a slider. Note that it is final like
          * the other classes. If you don't design your class to be inherited from, make
          * it final. Careless inheritance is dangerous and leads to bad code and bugs.
          */
          public final class SliderValues {
          private final int min;
          private final int max;
          private final int value;

          /**
          * Secondary constructor. It's purpose is to offer another way to construct
          * the object. It's important that every secondary constructor has
          * only a single statement consisting of "this(...)" which calls the
          * primary constructor. Only the primary constructor sets the fields.
          */
          public SliderValues(int min, int max) {
          this(min, max, 0);
          }

          /**
          * Primary constructor. Ideally this is how a primary constructor should
          * look like: Just a simple setup without methods or calculations.
          */
          public SliderValues(int min, int max, int value) {
          this.min = min;
          this.max = max;
          this.value = value;
          }

          /**
          * Yes, you could also have just three getters, but I prefer this option,
          * because the purpose of this class is to initialize a slider and that's
          * what this method does.
          * This class is not a data container.
          */
          public JSlider initialized(JSlider slider) {
          slider.setMinimum(min);
          slider.setMaximum(max);
          slider.setValue(value);
          return slider;
          }
          }

          public final class LabeledSlider {
          private final JPanel panel;
          private final JSlider slider;
          private final JLabel label;

          /**
          * A secondary constructor again for the sake of convenience.
          */
          public LabeledSlider(String text, int min, int max, ChangeListener listener) {
          this(
          text,
          new SliderValues(min, max),
          listener
          );
          }

          /**
          * Why didn't I just use a constructor with five values instead of the
          * SliderValues class? First, three integers in a row are risky for the
          * client. He could mistaken the order. Additionally, I don't want more than
          * 4 parameters per method/constructor.
          * @param listener I replaced the ChangeListener for the Consumer. The advantage
          * is that the caller doesn't need to somehow get the value of the slider
          * but instead he just gets it from the slider. Additionally, the slider
          * can hold its encapsulation and doesn't need to provide a getValue()
          * method.
          */
          public LabeledSlider(String text, SliderValues values, Consumer<Integer> listener) {
          label = new JLabel(text);
          slider = values.initialized(new JSlider());
          slider.addChangeListener(
          e -> listener.accept(slider.getValue())
          );
          panel = new JPanel(new BorderLayout());
          panel.add(label, BorderLayout.NORTH);
          panel.add(slider, BorderLayout.SOUTH);
          }

          /**
          * Note that I am not inheriting from any class, because there is exactly
          * one thing I want this class to do: Being attached on a container.
          * Inheriting from Container would give me this possibility - and 30 other
          * methods I don't want. This is a neat alternative using only one method.
          */
          public void addOn(Container container) {
          container.add(panel);
          }
          }

          public final class Adjustment {
          private final JPanel panel;

          public Adjustment(Circle circle) {
          panel = new JPanel();
          panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
          new LabeledSlider(
          "Diameter",
          new SliderValues(0, 150, 50),
          /*
          I don't know if you've used the other syntax on purpose, but if not,
          this is a way to shorten your ChangeListener creation. It's called
          "lambda" and is usable on Interfaces with only one method
          (ChangeListener is such an Interface).

          Note that this isn't the best application for a lambda. Normally
          you use it if you have short code around 4 lines or less, because
          it tends to hurt readability if it's longer.
          */
          e -> {
          double radius = diameter / 2.0;
          setDiameter(diameterSlider.getValue());
          String message = String.format(
          "Diameter: %d%nArea: %.2f%nCircumference: %.2f",
          diameter, getArea(radius), getCircumference(radius));
          displayArea.setText(message);
          }
          ).addOn(panel);
          new LabeledSlider(
          "RGB: Red",
          0,
          255,
          value -> circle.red(value)
          ).addOn(panel);
          new LabeledSlider(
          "RGB: Green",
          0,
          255,
          circle::green // alternative syntax for the lambda called "method reference".
          // If you don't understand it, just use the normal one.

          // It works only if your lambda provides the same amount and types
          // of values as the the method you're referencing takes.
          // In this case, green takes one argument (integer) and you get
          // one integer from the lambda.
          ).addOn(panel);
          // ...
          }

          public void addOn(Container container) {
          container.add(panel);
          }
          }





          share|improve this answer























          • Thanks for your answer. The application now just creates an instance of JFrame instead of extending it. I've also created a Circle class and moved any of the logic relating to the appearance of the circle to that class. I'm confused about how to move any of the other parts to separate classes. For instance, for the CircleAdjustment class containing the sliders, how would I add these to the JFrame? Would the CircleAdjustment class implement the changeListener for the JSliders?
            – colinhowlin
            Nov 14 at 15:00










          • edit I added some code to show how the Adjustment class could look like. Note that I am using different panels and layouts because the classes represent their own area on the window and thus they should've their own panel and their own layout.
            – Synth
            Nov 14 at 23:21















          up vote
          0
          down vote













          1) Is your CircleSlider really a window? Your code says yes, but as a user, I would find that quite strange. Your CircleSlider should use JFrame as an instance. You can see that clearly in your main method. You are using three methods from it. What about the rest? JFrame has probably 30 methods or more. Can I call all of them without destroying your CircleSlider class? Do I have to call the methods you provided or can I leave them untouched? Should I be able to call them?

          - Probably not. Define your own methods.



          2) I guess you are writing this because you feel like it would waste too many lines otherwise, right?



          private final JSlider diameterSlider, redSlider, greenSlider, blueSlider;


          The problem is not the waste of lines, but the number of instance variables you need for your class. That's your state and your state consists of 14 variables.

          Personally, I would try to stay below 5. It makes reasoning much easier, it makes it more testable, it keeps your class smaller and you could probably initialize the full state through the constructor - to name a few advantages.



          3)



          //set the diameter of the circle
          private void setDiameter(int newDiameter){
          //if new diameter is negative, set to 10
          diameter = newDiameter >= 0 ? newDiameter : 10;
          repaint();
          }


          If you already write something like "This method does X with Y" then the method should be a member of Y and Y should be a class. In your case, make a circle class and put the methods with these comments inside it.



          4) Yes, your constructor is really long. It seems like your application has different parts, but all of them are inside your CircleSlider class. You should create new classes for these parts, for example, a class containing the sliders for your circle (CircleAdjustment could be a name for it).



          5)



          addComponent(greenLabel, 7, 1, 1, 1, 0, 1, GridBagConstraints.NONE, GridBagConstraints.WEST);


          It's good that you are trying to help yourself with additional methods, but this one is quite difficult to read. I could easily swap some numbers and without looking at your method I wouldn't even dare to guess what these numbers mean. You could use additional classes to get around this:



              // instead of:
          constraints.gridx = column;
          constraints.gridy = row;
          constraints.gridwidth = width;
          constraints.gridheight = height;
          // something like this:
          new Grid(column, row, width, height)


          6) All these numbers you are using... ask yourself, do they depend on each other? I am sure some of them do because you are a grid-based layout and if you enlarge one field, it would influence another. This should be visible in your code. The easiest approach (not best) would be to make constants at the beginning of the class which depends on each other:



          private static final int RED_SLIDER_Y = 1;
          private static final int GREEN_SLIDER_Y = RED_SLIDER_Y +1;
          // ...


          EDIT:



          Here is an example of how an Adjustment class and some others around it could look like. I didn't implement the layout stuff completely, but the rest should be ok. If you've further questions, I am here.



          /**
          * Offers a convenient way to initialize a slider. Note that it is final like
          * the other classes. If you don't design your class to be inherited from, make
          * it final. Careless inheritance is dangerous and leads to bad code and bugs.
          */
          public final class SliderValues {
          private final int min;
          private final int max;
          private final int value;

          /**
          * Secondary constructor. It's purpose is to offer another way to construct
          * the object. It's important that every secondary constructor has
          * only a single statement consisting of "this(...)" which calls the
          * primary constructor. Only the primary constructor sets the fields.
          */
          public SliderValues(int min, int max) {
          this(min, max, 0);
          }

          /**
          * Primary constructor. Ideally this is how a primary constructor should
          * look like: Just a simple setup without methods or calculations.
          */
          public SliderValues(int min, int max, int value) {
          this.min = min;
          this.max = max;
          this.value = value;
          }

          /**
          * Yes, you could also have just three getters, but I prefer this option,
          * because the purpose of this class is to initialize a slider and that's
          * what this method does.
          * This class is not a data container.
          */
          public JSlider initialized(JSlider slider) {
          slider.setMinimum(min);
          slider.setMaximum(max);
          slider.setValue(value);
          return slider;
          }
          }

          public final class LabeledSlider {
          private final JPanel panel;
          private final JSlider slider;
          private final JLabel label;

          /**
          * A secondary constructor again for the sake of convenience.
          */
          public LabeledSlider(String text, int min, int max, ChangeListener listener) {
          this(
          text,
          new SliderValues(min, max),
          listener
          );
          }

          /**
          * Why didn't I just use a constructor with five values instead of the
          * SliderValues class? First, three integers in a row are risky for the
          * client. He could mistaken the order. Additionally, I don't want more than
          * 4 parameters per method/constructor.
          * @param listener I replaced the ChangeListener for the Consumer. The advantage
          * is that the caller doesn't need to somehow get the value of the slider
          * but instead he just gets it from the slider. Additionally, the slider
          * can hold its encapsulation and doesn't need to provide a getValue()
          * method.
          */
          public LabeledSlider(String text, SliderValues values, Consumer<Integer> listener) {
          label = new JLabel(text);
          slider = values.initialized(new JSlider());
          slider.addChangeListener(
          e -> listener.accept(slider.getValue())
          );
          panel = new JPanel(new BorderLayout());
          panel.add(label, BorderLayout.NORTH);
          panel.add(slider, BorderLayout.SOUTH);
          }

          /**
          * Note that I am not inheriting from any class, because there is exactly
          * one thing I want this class to do: Being attached on a container.
          * Inheriting from Container would give me this possibility - and 30 other
          * methods I don't want. This is a neat alternative using only one method.
          */
          public void addOn(Container container) {
          container.add(panel);
          }
          }

          public final class Adjustment {
          private final JPanel panel;

          public Adjustment(Circle circle) {
          panel = new JPanel();
          panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
          new LabeledSlider(
          "Diameter",
          new SliderValues(0, 150, 50),
          /*
          I don't know if you've used the other syntax on purpose, but if not,
          this is a way to shorten your ChangeListener creation. It's called
          "lambda" and is usable on Interfaces with only one method
          (ChangeListener is such an Interface).

          Note that this isn't the best application for a lambda. Normally
          you use it if you have short code around 4 lines or less, because
          it tends to hurt readability if it's longer.
          */
          e -> {
          double radius = diameter / 2.0;
          setDiameter(diameterSlider.getValue());
          String message = String.format(
          "Diameter: %d%nArea: %.2f%nCircumference: %.2f",
          diameter, getArea(radius), getCircumference(radius));
          displayArea.setText(message);
          }
          ).addOn(panel);
          new LabeledSlider(
          "RGB: Red",
          0,
          255,
          value -> circle.red(value)
          ).addOn(panel);
          new LabeledSlider(
          "RGB: Green",
          0,
          255,
          circle::green // alternative syntax for the lambda called "method reference".
          // If you don't understand it, just use the normal one.

          // It works only if your lambda provides the same amount and types
          // of values as the the method you're referencing takes.
          // In this case, green takes one argument (integer) and you get
          // one integer from the lambda.
          ).addOn(panel);
          // ...
          }

          public void addOn(Container container) {
          container.add(panel);
          }
          }





          share|improve this answer























          • Thanks for your answer. The application now just creates an instance of JFrame instead of extending it. I've also created a Circle class and moved any of the logic relating to the appearance of the circle to that class. I'm confused about how to move any of the other parts to separate classes. For instance, for the CircleAdjustment class containing the sliders, how would I add these to the JFrame? Would the CircleAdjustment class implement the changeListener for the JSliders?
            – colinhowlin
            Nov 14 at 15:00










          • edit I added some code to show how the Adjustment class could look like. Note that I am using different panels and layouts because the classes represent their own area on the window and thus they should've their own panel and their own layout.
            – Synth
            Nov 14 at 23:21













          up vote
          0
          down vote










          up vote
          0
          down vote









          1) Is your CircleSlider really a window? Your code says yes, but as a user, I would find that quite strange. Your CircleSlider should use JFrame as an instance. You can see that clearly in your main method. You are using three methods from it. What about the rest? JFrame has probably 30 methods or more. Can I call all of them without destroying your CircleSlider class? Do I have to call the methods you provided or can I leave them untouched? Should I be able to call them?

          - Probably not. Define your own methods.



          2) I guess you are writing this because you feel like it would waste too many lines otherwise, right?



          private final JSlider diameterSlider, redSlider, greenSlider, blueSlider;


          The problem is not the waste of lines, but the number of instance variables you need for your class. That's your state and your state consists of 14 variables.

          Personally, I would try to stay below 5. It makes reasoning much easier, it makes it more testable, it keeps your class smaller and you could probably initialize the full state through the constructor - to name a few advantages.



          3)



          //set the diameter of the circle
          private void setDiameter(int newDiameter){
          //if new diameter is negative, set to 10
          diameter = newDiameter >= 0 ? newDiameter : 10;
          repaint();
          }


          If you already write something like "This method does X with Y" then the method should be a member of Y and Y should be a class. In your case, make a circle class and put the methods with these comments inside it.



          4) Yes, your constructor is really long. It seems like your application has different parts, but all of them are inside your CircleSlider class. You should create new classes for these parts, for example, a class containing the sliders for your circle (CircleAdjustment could be a name for it).



          5)



          addComponent(greenLabel, 7, 1, 1, 1, 0, 1, GridBagConstraints.NONE, GridBagConstraints.WEST);


          It's good that you are trying to help yourself with additional methods, but this one is quite difficult to read. I could easily swap some numbers and without looking at your method I wouldn't even dare to guess what these numbers mean. You could use additional classes to get around this:



              // instead of:
          constraints.gridx = column;
          constraints.gridy = row;
          constraints.gridwidth = width;
          constraints.gridheight = height;
          // something like this:
          new Grid(column, row, width, height)


          6) All these numbers you are using... ask yourself, do they depend on each other? I am sure some of them do because you are a grid-based layout and if you enlarge one field, it would influence another. This should be visible in your code. The easiest approach (not best) would be to make constants at the beginning of the class which depends on each other:



          private static final int RED_SLIDER_Y = 1;
          private static final int GREEN_SLIDER_Y = RED_SLIDER_Y +1;
          // ...


          EDIT:



          Here is an example of how an Adjustment class and some others around it could look like. I didn't implement the layout stuff completely, but the rest should be ok. If you've further questions, I am here.



          /**
          * Offers a convenient way to initialize a slider. Note that it is final like
          * the other classes. If you don't design your class to be inherited from, make
          * it final. Careless inheritance is dangerous and leads to bad code and bugs.
          */
          public final class SliderValues {
          private final int min;
          private final int max;
          private final int value;

          /**
          * Secondary constructor. It's purpose is to offer another way to construct
          * the object. It's important that every secondary constructor has
          * only a single statement consisting of "this(...)" which calls the
          * primary constructor. Only the primary constructor sets the fields.
          */
          public SliderValues(int min, int max) {
          this(min, max, 0);
          }

          /**
          * Primary constructor. Ideally this is how a primary constructor should
          * look like: Just a simple setup without methods or calculations.
          */
          public SliderValues(int min, int max, int value) {
          this.min = min;
          this.max = max;
          this.value = value;
          }

          /**
          * Yes, you could also have just three getters, but I prefer this option,
          * because the purpose of this class is to initialize a slider and that's
          * what this method does.
          * This class is not a data container.
          */
          public JSlider initialized(JSlider slider) {
          slider.setMinimum(min);
          slider.setMaximum(max);
          slider.setValue(value);
          return slider;
          }
          }

          public final class LabeledSlider {
          private final JPanel panel;
          private final JSlider slider;
          private final JLabel label;

          /**
          * A secondary constructor again for the sake of convenience.
          */
          public LabeledSlider(String text, int min, int max, ChangeListener listener) {
          this(
          text,
          new SliderValues(min, max),
          listener
          );
          }

          /**
          * Why didn't I just use a constructor with five values instead of the
          * SliderValues class? First, three integers in a row are risky for the
          * client. He could mistaken the order. Additionally, I don't want more than
          * 4 parameters per method/constructor.
          * @param listener I replaced the ChangeListener for the Consumer. The advantage
          * is that the caller doesn't need to somehow get the value of the slider
          * but instead he just gets it from the slider. Additionally, the slider
          * can hold its encapsulation and doesn't need to provide a getValue()
          * method.
          */
          public LabeledSlider(String text, SliderValues values, Consumer<Integer> listener) {
          label = new JLabel(text);
          slider = values.initialized(new JSlider());
          slider.addChangeListener(
          e -> listener.accept(slider.getValue())
          );
          panel = new JPanel(new BorderLayout());
          panel.add(label, BorderLayout.NORTH);
          panel.add(slider, BorderLayout.SOUTH);
          }

          /**
          * Note that I am not inheriting from any class, because there is exactly
          * one thing I want this class to do: Being attached on a container.
          * Inheriting from Container would give me this possibility - and 30 other
          * methods I don't want. This is a neat alternative using only one method.
          */
          public void addOn(Container container) {
          container.add(panel);
          }
          }

          public final class Adjustment {
          private final JPanel panel;

          public Adjustment(Circle circle) {
          panel = new JPanel();
          panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
          new LabeledSlider(
          "Diameter",
          new SliderValues(0, 150, 50),
          /*
          I don't know if you've used the other syntax on purpose, but if not,
          this is a way to shorten your ChangeListener creation. It's called
          "lambda" and is usable on Interfaces with only one method
          (ChangeListener is such an Interface).

          Note that this isn't the best application for a lambda. Normally
          you use it if you have short code around 4 lines or less, because
          it tends to hurt readability if it's longer.
          */
          e -> {
          double radius = diameter / 2.0;
          setDiameter(diameterSlider.getValue());
          String message = String.format(
          "Diameter: %d%nArea: %.2f%nCircumference: %.2f",
          diameter, getArea(radius), getCircumference(radius));
          displayArea.setText(message);
          }
          ).addOn(panel);
          new LabeledSlider(
          "RGB: Red",
          0,
          255,
          value -> circle.red(value)
          ).addOn(panel);
          new LabeledSlider(
          "RGB: Green",
          0,
          255,
          circle::green // alternative syntax for the lambda called "method reference".
          // If you don't understand it, just use the normal one.

          // It works only if your lambda provides the same amount and types
          // of values as the the method you're referencing takes.
          // In this case, green takes one argument (integer) and you get
          // one integer from the lambda.
          ).addOn(panel);
          // ...
          }

          public void addOn(Container container) {
          container.add(panel);
          }
          }





          share|improve this answer














          1) Is your CircleSlider really a window? Your code says yes, but as a user, I would find that quite strange. Your CircleSlider should use JFrame as an instance. You can see that clearly in your main method. You are using three methods from it. What about the rest? JFrame has probably 30 methods or more. Can I call all of them without destroying your CircleSlider class? Do I have to call the methods you provided or can I leave them untouched? Should I be able to call them?

          - Probably not. Define your own methods.



          2) I guess you are writing this because you feel like it would waste too many lines otherwise, right?



          private final JSlider diameterSlider, redSlider, greenSlider, blueSlider;


          The problem is not the waste of lines, but the number of instance variables you need for your class. That's your state and your state consists of 14 variables.

          Personally, I would try to stay below 5. It makes reasoning much easier, it makes it more testable, it keeps your class smaller and you could probably initialize the full state through the constructor - to name a few advantages.



          3)



          //set the diameter of the circle
          private void setDiameter(int newDiameter){
          //if new diameter is negative, set to 10
          diameter = newDiameter >= 0 ? newDiameter : 10;
          repaint();
          }


          If you already write something like "This method does X with Y" then the method should be a member of Y and Y should be a class. In your case, make a circle class and put the methods with these comments inside it.



          4) Yes, your constructor is really long. It seems like your application has different parts, but all of them are inside your CircleSlider class. You should create new classes for these parts, for example, a class containing the sliders for your circle (CircleAdjustment could be a name for it).



          5)



          addComponent(greenLabel, 7, 1, 1, 1, 0, 1, GridBagConstraints.NONE, GridBagConstraints.WEST);


          It's good that you are trying to help yourself with additional methods, but this one is quite difficult to read. I could easily swap some numbers and without looking at your method I wouldn't even dare to guess what these numbers mean. You could use additional classes to get around this:



              // instead of:
          constraints.gridx = column;
          constraints.gridy = row;
          constraints.gridwidth = width;
          constraints.gridheight = height;
          // something like this:
          new Grid(column, row, width, height)


          6) All these numbers you are using... ask yourself, do they depend on each other? I am sure some of them do because you are a grid-based layout and if you enlarge one field, it would influence another. This should be visible in your code. The easiest approach (not best) would be to make constants at the beginning of the class which depends on each other:



          private static final int RED_SLIDER_Y = 1;
          private static final int GREEN_SLIDER_Y = RED_SLIDER_Y +1;
          // ...


          EDIT:



          Here is an example of how an Adjustment class and some others around it could look like. I didn't implement the layout stuff completely, but the rest should be ok. If you've further questions, I am here.



          /**
          * Offers a convenient way to initialize a slider. Note that it is final like
          * the other classes. If you don't design your class to be inherited from, make
          * it final. Careless inheritance is dangerous and leads to bad code and bugs.
          */
          public final class SliderValues {
          private final int min;
          private final int max;
          private final int value;

          /**
          * Secondary constructor. It's purpose is to offer another way to construct
          * the object. It's important that every secondary constructor has
          * only a single statement consisting of "this(...)" which calls the
          * primary constructor. Only the primary constructor sets the fields.
          */
          public SliderValues(int min, int max) {
          this(min, max, 0);
          }

          /**
          * Primary constructor. Ideally this is how a primary constructor should
          * look like: Just a simple setup without methods or calculations.
          */
          public SliderValues(int min, int max, int value) {
          this.min = min;
          this.max = max;
          this.value = value;
          }

          /**
          * Yes, you could also have just three getters, but I prefer this option,
          * because the purpose of this class is to initialize a slider and that's
          * what this method does.
          * This class is not a data container.
          */
          public JSlider initialized(JSlider slider) {
          slider.setMinimum(min);
          slider.setMaximum(max);
          slider.setValue(value);
          return slider;
          }
          }

          public final class LabeledSlider {
          private final JPanel panel;
          private final JSlider slider;
          private final JLabel label;

          /**
          * A secondary constructor again for the sake of convenience.
          */
          public LabeledSlider(String text, int min, int max, ChangeListener listener) {
          this(
          text,
          new SliderValues(min, max),
          listener
          );
          }

          /**
          * Why didn't I just use a constructor with five values instead of the
          * SliderValues class? First, three integers in a row are risky for the
          * client. He could mistaken the order. Additionally, I don't want more than
          * 4 parameters per method/constructor.
          * @param listener I replaced the ChangeListener for the Consumer. The advantage
          * is that the caller doesn't need to somehow get the value of the slider
          * but instead he just gets it from the slider. Additionally, the slider
          * can hold its encapsulation and doesn't need to provide a getValue()
          * method.
          */
          public LabeledSlider(String text, SliderValues values, Consumer<Integer> listener) {
          label = new JLabel(text);
          slider = values.initialized(new JSlider());
          slider.addChangeListener(
          e -> listener.accept(slider.getValue())
          );
          panel = new JPanel(new BorderLayout());
          panel.add(label, BorderLayout.NORTH);
          panel.add(slider, BorderLayout.SOUTH);
          }

          /**
          * Note that I am not inheriting from any class, because there is exactly
          * one thing I want this class to do: Being attached on a container.
          * Inheriting from Container would give me this possibility - and 30 other
          * methods I don't want. This is a neat alternative using only one method.
          */
          public void addOn(Container container) {
          container.add(panel);
          }
          }

          public final class Adjustment {
          private final JPanel panel;

          public Adjustment(Circle circle) {
          panel = new JPanel();
          panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
          new LabeledSlider(
          "Diameter",
          new SliderValues(0, 150, 50),
          /*
          I don't know if you've used the other syntax on purpose, but if not,
          this is a way to shorten your ChangeListener creation. It's called
          "lambda" and is usable on Interfaces with only one method
          (ChangeListener is such an Interface).

          Note that this isn't the best application for a lambda. Normally
          you use it if you have short code around 4 lines or less, because
          it tends to hurt readability if it's longer.
          */
          e -> {
          double radius = diameter / 2.0;
          setDiameter(diameterSlider.getValue());
          String message = String.format(
          "Diameter: %d%nArea: %.2f%nCircumference: %.2f",
          diameter, getArea(radius), getCircumference(radius));
          displayArea.setText(message);
          }
          ).addOn(panel);
          new LabeledSlider(
          "RGB: Red",
          0,
          255,
          value -> circle.red(value)
          ).addOn(panel);
          new LabeledSlider(
          "RGB: Green",
          0,
          255,
          circle::green // alternative syntax for the lambda called "method reference".
          // If you don't understand it, just use the normal one.

          // It works only if your lambda provides the same amount and types
          // of values as the the method you're referencing takes.
          // In this case, green takes one argument (integer) and you get
          // one integer from the lambda.
          ).addOn(panel);
          // ...
          }

          public void addOn(Container container) {
          container.add(panel);
          }
          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 14 at 23:16

























          answered Nov 13 at 14:05









          Synth

          1495




          1495












          • Thanks for your answer. The application now just creates an instance of JFrame instead of extending it. I've also created a Circle class and moved any of the logic relating to the appearance of the circle to that class. I'm confused about how to move any of the other parts to separate classes. For instance, for the CircleAdjustment class containing the sliders, how would I add these to the JFrame? Would the CircleAdjustment class implement the changeListener for the JSliders?
            – colinhowlin
            Nov 14 at 15:00










          • edit I added some code to show how the Adjustment class could look like. Note that I am using different panels and layouts because the classes represent their own area on the window and thus they should've their own panel and their own layout.
            – Synth
            Nov 14 at 23:21


















          • Thanks for your answer. The application now just creates an instance of JFrame instead of extending it. I've also created a Circle class and moved any of the logic relating to the appearance of the circle to that class. I'm confused about how to move any of the other parts to separate classes. For instance, for the CircleAdjustment class containing the sliders, how would I add these to the JFrame? Would the CircleAdjustment class implement the changeListener for the JSliders?
            – colinhowlin
            Nov 14 at 15:00










          • edit I added some code to show how the Adjustment class could look like. Note that I am using different panels and layouts because the classes represent their own area on the window and thus they should've their own panel and their own layout.
            – Synth
            Nov 14 at 23:21
















          Thanks for your answer. The application now just creates an instance of JFrame instead of extending it. I've also created a Circle class and moved any of the logic relating to the appearance of the circle to that class. I'm confused about how to move any of the other parts to separate classes. For instance, for the CircleAdjustment class containing the sliders, how would I add these to the JFrame? Would the CircleAdjustment class implement the changeListener for the JSliders?
          – colinhowlin
          Nov 14 at 15:00




          Thanks for your answer. The application now just creates an instance of JFrame instead of extending it. I've also created a Circle class and moved any of the logic relating to the appearance of the circle to that class. I'm confused about how to move any of the other parts to separate classes. For instance, for the CircleAdjustment class containing the sliders, how would I add these to the JFrame? Would the CircleAdjustment class implement the changeListener for the JSliders?
          – colinhowlin
          Nov 14 at 15:00












          edit I added some code to show how the Adjustment class could look like. Note that I am using different panels and layouts because the classes represent their own area on the window and thus they should've their own panel and their own layout.
          – Synth
          Nov 14 at 23:21




          edit I added some code to show how the Adjustment class could look like. Note that I am using different panels and layouts because the classes represent their own area on the window and thus they should've their own panel and their own layout.
          – Synth
          Nov 14 at 23:21


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207546%2fswing-gui-application-to-change-colour-of-circle-with-jslider%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Ellipse (mathématiques)

          Quarter-circle Tiles

          Mont Emei