【问题标题】:I've overridden paintComponent(), so why aren't my shapes appearing?我已经覆盖了paintComponent(),为什么我的形状没有出现?
【发布时间】:2020-01-22 03:55:33
【问题描述】:

我正在玩弄 awt 图形,起初我设法得到了我想要的所有东西,但在清理我的代码后突然出现了一个空框架,里面有 JPanel。

这可能很明显,但我找不到我的形状不再出现的原因。我做错了什么?

public class Main {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Game().setVisible(true);
            }
        });
    }
}
public class Game extends JFrame {
    static int width = 500;
    static int height = 500;

    public Game() {
        this.setPreferredSize(new Dimension(width, height));
        JPanel menuPanel = new JPanel(); // Menypanel
        JPanel filmPanel = new JPanel(); // Filmpanel
        JPanel gamePanel = new JPanel(); // Spelpanel
        gamePanel.setBackground(Color.WHITE);

        // Intro texts
        Queue<String> intro = new ArrayDeque<>();
        intro.add("Welcome to the jungle!");
        intro.add("We've got fun and games.");
        FadingTextBox introBox = new FadingTextBox(intro);
        gamePanel.add(introBox);

        getContentPane().add(gamePanel);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        pack();
    }
}

这个根本没有出现:

class FadingTextBox extends JComponent implements ActionListener {
    private RoundRectangle2D rr;
    private String text = "";
    private float alpha;
    private float alphaDelta = 0.05f; // Alpha fade speed
    private final int fps = 60;  // FPS
    private javax.swing.Timer timer = new Timer(1000 / fps, this);
    private java.util.Queue<String> textQueue; // Contains lines of texts

    public FadingTextBox(java.util.Queue<String> textQueue) {
        this.textQueue = textQueue;
        this.setFont(new Font("OCR A EXTENDED", Font.BOLD, 24));

        int arc = 10;
        int height = (int) (Game.height * 0.2);
        int width = (int) (Game.width - Game.width * 0.1);
        int x = Game.width / 2 - width / 2;
        int y = (int) (Game.height - height * 1.5);

        rr = new RoundRectangle2D.Double(x, y, width, height, arc, arc);

        setText(textQueue.remove());
        timer.start();
    }

    private void setText(String text) {
        this.text = text;
    }

    boolean isRunning() {
        return timer.isRunning();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        // Set component alpha
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));

        // Draw RoundRectangle
        g2.setBackground(Color.DARK_GRAY);
        g2.fill(rr);

        // Draw text
//        g2.setColor(Color.BLUE);
        final FontMetrics fm = g.getFontMetrics();
        Rectangle2D textBounds = fm.getStringBounds(text, g2);
        g2.drawString(text, (float) (rr.getCenterX() - (textBounds.getWidth() / 2)), (float) (rr.getCenterY() + textBounds.getHeight() / 2));
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (alpha >= 0) {
            alpha += alphaDelta;
        }
        if (alpha < 0) {
            alpha = 0;
            try {
                setText(textQueue.remove());
            } catch (NoSuchElementException ex) {
                timer.stop();
            }
            alphaDelta *= -1;
        } else if (alpha >= 1) {
            alpha = 1;
            alphaDelta *= -1;

            // Sleep 1 sec on full alpha
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        repaint();
    }
}

新拍摄:

public class Game extends JFrame {
    ...
    GameCanvas gameCanvas;

    public Game() {
        ...
        gameCanvas = new GameCanvas(); // Spelpanel
        getContentPane().add(gameCanvas);
        ...
        pack();
    }
}
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayDeque;
import java.util.NoSuchElementException;

public class GameCanvas extends Canvas implements Runnable {
    private final int fps = 24;  // FPS
    private RoundRectangle2D rr;
    private String text;
    private float alpha;
    private float alphaDelta = 0.05f; // Alpha fade speed
    private javax.swing.Timer timer = new Timer(1000 / fps, a -> repaint());
    private java.util.Queue<String> textQueue; // Contains lines of texts

    public GameCanvas() {
        this.setFont(new Font("OCR A EXTENDED", Font.BOLD, 20));
        // Intro texts
        textQueue = new ArrayDeque<>();
        textQueue.add("Welcome to the jungle!");
        textQueue.add("We've got fun and games.");

        // RoundRectangle
        int arc = 10;
        int height = (int) (Game.height * 0.2);
        int width = (int) (Game.width - Game.width * 0.1);// (int) (Game.width - Game.width * 0.5);
        int x = Game.width / 2 - width / 2 - 10;
        int y = (int) (Game.height - height * 1.5);
        rr = new RoundRectangle2D.Double(x, y, width, height, arc, arc);

        this.text = textQueue.remove();
        Thread thread = new Thread(this);  // Fade thread
        thread.start();
        timer.start();

    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2 = (Graphics2D) g;

        // Set component alpha

//        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));

        // Draw RoundRectangle
        g2.setBackground(Color.DARK_GRAY);
        g2.fill(rr);

        // Draw text
        final FontMetrics fm = g2.getFontMetrics();
        Rectangle2D textBounds = fm.getStringBounds(text, g2);
        g2.setColor(Color.WHITE);
        g2.drawString(text, (float) (rr.getCenterX() - (textBounds.getWidth() / 2)), (float) (rr.getCenterY() + textBounds.getHeight() / 2));
        g2.setColor(Color.DARK_GRAY);
    }

    @Override
    public void run() {
        while (true) {
            if (alpha >= 0) {
                alpha += alphaDelta;
            }
            if (alpha < 0) {
                alpha = 0;
                try {
                    this.text = textQueue.remove();
                } catch (NoSuchElementException ex) {
                    timer.stop();
                }
                alphaDelta *= -1;
            } else if (alpha >= 1) {
                alpha = 1;
                alphaDelta *= -1;

                // Sleep 1 sec on full alpha
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

【问题讨论】:

  • 只调用 repaint() 的定时器什么都不做。在执行 repaint() 之前,您需要调用一些更改组件属性的代码。
  • @camickr 这是有道理的。我已经注释掉了paint()函数中唯一实际改变的行,setComposite(alpha)-row。

标签: java swing awt event-dispatch-thread jcomponent


【解决方案1】:

这是因为您的gamePanel 没有使用组件填充面板的LayoutManager(默认使用FlowLayout)。为了看到一些东西,把它改成JPanel gamePanel = new JPanel(new BorderLayout());

然而,在Timer 的行动中,你Thread.sleep()。这将冻结整个 GUI,因为 Timer 的动作侦听器在 Event Dispatch Thread 中运行,这是一个不应 sleepThread。相反,您可以使用第二个 Timer 或某种 o 标志变量,或者可能是 SwingWorker

【讨论】:

  • 我将 gamePanel 更改为扩展 Canvas 的新类。给它一个计时器,但只是重新绘制,还给它一个单独的线程,带有一个可运行的线程来进行 alpha-fading,现在所有的睡眠都在那个可运行的中。但是现在它只绘制第一帧而不绘制其他任何内容。
  • @r.r 您应该为此创建另一个问题,包括所有详细信息。如果我的回答对您有帮助,请考虑 accepting it
  • @r.r 我将 gamePanel 更改为扩展 Canvas 的新类 - 你不应该使用 Canves。在 Swing 中使用 JPanel(或 JComponent)进行自定义绘制。问题是您没有覆盖自定义类的 getPreferredSize() 方法。提供布局管理器可以使用的首选大小是所有 Swing 组件的工作。 FlowLayout 尊重首选大小,但由于您没有指定一个,因此没有什么可绘制的。
  • @camickr 谢谢你的提示。我正在第四次(或第五次?)尝试扩展 JPanel(最初是为了摆脱 JPanel 附带的双缓冲闪烁)。我很难找到最佳实践的良好来源。我什么时候应该使用画布?
猜你喜欢
  • 2019-02-09
  • 1970-01-01
  • 1970-01-01
  • 2020-05-12
  • 1970-01-01
  • 2021-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多