您的问题表明您尚不清楚 Swing GUI 中图形和绘图的工作原理。给你的一些建议:
- 不要让您的类扩展 java.awt.Frame,因为这没有任何意义。您不是在创建 AWT 框架窗口,也不需要这个。
- 创建一个扩展 JPanel 的类,并在其 paintComponent 方法中绘制,就像 Swing painting tutorials(现已添加链接)向您展示的那样。
- 您从不直接调用绘图代码,而是由 JVM 间接调用。
- 如果您想从 GUI 本身的外部进行绘制,请绘制到 BufferedImage,然后在 GUI 中显示该图像。
- 不要使用通过在 GUI 组件上调用
getGraphics() 获得的 Graphics 对象,因为这样获得的对象不会持续存在,这可能会导致您创建不稳定的图形或更糟——抛出 NullPointerException。
例如:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
@SuppressWarnings("serial")
public class LineDraw extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = 300;
public LineDraw() {
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use rendering hints to draw smooth lines
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// do drawing here
g.drawLine(10, 10, 20, 300);
}
private static void createAndShowGui() {
LineDraw mainPanel = new LineDraw();
JFrame frame = new JFrame("Line Draw");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
如果您想在程序运行时添加线条,请再次使用在 JPanel 的 paintComponent 方法中绘制的 BufferedImage。当您需要在 GUI 中添加新行时,分别使用 getGraphics() 或 createGraphics() 从 BufferedImage 中提取 Graphics 或 Graphics2D 对象(可以这样做),使用此 Graphics 对象进行绘制,dispose图形对象,并重新绘制 GUI。例如在下面的代码中,当按下按钮时,我通过在 JButton 的 ActionListener 中添加代码(实际上是它的 AbstractAction,它类似于 ActionListener 但更强大)来绘制一个新行:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
@SuppressWarnings("serial")
public class LineDraw extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = 300;
private BufferedImage img;
private int yDistance = 20;
private int deltaY = 10;
public LineDraw() {
img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
add(new JButton(new DrawLineAction("Draw Line", KeyEvent.VK_D)));
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// draw the buffered image here
if (img != null) {
g.drawImage(img, 0, 0, this);
}
// use rendering hints to draw smooth lines
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// do drawing here
g.drawLine(10, 10, 20, 300);
}
public void drawNewLines() {
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.BLACK);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
yDistance += deltaY;
g2.drawLine(10, 10, yDistance, PREF_H);
g2.dispose();
repaint();
}
private class DrawLineAction extends AbstractAction {
public DrawLineAction(String name, int mnemonic) {
super(name); // give button its text
putValue(MNEMONIC_KEY, mnemonic); // alt-hot key for button
}
@Override
public void actionPerformed(ActionEvent e) {
drawNewLines();
}
}
private static void createAndShowGui() {
LineDraw mainPanel = new LineDraw();
JFrame frame = new JFrame("Line Draw");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}