【问题标题】:Paint a shape on mouse click with Java用Java在鼠标点击上绘制一个形状
【发布时间】:2014-05-09 00:18:07
【问题描述】:

我正在尝试创建一个 java 程序,当用户单击 Frame 时,它​​将在 JFrame 上绘制一个形状。我已经到了将其设置为接受不同形状并识别点击的地步,但我无法弄清楚如何实现形状的绘制。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.JComponent;

public class StamperFrame extends JFrame {

    private JButton circleButton, ovalButton, squareButton, rectButton;
    private int buttonValue = 0;

    public StamperFrame() {
        setTitle("Shape Stamper");
        setSize(500, 500);

        //Setting up the buttons and positioning them.
        JPanel buttonPanel = new JPanel();

        circleButton = new JButton("Circle");
        ovalButton = new JButton("Oval");
        squareButton = new JButton("Square");
        rectButton = new JButton("Rectangle");

        buttonPanel.add(circleButton);
        buttonPanel.add(ovalButton);
        buttonPanel.add(squareButton);
        buttonPanel.add(rectButton);
        getContentPane().add(buttonPanel, BorderLayout.SOUTH);
        //end button init



        //Setting up button logic
        circleButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                buttonValue = 1;
                System.out.println(buttonValue);
            }
        });
        ovalButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                buttonValue = 2;
                System.out.println(buttonValue);
            }
        });
        squareButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                buttonValue = 3;
                System.out.println(buttonValue);
            }
        });
        rectButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                buttonValue = 4;
                System.out.println(buttonValue);
            }
        });
        //end button click configuration

        getContentPane().addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                if (buttonValue == 1) {
                    System.out.println("Circle added at: " + e.getX() + "," + e.getY());
                } else if (buttonValue == 2) {
                    System.out.println("Oval added at: " + e.getX() + "," + e.getY());
                }else if (buttonValue == 3) {
                    System.out.println("Square added at: " + e.getX() + "," + e.getY());
                }else if (buttonValue == 4) {
                    System.out.println("Rectangle added at: " + e.getX() + "," + e.getY());
                }
            }
        });

    }
}

我知道它需要以某种方式在我的鼠标事件中起作用,但我不知道如何。

我的框架目前看起来像这样:http://puu.sh/8ELaR/c7252286c0.jpg

任何建议将不胜感激。

【问题讨论】:

    标签: java swing mouseevent actionlistener paintcomponent


    【解决方案1】:

    请参阅Custom Painting Approaches 了解自定义绘画的两种方法:

    1. 将要绘制的对象添加到 ArrayList
    2. 将对象直接绘制到 BufferedImage 上。

    链接中的示例仅绘制了一个矩形,因此您显然需要修改代码以支持不同的形状,但它应该会给您一些想法。

    【讨论】:

      【解决方案2】:

      好的。现在真正完整的回答:

      TL;DR:复制并粘贴以下代码:

      package FinalExam;
      
      import java.awt.*;
      import java.awt.event.*;
      import java.awt.geom.*;
      import javax.swing.*;
      
      public class StamperFrame extends JFrame {
      
          private final JButton circleButton, ovalButton, squareButton, rectButton;
      
          private final JPanel shapesPanel;
      
          private Shape shape;
          private final int w = 100;
          private final int h = 200;
      
          private Object lastButtonPressed;
      
          public StamperFrame() {
              setTitle("Shape Stamper");
              setSize(500, 500);
      
              final Container contentPane = getContentPane();
      
              //Setting up the buttons and positioning them.
              JPanel buttonPanel = new JPanel();
      
              circleButton = new JButton("Circle");
              ovalButton = new JButton("Oval");
              squareButton = new JButton("Square");
              rectButton = new JButton("Rectangle");
      
              buttonPanel.add(circleButton);
              buttonPanel.add(ovalButton);
              buttonPanel.add(squareButton);
              buttonPanel.add(rectButton);
      
              contentPane.add(buttonPanel, BorderLayout.SOUTH);
              //end button init
      
              shapesPanel = new JPanel(){
                  @Override
                  public void paintComponent(Graphics graphics) {
                      Graphics2D g = (Graphics2D) graphics;
                      super.paintComponent(g); 
                      if(shape != null) g.draw(shape);
                  }
      
              };
              contentPane.add(shapesPanel, BorderLayout.CENTER);
      
              final ActionListener buttonPressed = new ActionListener() {
                  @Override
                  public void actionPerformed(ActionEvent event) {
                      lastButtonPressed = event.getSource();
                  }
              };
      
              circleButton.addActionListener(buttonPressed);
              ovalButton.addActionListener(buttonPressed);
              squareButton.addActionListener(buttonPressed);
              rectButton.addActionListener(buttonPressed);
      
              contentPane.addMouseListener(new MouseAdapter() {
      
                  @Override
                  public void mouseClicked(MouseEvent e) {
      
                      int x = e.getX();
                      int y = e.getY();
      
                      if(lastButtonPressed == circleButton){
                          shape = new Ellipse2D.Double(x, y, w, w);
                          echo("Circle",x,y);
                      } else if(lastButtonPressed == ovalButton){
                          shape = new Ellipse2D.Double(x, y, w, h);
                          echo("Oval",x,y);
                      } else if (lastButtonPressed == squareButton){
                          shape = new Rectangle2D.Double(x, y, w, w);
                          echo("Square",x,y);
                      } else if (lastButtonPressed == rectButton){
                          echo("Rectangle",x,y);
                          shape = new Rectangle2D.Double(x, y, w, h);
                      } 
      
                      shapesPanel.repaint();
                  }
      
                  private void echo(String shape, int x, int y){
                      System.out.println(shape + " added at: " + x + "," + y);
                  }
      
              });
      
          }
      }
      

      详细解释

      1. 我们不需要变量 buttonValue 来记住按下了哪个按钮。按钮是事件源,所以我们只需存储它,稍后我们就可以知道按下了哪个按钮。
      2. 我们不需要 4 个 ActionListener 实例(每个按钮一个),因为它们都做同样的事情(将事件源存储为“按下的按钮”
      3. 绘图技巧是通过使用JPanel(shapesPanel 变量)作为“绘图画布”来完成的。我们扩展 JPanel 以覆盖 paintComponent。该方法将使用Graphics2D的绘图API。
      4. contentPane 处添加的ActionListener 将获得单击的x 和y 坐标,创建要绘制的Shape(基于最后一个lastButtonPressed),将其存储在变量@987654331 @ 并询问 shapesPanelrepaint() 本身。

      【讨论】:

      • 您好,感谢您的反馈。我实际上提出了一个新问题,因为我现在让程序在点击时进行绘制,但是 repaint() 方法导致了我需要解决的问题。 stackoverflow.com/questions/23557416/… 问题在于 repaint(),但我不确定是否修复。我一定会听取您的建议并减少 ActionListener 的数量。
      【解决方案3】:

      您将在内容窗格中添加一个新的 JPanel,可能位于中心

      JPanel drawingPanel = new JPanel();
      getContentPane().add(drawingPanel, BorderLayout.CENTER);
      

      然后,您将在每个按钮的动作侦听器代码中调用该代码来绘制 JPanel 的图形:

      rectButton.addActionListener(new ActionListener() {
      
              @Override
              public void actionPerformed(ActionEvent e) {
                 Graphics2D g = Graphics2D drawingPanel.getGraphics2D(); 
                 g.draw(new java.awt.Rectangle(42,42,20,40);
      
              }
          });
      

      等等……

      您需要熟悉 Java2D 才能完成 FinalExam 包的工作。

      【讨论】:

      • -1,您不应该使用 getGraphics() 进行绘画。您所做的任何绘画都将是暂时的,并且会在 Swing 第一次确定组件需要重新绘画时丢失。
      • 你是对的。我想应该覆盖paintComponent(Graphics g),检查那个奇怪的buttonValue 属性并绘制Shape。 repaint() 当然应该在某个地方调用。我讨厌期末考试。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-02
      • 2016-06-02
      • 1970-01-01
      • 1970-01-01
      • 2016-06-07
      • 2012-04-20
      • 1970-01-01
      相关资源
      最近更新 更多