Let me explain a few sections of my code for better understanding. The code starts with a lambda expression:
This can be written as:
Effectively, the main program only creates an object of ShapeDrawingApp and then calls it's initUI() method. This follows the paradigm that https://coderanch.com/wiki/660020/Main-Pain
Now, you might wonder why dont we directly call the method instead of using invokeLater. The answer is well explained in the java tutorials here: https://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
It simply states:
java tutorial wrote:all code that creates or interacts with Swing components must run on the event dispatch thread
I suggest reading about lambdas a bit if you find that statement confusing: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
To put it simply, it's just a compact way of writing anonymous classes with a single method.
Now, let's go to the variables... As you can see, I have only used 3 variables: The JFrame, the ButtonGroup and the ShapeDrawingPanel. This way, we only have field variables that are required to be accessed across methods.
The ButtonGroup has a method called getSelection. This method returns the selected button from the "circle", "square", "rectangle" ones. Hence we don't a reference to each of them (your original circle, square, triangle, rectangle, sphere, cube, cone, cylinder, torus variables). We are only interested in the selected one. Let me know if that makes sense
Moving to the initUI method, I created all panels in methods to keep the code neater and concise.
Looking at the code for JRadioButton, the code you wrote was repeating the same steps for each of them, so this is where a loop comes into picture.
The code reads as:
We can discuss this further if it's a bit confusing. Streams may seem a bit scary at first ;)
Once we have a list of all created JRadio buttons, we simply loop through them and add them to the button group as well as the panel. As you probably discovered already, adding them to the group creates this bond that only allows one of them to be selected. I have also taken the first item from the list using stream's findFirst() method and set it to selected by default. This is in line with your original code.
Now that the GUI is done, we add the listeners to the buttons. Since shapeSelectionGroup is a field variable, we can access it and find out which one is selected every time the user clicks the button. Additionally, since drawShapePanel is a field variable as well, we can ask it to draw our selected shape. As Campbell rightly stated, the if-else condition is still not a good way to draw the shape especially given that we know that they can be different objects with behaviors.
I'll let you work that one out, let us know if you are still unable to get that to work. Hint, Campbell has shared a nice little interface that can draw itself !!