在 Java 中单击按钮在 JPanel 中绘制一条线

Posted

技术标签:

【中文标题】在 Java 中单击按钮在 JPanel 中绘制一条线【英文标题】:Draw a line in a JPanel with button click in Java 【发布时间】:2011-08-13 11:05:04 【问题描述】:

我想在 JPanel 中画一条线。 这是我的 GUI,我想在 JPanel 中添加一条白色的线。

我找到了很多例子,但问题是如何使用它。

在许多示例中,它们总是在从 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);

那么如何使用这些线......

提前致谢。

最好的问候,

阿里

【问题讨论】:

1) 类名应该是EachWordUpperCase,所以circuit 应该是Circuit 2) setBounds(100, 100, 559, 332) 了解如何使用布局。 3) 最好有JFrame 的实例,而不是扩展它。 4) “他们绘制了一个从 JPanel 延伸的 JFrame。”废话。这是不可能的。 5) JLabel label_1 = new JLabel("New label") 从描述/屏幕截图来看,这些旨在用作按钮。为什么不使用JButton? 6) 为了尽快获得更好的帮助,请发帖SSCCE。 【参考方案1】:

使用以下方法绘制线条可能更容易:

    点击标记第一个端点 拖动以显示正在进行的行 发布以标记第二个端点

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

附录

    下面的例子实现了上面的大纲。 我更新了示例以展示如何使用按钮面板来影响绘图。 另请参阅此相关 example,它使用带有键绑定的 Action 接口。 我已更新此示例以使用 Key Bindings

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://***.com/questions/6991648
 * @see https://***.com/questions/6887296
 * @see https://***.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 扩展而来。 您是要创建一个新行还是只移动现有行? 我只想在一个方向上画一条线。 啊,正如@Vincent Ramdhanie 在说Etch A Sketch 时所建议的那样,您想在四个方向之一上移动一个端点。 我已经更新了示例,展示了一种让按钮控制绘图的方法。【参考方案2】:

这会像蚀刻草图一样工作吗?然后你需要跟踪该点的当前位置。

   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。 :-)【参考方案3】:

触发图形有一个简单的答案:例如下面的代码可以放在点击事件中,用于在 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 您是对答案投反对票还是错字? (即 getGrahics() ) @cagcowboy 否决了答案(错字仅在我的评论中;-) @kleopatra 啊,很公平,我以为你在否决一个错字……我认为这很苛刻,因为意思很清楚。不过,如果答案不正确,那么..... @kleopatra 是对的。最好覆盖paintComponent() 以访问图形上下文并在ActionListener 中调用repaint()。见Performing Custom Painting

以上是关于在 Java 中单击按钮在 JPanel 中绘制一条线的主要内容,如果未能解决你的问题,请参考以下文章

Java JPanel repaint() 问题?

Java Swing:在 JPanel 的组件下绘制?

无法移除组件并重新绘制

Java Swing 在单击我要删除的 jpanel 中存在的 Jbutton 时删除 Jpanel

当我绘制另一个矩形时,如何保留我在 Jpanel 上绘制的矩形?

在 java swing 组件上绘制边框