【问题标题】:JPanel Repaint Not ClearingJPanel 重绘未清除
【发布时间】:2011-11-15 12:22:48
【问题描述】:

我有一个自定义的抽象类“Panel”,它扩展了 JPanel。两者在绘画时没有太大区别。我有一个面板,我正在通过更新图像的 x 值来模拟动画。我现在有两个动画,一个可以正确重绘,另一个不能。这是给没有的。有效的标记为 A,无效的标记为 B。

A 和 B 遵循相同的格式。更新 Panel 上的某个变量,调用 update(Panel 中调用 PaintComponent 的方法),然后调用 repaint。它会调用 repaint after,因为这个问题之前是 A 的问题,并且已经通过这种方式解决了。

A:更新图像变量。 B:更新图像的 x 变量。

问题:重绘不会清除旧图像位置,因此屏幕上会出现混乱。

我尝试过的:

  • 我见过很多提到的 super.PaintComponent(g),但是这个 没有解决问题。
  • 我尝试更改重绘/更新方法的顺序 调用。
  • 重绘根本不会更新面板。 (可能是因为 绘画在 PaintComponent 中完成)

任何帮助将不胜感激。

代码:

面板:

public Panel (boolean visible){
    super();
    this.setLayout(new BorderLayout(640, 416));//sets the Layout type of the panel
    this.setOpaque(false);//Makes it so that the panel underneath can be seen where images aren't drawn
    this.setVisible(visible);
    ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    gs = ge.getDefaultScreenDevice();
    gc = gs.getDefaultConfiguration();
}

public void paintComponent (Graphics g){
    setUp();
    drawOff();
    setDown(g);
}

private void setUp(){
    off_screen = gc.createCompatibleImage(getSize().width, getSize().height, Transparency.TRANSLUCENT);
    buffer = off_screen.createGraphics();
}

protected abstract void drawOff();

private void setDown(Graphics g){
    g.drawImage(off_screen,0,0,this);
    off_screen.flush(); 
}

public void update(){
    paintComponent(this.getGraphics());
}

动画方法(mg 是有问题的面板):

private void battleStart(User user) {
    for (int i = 0; i < user.battle.length; i++) {
        mg.battleStart(user.battleStart(i));
        mg.update();
        try {
            Thread.sleep(150);
        } catch (Exception e) {

        }
        mg.repaint();
    }
}

private void animateStart(User user){
    for (int i = 0; i < 10; i++){
        mg.x = mg.x + 10;
        mg.update();
        try {
            Thread.sleep(100);
        } catch (Exception e) {

        }
        mg.repaint();
    }
}

【问题讨论】:

标签: java swing jpanel repaint


【解决方案1】:

我认为你的设计有问题,这就是为什么事情不工作。我不太确定你的非抽象 JPanel 是如何工作的,但考虑让你的父 JPanel 更符合这些思路:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class MyPanel extends JPanel {
   private GraphicsEnvironment ge;
   private GraphicsDevice gs;
   private GraphicsConfiguration gc;
   private BufferedImage offScreen;

   public MyPanel(boolean visible) {
      super();
      this.setLayout(new BorderLayout(640, 416)); // strange constants for this layout.
      this.setOpaque(false);
      this.setVisible(visible);
      ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
      gs = ge.getDefaultScreenDevice();
      gc = gs.getDefaultConfiguration();

      addComponentListener(new ComponentAdapter() {
         @Override
         public void componentResized(ComponentEvent e) {
            setUp();
         }
      });
   }

   @Override
   // don't make this public. Keep it protected like the super's
   // just draw in this method. Don't call other methods that create buffers
   // or draw to buffers.
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (offScreen != null) {
         g.drawImage(offScreen, 0, 0, null);
      }
   }

   private void setUp() {
      offScreen = gc.createCompatibleImage(getSize().width, getSize().height,
            Transparency.TRANSLUCENT);
   }

   // draw to the buffer outside of the paintComponent
   // and then call repaint() when done
   public void upDateOffScreen() {
      // ?? offScreen.flush(); // I've never used this before, 
                  // so am not sure if you need this here
      Graphics2D osGraphics = offScreen.createGraphics();
      // TODO: do drawing with osGraphics object here
      osGraphics.dispose();
      repaint();
   }
}

同样,

  • 在 EDT(事件调度线程)之外执行所有长处理方法。
  • 永远不要在 EDT 上调用 Thread.sleep(...)。
  • 考虑使用 Swing Timers 而不是使用 Thread.sleep 来制作动画。
  • 可以在 EDT 之外调用 JPanel 上的 repaint,但大多数情况下就是这样。
  • 应在 EDT 上调用所有其他 Swing 方法。
  • 阅读、重新阅读和学习 2D 和 Swing 图形教程。

【讨论】:

  • +1 我想念那里使用javax.swing.Timer 而不是Thread.sleep(int) 这里有两个最疯狂的例子stackoverflow.com/questions/7206122/swing-rate-limiting
  • 我使用了 Swing Timers 并解决了这个问题。这是因为 repaint 方法没有被调用/做它应该做的事情。可能是因为你提到的那个 EDT。但是非常感谢。 :)
猜你喜欢
  • 2017-08-31
  • 2011-10-17
  • 2019-03-05
  • 1970-01-01
  • 2011-08-05
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多