缓冲图像不会绘制,但会加载

问题描述 投票:0回答:1
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.*;
import javax.swing.Timer;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MainCasino extends JPanel{
    Random ra = new Random();
    Scanner sc = new Scanner(System.in);
    DrawingPanel pane;
    JFrame window;
    Timer timer;
    
    BufferedImage bg = loadImage("Casinobg.png");
    
    final int PANW = 900;
    final int PANH = 700;
    final int T_SPEED = 15;
    
    int prob;
    int result;

    public static void main(String[] args) {
        new MainCasino();
    }
    
    MainCasino(){
        setupGUI();
        monkeyBusiness();
    }
    
    void setupGUI() {
        window = new JFrame("SLOT MACHINE");
        window.setPreferredSize(new Dimension(PANW, PANH));
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.pack();
        window.setLocationRelativeTo(null);
        window.setVisible(true);
        
        pane = new DrawingPanel();
        pane.setPreferredSize(new Dimension(PANW, PANH));
        pane.setVisible(true);
        window.add(pane);
        window.addKeyListener(new KeyAdapter() {
            public void keyTyped(KeyEvent e) {
                if (e.getKeyChar() == ' ') {
                    
                }
            }
        });
    }
    void monkeyBusiness() {
        timer = new Timer(T_SPEED, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                
                pane.repaint();
            }
        });
        timer.start();
    }
    
    void spin() {
        prob = ra.nextInt(100, 500)+1;
        result = ra.nextInt(prob)+1;
    }
    
    private class DrawingPanel extends JPanel {
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            System.out.println("WOmp");
            g.drawImage(bg, 1, 1, PANW, PANH, null);
        }
    }
    
    static BufferedImage loadImage(String filename) {
        BufferedImage img = null;
        try {
            img = ImageIO.read(new File(filename));
        } catch (Exception e) {
            System.out.println(e.toString());
            JOptionPane.showMessageDialog(null, "An image failed to load: " + filename, "Error",
                    JOptionPane.ERROR_MESSAGE);
        }
        return img;
    }
}   

我尝试更改项目文件夹中图像的位置,但似乎位于正确的位置。

我尝试将图像的 x 和 y 从 0,0 更改为 lese,但这不起作用。

我尝试放置一个系统输出来检查计时器是否正在运行(它是)

我不知道出了什么问题。

java swing bufferedimage paintcomponent
1个回答
0
投票

运行您的代码没有问题,一旦插入我知道会加载的图像。这让我相信图像实际上并未加载,或者您没有看到错误消息(

JOptionPane
可能显示在框架后面,并且错误消息可能会在其他输出的噪音中丢失)并且您不处理图像为空的可能性。稍后将详细介绍这一点。

但是,您的工作流程存在一些需要改进的问题。

正如已经说过的。一般来说,您最好在将 UI 设为可见之前对其进行设置,这有助于解决此类小问题。另外,窗口不应该指定大小,主要原因是窗口装饰显示在窗口内部,使得可查看内容的可用空间更小。相反,您想要

pack
内容周围的窗口。所以,简而言之,不要在窗口上使用
setPreferredSize

所以,你的

setupGUI
可能看起来更像......

void setupGUI() {
    pane = new DrawingPanel();
    pane.setPreferredSize(new Dimension(PANW, PANH));
    
    window = new JFrame("SLOT MACHINE");
    window.add(pane);
    window.pack();
    window.setLocationRelativeTo(null);
    window.setVisible(true);
}

这确保了窗口的可视区域代表其内容的要求。它还会自动布局容器层次结构并为您绘制它。

如果您需要在窗口可见后动态更新 UI(即添加/删除/更新组件),您必须自己调用

revalidate
repaint

你的

DrawingPanel
也依赖于外部状态。您应该尝试解耦代码,以便它支持封装等概念,并根据您的需要使用依赖注入、模型视图控制器甚至观察者模式等概念。重点是尝试创建一个独立的对象,该对象不直接耦合到其他类/对象。

为此,我会考虑将

DrawingPanel
更改为更像......

public class DrawingPanel extends JPanel {

    private BufferedImage backgroundImage;

    public DrawingPanel(BufferedImage backgroundImage) {
        this.backgroundImage = backgroundImage;
    }

    @Override
    public Dimension getPreferredSize() {
        if (backgroundImage == null) {
            return new Dimension(200, 200);
        } else {
            return new Dimension(backgroundImage.getWidth(), backgroundImage.getHeight());
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        if (backgroundImage == null) {
            g2d.setColor(Color.RED);
            g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
            g2d.drawLine(0, 0, getWidth(), getHeight());
            g2d.drawLine(getWidth(), 0, 0, getHeight());
        } else {
            int x = (getWidth() - backgroundImage.getWidth()) / 2;
            int y = (getHeight() - backgroundImage.getHeight()) / 2;
            g2d.drawImage(backgroundImage, x, y, this);
        }
        g2d.dispose();
    }
}

这利用依赖注入来“注入”对象属性。它将类解耦,使其独立并封装功能,因此,例如,

preferredSize
是由类本身计算的 - 它是自我确定的。

但是为什么我的图像没有画出来?

我听到你说。正如我已经说过的,我的猜测是您的图像实际上并未加载,并且错误处理无法为您提供该信息。

仔细看看...

static BufferedImage loadImage(String filename) {
    BufferedImage img = null;
    try {
        img = ImageIO.read(new File(filename));
    } catch (Exception e) {
        System.out.println(e.toString());
        JOptionPane.showMessageDialog(null, "An image failed to load: " + filename, "Error",
                JOptionPane.ERROR_MESSAGE);
    }
    return img;
}

我们可以确定...

  • 该方法隐藏了异常
  • 可以返回
    null
    ,但你从未真正检查过

我还发现最初的

JOptionPane
不可靠,因为主窗口在其顶部可见......有些令人惊讶,这可能是我的用户观察问题,但我不记得看到过它我第一次运行代码。

更好的解决方案是允许异常传播回调用者。从本质上讲,

loadImage
方法没有责任确定失败时应该执行哪些操作,因此,我会做类似的事情......

static BufferedImage loadImage(String filename) throws IOException {
    return ImageIO.read(new File(filename));
}

现在,这将给您带来问题,因为您无法将异常作为变量初始化工作流程的一部分来处理,这就是为什么我们有构造函数和依赖注入之类的东西。

所以我会改变你的赌场类的构造函数,使其更像......

MainCasino(BufferedImage backgroundImage) { 
    bg = backgroundImage;
    ... 
}

现在,这迫使您在尝试启动

MainCasino
类之前就处理可能的异常。

另一个问题是,加载图像时使用

File
和相对路径。问题是,“工作目录”(或代码运行的位置)并不总是与代码所在的位置相同。这是一个相对常见的问题,有一个通用的解决方案 - 嵌入您的资源。

本质上,这只是意味着确保您需要的资源在类路径中可用。这通常是通过将资源包含在生成的 Jar 文件中并在运行时使用

Class#getResource
来完成的。

如何完成此操作将取决于您的 IDE 和构建系统,例如,某些 IDE/构建系统允许您直接将资源直接包含在源文件夹中,有些则要求将它们放置在“特殊”目录中。您需要研究您的 IDE 并构建系统。

可运行的示例...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                BufferedImage backgroundImage;
                try {
                    backgroundImage = ImageIO.read(getClass().getResource("/resources/apple.png"));
                    JFrame frame = new JFrame("Test");
                    frame.add(new BackgroundPane(backgroundImage));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    protected class MainPane extends JPanel {

        public MainPane(BufferedImage backgroundImage) {
            setLayout(new BorderLayout());
            add(new BackgroundPane(backgroundImage));
        }

    }

    protected class BackgroundPane extends JPanel {

        private BufferedImage backgroundImage;

        public BackgroundPane(BufferedImage backgroundImage) {
            this.backgroundImage = backgroundImage;
        }

        @Override
        public Dimension getPreferredSize() {
            if (backgroundImage == null) {
                return new Dimension(200, 200);
            } else {
                return new Dimension(backgroundImage.getWidth(), backgroundImage.getHeight());
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (backgroundImage == null) {
                g2d.setColor(Color.RED);
                g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
                g2d.drawLine(0, 0, getWidth(), getHeight());
                g2d.drawLine(getWidth(), 0, 0, getHeight());
            } else {
                int x = (getWidth() - backgroundImage.getWidth()) / 2;
                int y = (getHeight() - backgroundImage.getHeight()) / 2;
                g2d.drawImage(backgroundImage, x, y, this);
            }
            g2d.dispose();
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.