Java中通过按钮点击在JPanel上绘制线条

20
我想在JPanel中画一条线。 这是我的GUI,我希望在JPanel中有一条白色的线。

enter image description here

我发现很多例子,但问题是如何使用它。
在许多示例中,它们总是在扩展自JPanel的JFrame中进行绘制。
我想将面板添加到框架中,并添加一些按钮以在许多方向上绘制线条,并使用中心的X按钮清除JPanel。
这是界面的代码:
import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.Color;
import javax.swing.JScrollPane;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;


public class circuit extends JFrame {

 private JPanel contentPane;

 /**
  * Launch the application.
  */
 public static void main(String[] args) {
  EventQueue.invokeLater(new Runnable() {
   public void run() {
    try {
     circuit frame = new circuit();
     frame.setVisible(true);
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  });
 }

 /**
  * Create the frame.
  */
 public circuit() {
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  setBounds(100, 100, 559, 332);
  contentPane = new JPanel();
  contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
  setContentPane(contentPane);
  contentPane.setLayout(null);

  JScrollPane scrollPane = new JScrollPane();
  scrollPane.setBounds(10, 21, 359, 255);
  contentPane.add(scrollPane);

  JPanel panel = new JPanel();
  scrollPane.setViewportView(panel);
  panel.setBackground(Color.WHITE);

  JLabel label = new JLabel("New label");
  label.addMouseListener(new MouseAdapter() {
   @Override
   public void mouseClicked(MouseEvent arg0) {


    /////////////


   }
  });
  label.setIcon(new ImageIcon("C:\\Users\\achermen\\Desktop\\up.png"));
  label.setBounds(447, 66, 46, 48);
  contentPane.add(label);

  JLabel label_1 = new JLabel("New label");
  label_1.setIcon(new ImageIcon("C:\\Users\\achermen\\Desktop\\down.png"));
  label_1.setBounds(447, 159, 46, 48);
  contentPane.add(label_1);

  JLabel label_2 = new JLabel("New label");
  label_2.setIcon(new ImageIcon("C:\\Users\\achermen\\Desktop\\right.png"));
  label_2.setBounds(495, 112, 46, 48);
  contentPane.add(label_2);

  JLabel label_3 = new JLabel("New label");
  label_3.setIcon(new ImageIcon("C:\\Users\\achermen\\Desktop\\left.png"));
  label_3.setBounds(398, 112, 46, 48);
  contentPane.add(label_3);

  JLabel label_4 = new JLabel("New label");
  label_4.setIcon(new ImageIcon("C:\\Users\\achermen\\Desktop\\1303860240_list-remove.png"));
  label_4.setBounds(447, 112, 46, 48);
  contentPane.add(label_4);
 }
}

这是绘制一条线的代码

public void paint(Graphics graphics)
{
    graphics.drawLine(10, 20, 300, 310);
}

所以如何使用这些行......
提前感谢。
最好的问候,
Ali

1
  1. 类名应该是每个单词首字母大写,所以circuit应该是Circuit
  2. setBounds(100, 100, 559, 332) 学习如何使用布局。
  3. 最好拥有一个JFrame的实例,而不是扩展它。
  4. “他们在扩展自JPanelJFrame中绘制。” 荒谬。这是不可能的。
  5. JLabel label_1 = new JLabel("New label") 根据描述/截图,这些标签旨在像按钮一样使用。为什么不使用JButton
  6. 为了更快地获得更好的帮助,请发布一个SSCCE
- Andrew Thompson
3个回答

22
可能更容易绘制线条的方法如下:
  1. 单击以标记第一个端点
  2. 拖动以显示正在绘制的线条
  3. 释放以标记第二个端点

这个相关的示例可能会提供一些额外的指导。

补充说明

  1. 下面的示例实现了上述概述。
  2. 我已更新示例以展示如何使用一组按钮来影响绘图。
  3. 另请参阅这个相关的示例,它使用了键绑定的Action接口。
  4. 我已更新此示例以使用键绑定

LinePanel.java

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

/**
 * @see https://dev59.com/D1rUa4cB1Zd3GeqPgRE2
 * @see https://dev59.com/3lnUa4cB1Zd3GeqPdsaT
 * @see https://stackoverflow.com/questions/5797965
 */
public class LinePanel extends JPanel {

    private MouseHandler mouseHandler = new MouseHandler();
    private Point p1 = new Point(100, 100);
    private Point p2 = new Point(540, 380);
    private boolean drawing;

    public LinePanel() {
        this.setPreferredSize(new Dimension(640, 480));
        this.addMouseListener(mouseHandler);
        this.addMouseMotionListener(mouseHandler);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.blue);
        g2d.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setStroke(new BasicStroke(8,
            BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
        g.drawLine(p1.x, p1.y, p2.x, p2.y);
    }

    private class MouseHandler extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            drawing = true;
            p1 = e.getPoint();
            p2 = p1;
            repaint();
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            drawing = false;
            p2 = e.getPoint();
            repaint();
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (drawing) {
                p2 = e.getPoint();
                repaint();
            }
        }
    }

    private class ControlPanel extends JPanel {

        private static final int DELTA = 10;

        public ControlPanel() {
            this.add(new MoveButton("\u2190", KeyEvent.VK_LEFT, -DELTA, 0));
            this.add(new MoveButton("\u2191", KeyEvent.VK_UP, 0, -DELTA));
            this.add(new MoveButton("\u2192", KeyEvent.VK_RIGHT, DELTA, 0));
            this.add(new MoveButton("\u2193", KeyEvent.VK_DOWN, 0, DELTA));
        }

        private class MoveButton extends JButton {

            KeyStroke k;
            int dx, dy;

            public MoveButton(String name, int code,
                    final int dx, final int dy) {
                super(name);
                this.k = KeyStroke.getKeyStroke(code, 0);
                this.dx = dx;
                this.dy = dy;
                this.setAction(new AbstractAction(this.getText()) {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        LinePanel.this.p1.translate(dx, dy);
                        LinePanel.this.p2.translate(dx, dy);
                        LinePanel.this.repaint();
                    }
                });
                ControlPanel.this.getInputMap(WHEN_IN_FOCUSED_WINDOW)
                    .put(k, k.toString());
                ControlPanel.this.getActionMap()
                    .put(k.toString(), new AbstractAction() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        MoveButton.this.doClick();
                    }
                });
            }
        }
    }

    private void display() {
        JFrame f = new JFrame("LinePanel");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.add(new ControlPanel(), BorderLayout.SOUTH);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new LinePanel().display();
            }
        });
    }
}

很多代码需要阅读!我的问题是如何在JPanel中画一条线。我找到了许多例子,但当我尝试更改界面并添加按钮时,我无法做到这一点,因为JFrame从JPanel继承。 - Ali Ben Messaoud
你想要创建一个新行还是只是移动现有的一行? - trashgod
我只想在一个方向上画一条线。 - Ali Ben Messaoud
啊,你想要将一个端点朝四个方向之一移动,就像@Vincent Ramdhanie所建议的那样,就像Etch A Sketch - trashgod
1
我已经更新了示例,以展示一种使按钮控制绘图的方法。 - trashgod
希望我能再次点赞。做了一些编辑,如果你更喜欢早期版本,可以回滚它们。 - Andrew Thompson

7

这是否像一个类似于画板玩具的工作方式?那么你需要跟踪点的当前位置。

   Point current = new Point(0, 0); //for example.

当用户点击按钮时,您可以根据需要简单地增加或减少x和y的值。
在左箭头上:
   current.setX(current.getX() - INC);

INC可能是指定绘制直线距离的长度的变量。也许是5?但请始终将第二个点p1设置为上一个位置。

创建一个扩展Canvas或JPanel的类来绘制,而不是直接在JFrame上绘制,这样会更容易。

例如:

public class Circuit extends JFrame {
  Point p1, current;

  JPanel drawPanel;

  //your other declarations

  public Circuit(){
         super();
         drawPanel = new DrawPanel();
         p1 = new Point(0, 0);
         current = new Point(0, 0);
         add(drawPanel, BorderLayout.CENTER);
         //your other code
  }

  class DrawingPanel extends JPanel{

        public void paintComponent(Graphics g){
             g.drawLine(p1.getX(), p1.getY(), current.getX(), current.getY());
        }
  }


   //the rest of your code.
}

+1 因为想到了 Etch-A-Sketch。 :-) - trashgod

1

触发图形的简单方法是:例如,以下代码可以放置在单击事件中,并用于在jPanel上绘制一些简单对象。在这种情况下,jPanel1位于选项卡jPanel7的一侧,并且靠近触发按钮。在netbeans GUI中执行此操作时,将代码放置在按钮动作事件内部。一旦出现了通常的错误,因为没有正确的导入,请右键单击代码并单击“修复导入”。太棒了,一切都好了 :-) 警告:面板的setBackground命令将覆盖图形对象。如果您不使用图形对象设置背景颜色,则看不到您的对象!

Graphics g = jPanel1.getGraphics();  
g.setColor(Color.blue);
    g.drawLine( 0, 50,  20, 50);
    g.setColor(Color.white); 
    g.fillRect(40, 50,  20, 20); 
    g.setColor(Color.blue); 
    g.drawRect(40, 50,  20, 20); 
    g.drawOval(80, 50,  20, 20); 
    g.setColor(Color.green); 
    g.fillOval(80, 50,  18, 18);   

这让你重新相信真爱 :-) 难点在于任何更改或重绘都会抹掉您的努力。这种方法被Java创始人明确反对。但在当前版本的Netbeans Swing中,由于锁定代码更改而使扩展jPanel变得困难,这种方法可能是您唯一的短期解决方案。为jPanel提供一个简单的持久图形扩展将成为当前Netbeans Swing环境中最受欢迎的补充,即图形面板。这将允许您拖放图形面板,然后开始使用该面板的事件驱动。其他40个IDE已经具备了此功能,似乎Java添加此功能的速度较慢。


@cagcowboy 不明白你怎么会给一个(在Swing上下文中)完全错误的答案点赞。 - kleopatra
@kleopatra 你是在给答案投反对票还是针对打字错误?(即 getGrahics()) - cagcowboy
@cagcowboy 给答案点了个踩(错别字只在我的评论里;-) - kleopatra
@kleopatra 哦,好的,我以为你是因为错别字而给我点了踩……我觉得那样有点过分,因为意思很清楚。不过,如果答案是错误的,那就…… - cagcowboy
@kleopatra是正确的。最好覆盖paintComponent()以访问图形上下文,并在ActionListener中调用repaint()。请参见执行自定义绘画 - trashgod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接