0

I'm practising to draw a shape on a JPanel by clicking on a Jbutton, but I cannot. It's been five hours that I'm surfing the web, but I cannot find the way to do it. This is what I want to do: if I click on "Rectangle" button a rectangle appears under the buttons and if I click on "Circle" button a circle appears.

   import javax.swing.*;
   import java.awt.*;
   import java.awt.event.*;

   class Shape extends JFrame {
       JButton rec, circle;
       static String botSelected;
       Shape (){
           frameSet ();
       }

       void frameSet(){
           JFrame frame = new JFrame();
           frame.setVisible(true);
           frame.setSize(600,300);
           rec = new JButton ("Rectangle");
           circle = new JButton("Circle");
           JPanel panel = new JPanel();
           frame.add(panel);
           panel.add(rec);
           panel.add(circle);
           Click clk = new Click();
           rec.addActionListener(clk);
           circle.addActionListener(clk);
       }

       public void paint (Graphics g){
           super.paint(g);
           if (botSelected.equals("Rectangle"))
               g.fillRect(50,50,50,50);
           else if (botSelected.equals("Circle"))
               g.fillOval(50,50,50,50);
       }

       public static void main (String [] arg){
           Shape s = new Shape();
       }
   }

   class Click implements ActionListener{
       public void actionPerformed (ActionEvent e){
           Shape.botSelected = e.getActionCommand();
       }
   }
  • You need to call repaint for the changes to show up. This code is littered with so many bad practices. Why are you extending JFrame? You shouldn't name your class `Shape` because it is a class in awt, ie `java.awt.Shape` – matt May 15 '17 at 06:36
  • The first thing I would do is have a read through [Painting in Swing](http://www.oracle.com/technetwork/java/painting-140037.html) and [Performing custom painting](https://docs.oracle.com/javase/tutorial/uiswing/painting/) to better understand how the painting process works. As general recommendation, I'd avoid `static`, it's not a solution for cross object communication – MadProgrammer May 15 '17 at 06:37

2 Answers2

2

The first thing I would do is have a read through Painting in Swing and Performing custom painting to better understand how the painting process works.

Next you need to understand that JFrame is a bad choice for painting to. Why? Because it's multilayered.

RootPane

A JFrame contains a JRootPane, which contains a JLayeredPane the contentPane, glassPane and the JMenuBar and in your example, it also contains a JPanel.

With the (default) exception of the glassPane, all these components are opaque.

While it's possible to have something drawn in the paint method show it, if any of the other components paint themselves, it will be wiped clean - this is because Swing components can actually be painted independently of each other, with having to have the parent paint itself first.

A better solution is to start by extending from JPanel and override its paintComponent method.

For simplicity, I'd also encourage you to implement the ActionListener against this class as well, it will allow the actionPerformed method to access the properties of the component and, in your case, call repaint to trigger a paint cycle when you want to update the UI.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
1

Here is a derived example from your code.

As @MadProgrammer said, don't extend JFrame.

In the following example, here are the major changes :

  • give a non-null value to botSelected, or the first calls to paintComponent will give you a NullPointerException

  • the class now extends JPanel, and overrides paintComponent for custom painting

  • the ActionListener is an anonymous class, because you don't need a separate class, and it has direct access to the fields from Shape

  • botSelected is no longer static (see above point)

.

import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

class Shape extends JPanel {
    JButton rec, circle;
    String botSelected = "";// don't let it be null, it would make paintComponent crash on startup

    Shape() {
        frameSet();
    }

    void frameSet() {
        JFrame frame = new JFrame();
        frame.setVisible(true);
        frame.setSize(600, 300);
        rec = new JButton("Rectangle");
        circle = new JButton("Circle");

        frame.add(this);
        this.add(rec);
        this.add(circle);
        // anonymous class, has access to fields from the outer class Shape
        ActionListener clk = new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                botSelected = e.getActionCommand();
                repaint();
            }

        };
        rec.addActionListener(clk);
        circle.addActionListener(clk);
    }

    //custom painting of the JPanel
    @Override
    public void paintComponent(final Graphics g) {

        super.paintComponent(g);
        if (botSelected.equals("Rectangle")) {
            g.fillRect(50, 50, 50, 50);
        } else if (botSelected.equals("Circle")) {
            g.fillOval(50, 50, 50, 50);
        }
    }

    public static void main(final String[] arg) {
        Shape s = new Shape();
    }

}
Arnaud
  • 17,229
  • 3
  • 31
  • 44
  • I still not clear why extending the JFrame did not work but Jpanel works. and how the "this" works to adding the buttons. And why final String in the main method? where can I read more about these? TNX – Ali Tahrei Sh. May 15 '17 at 23:54
  • A `JFrame` has its own content `JPanel`, trying to override the `paint` from the `JFrame` will do nothing useful.Since your class itself is a `JPanel` , `this` means the `Shape` `JPanel`itself, so you can add things simply with `this.add...`. – Arnaud May 16 '17 at 05:52
  • The `final` has been added automatically by my IDE (Eclipse here), because of a rule I have set : "add final to method parameters". You may find more information here : http://stackoverflow.com/questions/2236599/final-keyword-in-method-parameters – Arnaud May 16 '17 at 05:57