如何使用ActionListener在JPanel上绘制一些形状?

时间:2017-05-15 06:29:32

标签: java swing jpanel actionlistener draw

我正在练习通过点击Jbutton在JPanel上绘制一个形状,但我不能。我正在网上冲浪五个小时,但我找不到办法。 这就是我想要做的:如果我点击“矩形”按钮,按钮下会出现一个矩形,如果我点击“圆圈”按钮,就会出现一个圆圈。

   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();
       }
   }

2 个答案:

答案 0 :(得分:1)

我要做的第一件事是阅读Painting in SwingPerforming custom painting,以便更好地了解绘画过程的工作原理。

接下来你需要明白JFrame是绘画的不错选择。为什么?因为它是多层次的。

RootPane

JFrame包含JRootPane,其中包含JLayeredPane contentPaneglassPaneJMenuBar,在您的示例中,还包含JPanel

使用glassPane的(默认)例外,所有这些组件都是不透明的。

虽然可以在paint方法中绘制一些东西来展示它,但是如果任何其他组件自己绘制,它将被擦干净 - 这是因为Swing组件实际上可以独立绘制彼此必须先让父母自己画画。

更好的解决方案是从JPanel延伸并覆盖其paintComponent方法。

为简单起见,我还鼓励您对此类实施ActionListener,它将允许actionPerformed方法访问组件的属性,在您的情况下,当您想要更新UI时,调用repaint来触发绘制周期。

答案 1 :(得分:1)

以下是您的代码中的派生示例。

正如@MadProgrammer所说,不要延长JFrame

在以下示例中,以下是主要更改:

  • botSelected提供非空值,或者第一次拨打paintComponent会给您NullPointerException

  • 该课程现在扩展JPanel,并覆盖paintComponent以进行自定义绘画

  • ActionListener是一个匿名类,因为您不需要单独的类,并且可以直接访问Shape

  • botSelected不再是静态的(参见上文)

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();
    }

}