JPanel 重绘未清除

发布于 2024-12-04 07:53:05 字数 2002 浏览 1 评论 0原文

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

和 B 遵循相同的格式。更新Panel上的一些变量,调用update(Panel中调用PaintComponent的方法),然后调用repaint。它调用 repaint 之后,因为这个问题之前与 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();
    }
}

I have a custom, abstract class 'Panel' which extends JPanel. There aren't many differences with the two when painting. I have a Panel and I'm simulating an animation by updating the x value of an image. I have two animations right now, one that properly repaints and another than does not. This is for the one that does not. The one that works will be labelled A, the one that doesn't will be B.

A and B follow the same format. Update some variable on the Panel, calls update (a method in Panel which calls PaintComponent) and then calls repaint. It calls repaint after because this issue was with A before and was solved that way.

A: Updates an image variable.
B: Updates the x variable of an image.

The Problem: The repaint doesn't clear the old image location and so it's a choppy mess across the screen.

What I've tried:

  • I've seen the super.PaintComponent(g) mentioned a lot, but this
    hasn't solved the problem.
  • I've tried changing the order for when the repaint/update methods are
    called.
  • Repaint does not update the Panel at all. (Probably because the
    painting is done in PaintComponent)

Any help would be appreciated.

Code:

Panel:

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());
}

Animation Methods (mg is the panel in question):

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();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小鸟爱天空丶 2024-12-11 07:53:05

我认为你的设计太离谱了,这就是为什么事情不起作用的原因。我不太确定你的非抽象 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 上的重绘,但大多数情况仅此而已。
  • 所有其他 Swing 方法都应在 EDT 上调用。
  • 阅读、重读和研究 2D 和 Swing 图形教程。

I think your design is way off and that is why things are not working. I'm not quite sure how your non-abstract JPanels work, but consider making your parent JPanel something more along these lines:

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();
   }
}

Also and again,

  • Do all long processing methods off of the EDT (Event Dispatch Thread).
  • Never call Thread.sleep(...) on the EDT.
  • Consider using Swing Timers instead of using Thread.sleep for the animations.
  • It's OK to call repaint on your JPanel off of the EDT, but for the most part that's about it.
  • All other Swing methods should be called on the EDT.
  • Read, re-read, and study the 2D and Swing graphics tutorials.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文