如何在 JPanel 中绘图? (摇摆/图形Java)

Posted

技术标签:

【中文标题】如何在 JPanel 中绘图? (摇摆/图形Java)【英文标题】:How to draw in JPanel? (Swing/graphics Java) 【发布时间】:2011-09-01 09:39:27 【问题描述】:

我正在做一个项目,我正在尝试制作一个绘画程序。 到目前为止,我已经使用 Netbeans 创建了 GUI 并设置了程序。

到目前为止,我可以调用所有必要的协调来在其中绘制,但我对如何在其中实际绘制感到非常困惑。

在我的代码接近尾声时,我尝试在面板内绘图失败。

谁能解释/展示如何在这样的示例中使用图形?

我发现的所有示例都创建了一个类并使用JPanel 扩展它,但我不知道我是否可以这样做,因为它是在 netbeans 中生成的。

我需要在JPanel 内,在我的JFrame 内绘图。我不知道把图形类放在哪里。

JavaPaintUI 类

package javapaint;

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

public class JavaPaintUI extends javax.swing.JFrame 

public JavaPaintUI() 
    initComponents();



private void initComponents() 


    jPanel2 = new javax.swing.JPanel();

    jPanel2.setBackground(new java.awt.Color(255, 255, 255));
    jPanel2.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
    jPanel2.addMouseListener(new java.awt.event.MouseAdapter() 
        public void mousePressed(java.awt.event.MouseEvent evt) 
            jPanel2MousePressed(evt);
        
        public void mouseReleased(java.awt.event.MouseEvent evt) 
            jPanel2MouseReleased(evt);
        
    );
    jPanel2.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() 
        public void mouseDragged(java.awt.event.MouseEvent evt) 
            jPanel2MouseDragged(evt);
        
    );
    pack();
// </editor-fold>                        

int currentX, currentY, oldX, oldY;

private void jPanel2MouseDragged(java.awt.event.MouseEvent evt)                                      
    if (tool == 1) 
        currentX = evt.getX();
        currentY = evt.getY();
        oldX = currentX;
        oldY = currentY;
        System.out.println(currentX + " " + currentY);
        System.out.println("PEN!!!!");
    

                                    

private void jPanel2MousePressed(java.awt.event.MouseEvent evt)                                      
    oldX = evt.getX();
    oldY = evt.getY();
    System.out.println(oldX + " " + oldY);
                                    


//mouse released//
private void jPanel2MouseReleased(java.awt.event.MouseEvent evt)                                       
    if (tool == 2) 
        currentX = evt.getX();
        currentY = evt.getY();
        System.out.println("line!!!! from" + oldX + "to" + currentX);
    
                                     

//set ui visible//
public static void main(String args[]) 
    java.awt.EventQueue.invokeLater(new Runnable() 

        public void run() 
            new JavaPaintUI().setVisible(true);
        
    );


// Variables declaration - do not modify                     
private javax.swing.JPanel jPanel2;
// End of variables declaration                   

class jPanel2 extends JPanel 

    @Override
    public void paintComponent(Graphics g) 
        super.paintComponent(g);

        g.drawString("BLAH", 20, 20);
        g.drawRect(200, 200, 200, 200);
    


屏幕截图

整个东西是JFrame,中间的白色部分是jPanel2,这是我想画的。

【问题讨论】:

一个非常简单的Java绘画例子,请看我在这个帖子里的回复:changing-jpanel-graphics-g-color-drawing-line。此外,不要与 NetBeans 生成的代码混为一谈,因为学习自己首先编写 Swing/图形代码会带来即时和长期的收益。 “我找到的所有示例都创建了一个类并使用 jpanel 扩展它,但我不知道我是否可以这样做,因为它是在 netbeans 中生成的。”那么这是您的基本问题,不了解如何使用您的自动 IDE。在这种情况下,我建议将您不理解的 IDE 放在一边,它似乎已经抓住了您的腹股沟短毛,并学习如何编写 Java 代码。也许稍后,在 IDE 的 F1 工具的帮助下,您将了解如何使用自定义组件。但暂时不要考虑它,因为它是您不需要的额外复杂功能。 当然,我在几个网站上意识到了这一点,因为作弊者不会赢:) 现在比以前更感谢大家 【参考方案1】:

Bijaya Bidari 的代码变体已被 Java 8 接受,而没有关于构造函数中可覆盖的方法调用的警告:

public class Graph extends JFrame 
    JPanel jp;

    public Graph() 
        super("Simple Drawing");
        super.setSize(300, 300);
        super.setDefaultCloseOperation(EXIT_ON_CLOSE);

        jp = new GPanel();
        super.add(jp);
    

    public static void main(String[] args) 
        Graph g1 = new Graph();
        g1.setVisible(true);
    

    class GPanel extends JPanel 
        public GPanel() 
            super.setPreferredSize(new Dimension(300, 300));
        

        @Override
        public void paintComponent(Graphics g) 
            super.paintComponent(g);
            //rectangle originated at 10,10 and end at 240,240
            g.drawRect(10, 10, 240, 240);
                    //filled Rectangle with rounded corners.    
            g.fillRoundRect(50, 50, 100, 100, 80, 80);
        
    

【讨论】:

【参考方案2】:

这是一个简单的例子。我想这很容易理解:

import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Graph extends JFrame 
JFrame f = new JFrame();
JPanel jp;


public Graph() 
    f.setTitle("Simple Drawing");
    f.setSize(300, 300);
    f.setDefaultCloseOperation(EXIT_ON_CLOSE);

    jp = new GPanel();
    f.add(jp);
    f.setVisible(true);


public static void main(String[] args) 
    Graph g1 = new Graph();
    g1.setVisible(true);


class GPanel extends JPanel 
    public GPanel() 
        f.setPreferredSize(new Dimension(300, 300));
    

    @Override
    public void paintComponent(Graphics g) 
        //rectangle originates at 10,10 and ends at 240,240
        g.drawRect(10, 10, 240, 240);
        //filled Rectangle with rounded corners.    
        g.fillRoundRect(50, 50, 100, 100, 80, 80);
    

输出如下:

【讨论】:

您可以使用extends JFrame 或使用JFrame f = new JFrame();。通过同时执行这两个操作,您可以创建 2 个 JFrame 对象。你也可以省略g.drawRect(10, 10, 240, 240);【参考方案3】:

注意额外的 cmets。

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

class JavaPaintUI extends JFrame 

    private int tool = 1;
    int currentX, currentY, oldX, oldY;

    public JavaPaintUI() 
        initComponents();
    

    private void initComponents() 
        // we want a custom Panel2, not a generic JPanel!
        jPanel2 = new Panel2();

        jPanel2.setBackground(new java.awt.Color(255, 255, 255));
        jPanel2.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
        jPanel2.addMouseListener(new MouseAdapter() 
            public void mousePressed(MouseEvent evt) 
                jPanel2MousePressed(evt);
            
            public void mouseReleased(MouseEvent evt) 
                jPanel2MouseReleased(evt);
            
        );
        jPanel2.addMouseMotionListener(new MouseMotionAdapter() 
            public void mouseDragged(MouseEvent evt) 
                jPanel2MouseDragged(evt);
            
        );

        // add the component to the frame to see it!
        this.setContentPane(jPanel2);
        // be nice to testers..
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
    // </editor-fold>

    private void jPanel2MouseDragged(MouseEvent evt) 
        if (tool == 1) 
            currentX = evt.getX();
            currentY = evt.getY();
            oldX = currentX;
            oldY = currentY;
            System.out.println(currentX + " " + currentY);
            System.out.println("PEN!!!!");
        
    

    private void jPanel2MousePressed(MouseEvent evt) 
        oldX = evt.getX();
        oldY = evt.getY();
        System.out.println(oldX + " " + oldY);
    


    //mouse released//
    private void jPanel2MouseReleased(MouseEvent evt) 
        if (tool == 2) 
            currentX = evt.getX();
            currentY = evt.getY();
            System.out.println("line!!!! from" + oldX + "to" + currentX);
        
    

    //set ui visible//
    public static void main(String args[]) 
        EventQueue.invokeLater(new Runnable() 
            public void run() 
                new JavaPaintUI().setVisible(true);
            
        );
    

    // Variables declaration - do not modify
    private JPanel jPanel2;
    // End of variables declaration

    // This class name is very confusing, since it is also used as the
    // name of an attribute!
    //class jPanel2 extends JPanel 
    class Panel2 extends JPanel 

        Panel2() 
            // set a preferred size for the custom panel.
            setPreferredSize(new Dimension(420,420));
        

        @Override
        public void paintComponent(Graphics g) 
            super.paintComponent(g);

            g.drawString("BLAH", 20, 20);
            g.drawRect(200, 200, 200, 200);
        
    

屏幕截图

其他示例 - 更适合多条线和多条线段

HFOE 将一个很好的链接作为对该线程的第一条评论。 Camickr 还在Custom Painting Approaches 文章中描述了主动绘画与绘画到BufferedImage

另请参阅使用painting in a BufferedImage 的这种方法。

【讨论】:

@Andrew,您回答的唯一一件事就是重命名内部类......我的回答为如何编写绘图程序提供了一个可行的解决方案。我不是在攻击你的答案。我是说这可能是一个单行评论,并且会产生同样的影响。问题是“任何人都可以在这样的示例中解释/展示如何使用图形吗?”现在,你的答案能回答吗? @Yanick:“你回答的唯一事情就是重命名内部类。”检查从以下开始的 cmets 以查看对源代码的 5 值得注意的更改。 // 我们想要一个自定义的 Panel2,而不是一个通用的 JPanel! // 将组件添加到框架中以查看它! // 善待测试人员.. // 这个类名很容易混淆,因为它也被用作 // 属性的名称! // 设置自定义面板的首选尺寸。 我已经阅读了您的“修改”(阅读我上次评论的更新);它仍然没有回答这个问题。我真的很惊讶你有一个赞成票。 +1 用于通过调整原始代码用工作代码回答问题。 感谢您的回答,但是当我进行这些更改时,它会覆盖我所有其他 UI 和 Swing 组件(可能是所有 netbeans 的东西)。现在可以在使用 g.drawLine(oldX, oldY, currentX, currentY); 移动鼠标时让它绘制。但如果我把它放在我的paintcomponent 后面跟着repaint() 它只会临时画线。 I want it do draw lines similar to how i have it output (when pen is selected, every movement paints a line from new and previous cords and when the line is selected it paints a line when released from the first point to the second point) 【参考方案4】:

使用图形用户界面时,您需要记住在窗格上绘图是在Java AWT/Swing event queue 中完成的。您不能只在paint()/paintComponent()/etc 之外使用Graphics 对象。方法。

但是,您可以使用一种称为“Frame buffering”的技术。基本上,您需要有一个 BufferedImage 并直接在其上绘制(请参阅它的 createGraphics() 方法;那个图形上下文您可以保留并重用于同一个 BufferedImage 实例上的多个操作,不需要一直重新创建它,仅在创建新实例时)。然后,在您的JPanelpaintComponent() 中,您只需将BufferedImage 实例绘制到JPanel。使用此技术,您可以通过affine transformations 非常轻松地执行缩放、平移和旋转操作。

【讨论】:

感谢您的回答,我在几个示例中看到了这个,但不确定它做了什么。我试试看。 我觉得我对这一点的了解太多了,我对这些概念的了解还不够。 @Nick,使用方便的绘图方法等查看缓冲图像,例如像素值的美化二维数组等。您的应用程序通过缓冲图像的 Graphics 上下文绘制到缓冲图像 - 和您的 JPanel 在准备好更新时使用该图像进行自我更新(当操作系统重绘它时)。在您的情况下,这是最简单的解决方案;对于光栅图形。一个更复杂的解决方案是保留 Andrew 建议的绘图元素数组,而不是缓冲图像,并在 paintComponent 方法中绘制这些元素; 矢量图形解决方案。

以上是关于如何在 JPanel 中绘图? (摇摆/图形Java)的主要内容,如果未能解决你的问题,请参考以下文章

如何在将鼠标放在图形元素顶部的画布上添加 JPanel?

如何在不覆盖JFrame的情况下将JPanel图形添加到JFrame

JPanel 图形清除和重绘?

如何将 BufferedImage 绘制到 JPanel

JTextFields 在 JPanel 上的活动绘图之上,线程问题

将处理 3 添加到 Jpanel