請注意,如果您使用組件上的getGraphics()
來獲取Graphics上下文,則獲得的圖形將不會持續。例如,在下面的代碼中,您會看到如果按下該按鈕,則會出現一個藍色矩形,但如果GUI最小化並稍後調整大小,則該矩形會消失。
另外,按我的意見:在JPanel的paintComponent方法裏面
- 平局。
- 使用Swing Timer不是一個(true)循環。
- 在該Timer中,更改圖形JPanel的狀態(更改其字段),然後調用repaint()。
- 然後讓paintComponent方法使用這些字段來告訴它如何繪製。
- 不要忘記在你的覆蓋範圍內調用super的繪畫方法。
例如:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class UnstableStableGraphics extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 400;
private static final int GAP = 20;
public UnstableStableGraphics() {
add(new JButton(new DrawBlueRectAction()));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
int w = PREF_W/2 - 2 * GAP;
int h = PREF_H - 2 * GAP;
g.fillRect(GAP, GAP, w, h);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class DrawBlueRectAction extends AbstractAction {
public DrawBlueRectAction() {
super("Draw Unstable Blue Rectangle");
}
@Override
public void actionPerformed(ActionEvent arg0) {
Graphics g = getGraphics();
g.setColor(Color.BLUE);
int x = PREF_W/2 + GAP;
int w = PREF_W/2 - 2 * GAP;
int h = PREF_H - 2 * GAP;
g.fillRect(x, GAP, w, h);
g.dispose();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
UnstableStableGraphics mainPanel = new UnstableStableGraphics();
JFrame frame = new JFrame("UnstableStableGraphics");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
說了這麼多,這是完全正常的使用要求一個BufferedImage通過getGraphics()
獲得Graphics對象(只要你處理圖形的完成時對象,以完成後節省資源),然後將該圖像顯示在paintComponent方法中,通常作爲背景圖像顯示。但是,通常我會在BufferedImage上調用createGraphics()
,因爲它返回的是更強大的Graphics2D對象,而不是Graphics對象。
例如,包括使用的背景圖像,子畫面圖像和一個Swing定時器:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
@SuppressWarnings("serial")
public class BackgroundExample extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final int SPRITE_W = 20;
private static final Color SPRITE_COLOR = Color.RED;
private static final int TIMER_DELAY = 20;
private Image background = null;
private Image sprite = null;
private int spriteX = 0;
private int spriteY = 0;
public BackgroundExample() {
background = createBackground();
sprite = createSprite();
new Timer(TIMER_DELAY, new TimerListener()).start();
}
private Image createSprite() {
BufferedImage img = new BufferedImage(SPRITE_W, SPRITE_W, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setColor(SPRITE_COLOR);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int x = 1;
int y = 1;
int width = SPRITE_W -2;
int height = SPRITE_W - 2;
g2.fillOval(x, y, width, height);
g2.dispose();
return img;
}
private Image createBackground() {
BufferedImage img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.GREEN);
g2.fillRect(0, 0, PREF_W, PREF_H);
g2.setColor(Color.GRAY);
int x = 0;
int y = 0;
g2.fillRect(x, y, 2 * SPRITE_W, 2 * SPRITE_W);
x = PREF_W - 2 * SPRITE_W;
g2.fillRect(x, y, 2 * SPRITE_W, 2 * SPRITE_W);
y = PREF_H - 2 * SPRITE_W;
g2.fillRect(x, y, 2 * SPRITE_W, 2 * SPRITE_W);
x = 0;
g2.fillRect(x, y, 2 * SPRITE_W, 2 * SPRITE_W);
g2.dispose();
return img;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
g.drawImage(background, 0, 0, this);
}
if (sprite != null) {
g.drawImage(sprite, spriteX, spriteY, this);
}
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
} else {
return new Dimension(PREF_W, PREF_H);
}
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
spriteX++;
spriteY++;
repaint();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
BackgroundExample mainPanel = new BackgroundExample();
JFrame frame = new JFrame("BackgroundExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
這不是實現這種方式。閱讀[教程](https://docs.oracle.com/javase/tutorial/uiswing/painting/)。 – user1803551
1.在JPanel的paintComponent方法中繪製。 2.使用Swing Timer而不是'while(true)'循環。 3.在該Timer中,更改圖形JPanel的狀態(更改其字段),然後調用repaint()。 4.然後讓paintComponent方法使用這些字段來告訴它如何繪製。 5.不要忘記在你的覆蓋範圍內調用super的繪畫方法。 –
@DontKnowMuchButGettingBetter,user1803551感謝它現在的作品! – Rof