paintComponent 问题 Java - Swing

issues with paintComponent Java - Swing

我正在尝试编写一个 swing gui,我可以通过按下两个不同的 JMenuItem、圆形和矩形在随机位置绘制形状。 我让它工作了,但我用了

Graphics2D gg = (Graphics2D) canvas.getGraphics();

有人建议我使用并覆盖 paintComponent()。所以我几个小时前就开始尝试了:D 我知道有很多关于这个的问题,但我真的读了很多,尝试和搜索但我无法帮助自己..

请查看我的 RandomDrawer Class,我发现我必须在那里实现 paintComponent()(我希望至少如此)。 进一步在下一个方法

public void actionPerformed(ActionEvent e)

我开始知道发生了什么动作,我可以或者我怎样才能告诉他之后画画?还是我的整个方法有缺陷?

这是我的代码。

感谢您的包容,非常感谢。

package plotterpackage;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.Random;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.border.BevelBorder;
import javax.swing.text.JTextComponent;



public class PlotterApp implements ComponentListener  {
private JFrame frame;
private JPanel canvas;
private JPanel statusBar;
private JTextField status;
/**
 * Public default constructor.    
 */
public PlotterApp() {
    initialize();
}
/**
 * Start of the application.
 * @param args command line arguments
 */
public static void main(String[] args) {
    PlotterApp app = new PlotterApp();
    app.start();
}
/**
 * Initialize the application.
 */
protected void initialize() {
    frame = new JFrame("Main");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.setBounds(50,50, 50+640, 50+480);
    frame.setBackground(Color.GREEN);
    frame.setJMenuBar(createMenuBar());

    frame.getContentPane().add(createContent(), BorderLayout.CENTER);
    frame.getContentPane().add(createStatusBar(),BorderLayout.SOUTH);        
}
/**
 * Start the graphical user interface.
 */
public void start() {
    // show the GUI
    frame.setVisible(true);
    status.setText("Application started");
}
/**-*
 * Internal helper to create the main content.
 * @return component with application content.
 */
protected JComponent createContent() {
    canvas = new JPanel();
    canvas.addMouseListener(new Painter());
    canvas.addMouseMotionListener(new Painter());
    canvas.addComponentListener(this);
    canvas.setBackground(new Color(128,218,255));
    canvas.setForeground(Color.RED);
    canvas.setBorder(new BevelBorder(BevelBorder.LOWERED));
    return canvas;
}
/**
 * Internal helper to create the statusbar and -fields.
 * @return component with status/bar.
 */    
protected JComponent createStatusBar() {
    FlowLayout layout = new FlowLayout(FlowLayout.LEFT);
    layout.setHgap(5);

    statusBar = new JPanel(layout);
    statusBar.add(new JLabel("Status: "));

    status = new JTextField();
    status.setPreferredSize(new Dimension(400,25));
    status.setEditable(false);
status.setBorder(newBevelBorder(BevelBorder.RAISED,Color.MAGENTA,Color.LIGHT_GRAY));
    status.getInsets().set(2, 10, 2, 10);
    statusBar.add(status);

    return statusBar;
}
/**
 * Internal helper to create the frames menubar.
 * @return menu bar 
 */
protected JMenuBar createMenuBar() {
    JMenuBar mb = new JMenuBar();
    JMenuItem item;
    JMenu menu;
    // Action menu
    menu = new JMenu("Actions");
    mb.add(menu);
    item = new JMenuItem("Draw RandomCircle");
    item.addActionListener(new RandomDrawer());
    menu.add(item);

    item = new JMenuItem("Draw RandomRectangle");
    item.addActionListener(new RandomDrawer());
    menu.add(item);

    menu.addSeparator();
    item = new JMenuItem("Exit");
    item.addActionListener(new AppCloser());
    menu.add(item);

    // Color menu not used so far
    menu = new JMenu("Colors");        
    mb.add(menu);
    // Help menu not used so far
    menu = new JMenu("Help");        
    mb.add(menu);

    return mb;
}

class AppCloser implements ActionListener {
    /* (non-Javadoc)
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("application finished, bye-bye... ");
        frame.setVisible(false);
        frame.dispose();
        System.exit(0);
    }        
}

class RandomDrawer extends JPanel implements ActionListener {
    /* (non-Javadoc)
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */ 
    @Override
    protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          Graphics2D g2 = (Graphics2D) g;
          g2.setColor(Color.BLACK);
          g2.drawOval(100, 100, 100, 100);  
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Random generator = new Random();
        int x = generator.nextInt(100)+100;
        int y = generator.nextInt(100)+100;
        int w;

        if (e.getActionCommand()==("Draw RandomCircle")) {
            System.out.printf("x = %d y = %d\n", x, y);
            //status.setText(String.format("rnd draw x:  y: "));
            //gg.setColor(Color.BLACK);
            //gg.drawOval(x, y, generator.nextInt(x), generator.nextInt(y));    
        }

        else if (e.getActionCommand()==("Draw RandomRectangle")) {
            System.out.printf("x = %d y = %d\n", x, y);
            //status.setText(String.format("rnd draw x:  y: "));
            //Graphics2D gg = (Graphics2D) canvas.getGraphics();
            //gg.setColor(Color.BLACK);
            //gg.drawRect(x, y, generator.nextInt(x), generator.nextInt(y));    
        }
    }
}


class Painter extends MouseAdapter implements MouseMotionListener {

  Point start, end;
  int startX, startY, oldX, oldY, oldWidth, oldHeight;

  public void mousePressed(MouseEvent e) {
    start = e.getPoint();
    oldX = startX;
    oldY = startY;
    startX = e.getX();
    startY = e.getY();
    status.setText(String.format("Mouse start: " + start));
  }

  public void mouseDragged(MouseEvent e) {
    Graphics2D gc = (Graphics2D)canvas.getGraphics();
    gc.setColor(new Color(128, 218, 255));
    gc.drawOval(oldX, oldY, oldWidth, oldHeight);
    System.out.printf("oldWidth ist = %3d, oldHeight ist = %3d\n", oldWidth, oldHeight);
    oldWidth = e.getX();
    oldHeight = e.getY();
    gc.setColor(Color.BLACK);
    gc.drawOval(startX, startY, e.getX(), e.getY());
  }

  public void mouseReleased(MouseEvent e) {
    end = e.getPoint();
    status.setText(String.format("Mouse end: " + end));
  }
}


@Override
public void componentHidden(ComponentEvent e) {
    // TODO Auto-generated method stub

}
@Override
public void componentMoved(ComponentEvent e) {
    // TODO Auto-generated method stub

}
@Override
public void componentResized(ComponentEvent e) {
    // TODO Auto-generated method stub

}
@Override
public void componentShown(ComponentEvent e) {
    // TODO Auto-generated method stub

}
}

您可以将形状放在某种容器中,例如 ArrayList。 在 paintComponent(Graphics g) 中,你应该从该列表中绘制每个形状,在 actionPerformed(ActionEvent e) 中,你应该使用 repaint () 对象上的方法,您在其上绘制。

不要做...

Graphics2D gg = (Graphics2D) canvas.getGraphics();

这不是自定义绘画的方式。 Swing 会在需要绘制某些东西时询问您,您应该重新绘制组件的当前状态。

首先查看 Painting in AWT and Swing and Performing Custom Painting 了解更多详情

基本上,您需要覆盖JPanelpaintComponent方法(确保首先调用super.paintComponent)并绘制组件的当前状态。

您需要以对您的(List 或自定义对象甚至 Image)最有用的任何形式存储状态

您可以在更改状态后通过调用 repaint 请求 API 更新 UI