如何在 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
实例上的多个操作,不需要一直重新创建它,仅在创建新实例时)。然后,在您的JPanel
的paintComponent()
中,您只需将BufferedImage
实例绘制到JPanel
。使用此技术,您可以通过affine transformations 非常轻松地执行缩放、平移和旋转操作。
【讨论】:
感谢您的回答,我在几个示例中看到了这个,但不确定它做了什么。我试试看。 我觉得我对这一点的了解太多了,我对这些概念的了解还不够。 @Nick,使用方便的绘图方法等查看缓冲图像,例如像素值的美化二维数组等。您的应用程序通过缓冲图像的Graphics
上下文绘制到缓冲图像 - 和您的 JPanel 在准备好更新时使用该图像进行自我更新(当操作系统重绘它时)。在您的情况下,这是最简单的解决方案;对于光栅图形。一个更复杂的解决方案是保留 Andrew 建议的绘图元素数组,而不是缓冲图像,并在 paintComponent
方法中绘制这些元素; 矢量图形解决方案。以上是关于如何在 JPanel 中绘图? (摇摆/图形Java)的主要内容,如果未能解决你的问题,请参考以下文章
如何在不覆盖JFrame的情况下将JPanel图形添加到JFrame