Graphics2D and JComponent

3

我对Swing/G2D不是很熟悉,请耐心等待。 我有一个类,它是我的GUI上的组件(用于绘制的画布):

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

public class DrawPanel extends JComponent{
public void paintComponent(Graphics g){
    Graphics2D g2 = (Graphics2D) g;

    g2.setPaint(Color.black);
    g2.fillRect(0, 0, getWidth(), getHeight());

    BrushStroke bs = new BrushStroke();     
    add(bs);
}
}

我一直在尝试将以下内容添加到上面的JComponent中:

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

public class BrushStroke extends JComponent{
public void paintComponent(Graphics g){
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);

    g2.setPaint(Color.red);
    g2.fillOval(0, 0, 10, 10);          
}
}

画笔在绘制面板上没有显示。

我一直在寻找答案,但每个示例似乎都是自相矛盾的。

如果有人尝试过我正在尝试的事情,那么帮助将不胜感激。另外,如果我完全走错了方向,请指出。


你不应该使用 JComponent 来绘制画笔轨迹。 - Chris Dennett
@ChrisDennett,使用JComponent进行自定义绘制没有任何问题。默认情况下,组件将是透明的。如果您想要一个不透明的组件,那么您可能会扩展JPanel,这样您就不必担心背景绘制了。 - camickr
2个回答

3
  1. 不要在任何绘制方法中向面板添加组件。当Swing确定需要绘制组件时,将调用绘制方法。因此,您会多次将该组件添加到面板中。

  2. 当您进行自定义绘制时,您需要负责覆盖getPreferredSize()方法以提供组件的大小。这样布局管理器就可以正确地定位组件。如果不这样做,则首选大小为0,因此无需绘制任何内容。

请阅读Swing教程中有关自定义绘制的部分,了解更多信息和示例。


2
JComponent.add方法中,文档中写道:
请注意:如果将组件添加到已显示的容器中,则必须在该容器上调用validate以显示新组件。如果正在添加多个组件,则可以通过在所有组件添加后仅调用一次validate来提高效率。
在向DrawPanel添加元素后,应刷新它。注意不要在方法中执行此操作,否则会导致无限递归。
请改为执行以下操作:
DrawPanel drawPanel = new DrawPanel();
drawPanel.add(new BrushStroke());
drawPanel.repaint();

编辑 这里提供一个完全可行的解决方案(扩展JPanel而不是JComponent)。

public static void main(String[] args){
   JFrame frame = new JFrame();
   DrawPanel drawPanel = new DrawPanel();
   drawPanel.add(new BrushStroke());
   frame.getContentPane().add(drawPanel);
   frame.pack();
   frame.setVisible(true);
}
class DrawPanel extends JPanel{
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setPaint(Color.black);
        g2.fillRect(0, 0, getWidth(), getHeight());
    }
    @Override
    public  Dimension getPreferredSize(){
        return new Dimension(100, 100);
    }
}
class BrushStroke extends JPanel{
    public void paintComponent(Graphics g){
        this.setOpaque(false);
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setPaint(Color.red);
        g2.fillOval(0, 0, 10, 10); 
    }
    @Override
    public  Dimension getPreferredSize(){
        return new Dimension(10, 10);
    }
}

输出结果如下所示:

enter image description here


该输出结果如上图所示。

嗨,谢谢回复。我会尝试这个方法。不过我有一个问题。我的原始实现是考虑将DrawPanel转储到缓冲区中。在这个新的方案中,我该如何实现呢?谢谢。 - Jack H
没问题。你所说的将DrawPanel转储到缓冲区是什么意思? - GETah
不,你不应该在paintComponent()的结尾处执行super.paint()。这会导致无限循环,因为paint()会调用paintComponent()。此外,你不应该直接在组件上调用paint()。你应该使用repaint()告诉Swing需要重新绘制组件。 - camickr
1
@VisionIncision 明天我会试一下你的代码,然后告诉你结果 :) 我会保持更新。 - GETah
1
@VisionIncision 很好的问题。JPanel可能实现了一些JComponent没有的东西(我不太熟悉JComponents :))。 - GETah
显示剩余6条评论

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