3

我之前发表过一篇文章,解释了我在卡片布局中绘制图像时遇到的问题。我得到了有限的帮助,并没有解决问题。所以我再次发布这篇文章来解释它,希望能得到一些有效的帮助。

我正在尝试为我的 java 游戏制作标题屏幕。我制作了两个java文件。第一个文件加载卡片布局,下一个加载标题屏幕。但不知何故,在第二个文件中我无法让它绘制我的背景图像。我没有收到任何错误消息。它根本不画任何东西。

第一个文件:

import javax.swing.*;
import java.awt.*;

public class MainScreen extends JFrame{

    public static CardLayout cardLayout = new CardLayout();//set a new cardlayout

    // *** JPanel to hold the "cards" and to use the CardLayout:
    static JPanel cardContainer = new JPanel(cardLayout);//some variable for the cardlayout
    public static JComboBox cardCombo = new JComboBox();//some variable for the cardlayout
    public static JPanel comboPanel = new JPanel();;//some variable for the cardlayout
    Image background = Toolkit.getDefaultToolkit().createImage("data/images/title.png");//loads the background image

    public MainScreen() {

        JFrame frame = new JFrame();
        frame.setTitle("Project");//Title of the screen
        frame.setSize(800,600);//Size of the window
        frame.setResizable(false);//Is the window resizable?
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//Exit the frame when the default red cross is clicked
        frame.setVisible(true);//is the frame visible?
        frame.getContentPane().add(cardContainer, BorderLayout.CENTER);//add the cardcontainer to flip panels
        frame.setLocationRelativeTo(null);
    }

    public static void debug(){//makes an extra card, this is a debug card and is not used for anything but debugging

        JPanel debugPanel = new JPanel(new BorderLayout());//Debug panel, not used for anything, script does not work if not here
        debugPanel.setBackground(Color.BLACK);//set the background color to black
        String debug = "Debug Panel";//name the card or something like that
        cardContainer.add(debugPanel, debug);//add the card to the panel
        cardCombo.addItem(debug);//add the item??
    }

    public static void main(String[] args){//this runs when the script opens

        new MainScreen();//run the main screen class, that loads the window and card layout
        debug();//run the next class that initializes the mainmenu
        new MainMenu(null);//load the main menu
    }
}

第二个文件:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class MainMenu extends JPanel{

    Image background = Toolkit.getDefaultToolkit().createImage("data/images/title.png");//loads the background image

    public MainMenu(MainScreen frame){
        JPanel menuPanel = new JPanel();//This is the menu panel, where the main menu is loaded
        menuPanel.setBackground(Color.BLACK);//set the background color to black
        String menu = "Menu Panel";//name the card or something
        MainScreen.cardContainer.add(menuPanel, menu);//add the card to the panel
        MainScreen.cardCombo.addItem(menu);//add the item??
        MainScreen.cardLayout.show(MainScreen.cardContainer, menu);//choose what card to show. For this instance show the mainmenu
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(background, 0, 0, null);
        repaint();
    }

}

编辑

您能否将存在图像显示问题的代码的确切部分提取到 SSCCE 中?并附上使用图像的链接 - 它可能已损坏,在这种情况下,问题不在代码内部。

干得好

import javax.swing.*;
import java.awt.*;

public class MainScreen extends JFrame{

    public static CardLayout cardLayout = new CardLayout();//set a new cardlayout

    // *** JPanel to hold the "cards" and to use the CardLayout:
    static JPanel cardContainer = new JPanel(cardLayout);//some variable for the cardlayout
    public static JComboBox cardCombo = new JComboBox();//some variable for the cardlayout
    public static JPanel comboPanel = new JPanel();;//some variable for the cardlayout
    Image background = Toolkit.getDefaultToolkit().createImage("data/images/title.png");//loads the background image

    public MainScreen() {

        JFrame frame = new JFrame();
        frame.setTitle("Project");//Title of the screen
        frame.setSize(800,600);//Size of the window
        frame.setResizable(false);//Is the window resizable?
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//Exit the frame when the default red cross is clicked
        frame.setVisible(true);//is the frame visible?
        frame.getContentPane().add(cardContainer, BorderLayout.CENTER);//add the cardcontainer to flip panels
        frame.setLocationRelativeTo(null);
    }

    public static void debug(){//makes an extra card, this is a debug card and is not used for anything but debugging

        JPanel debugPanel = new JPanel(new BorderLayout());//Debug panel, not used for anything, script does not work if not here
        debugPanel.setBackground(Color.BLACK);//set the background color to black
        String debug = "Debug Panel";//name the card or something like that
        cardContainer.add(debugPanel, debug);//add the card to the panel
        cardCombo.addItem(debug);//add the item??

        JPanel titlePanel = new JPanel(new BorderLayout());//Debug panel, not used for anything, script does not work if not here
        titlePanel.setBackground(Color.BLACK);//set the background color to black
        String title = "Title Panel";//name the card or something like that
        cardContainer.add(titlePanel, title);//add the card to the panel
        cardCombo.addItem(title);//add the item??

        cardLayout.show(cardContainer, title);//choose what card to show. For this instance show the mainmenu
    }

    public static void main(String[] args){//this runs when the script opens

        new MainScreen();//run the main screen class, that loads the window and card layout
        debug();//run the next class that initializes the mainmenu
    }

    //Here the i try to paint the image. No error messages show.
    public void paintComponent(Graphics g){//<-------------HERE
        g.drawImage(background, 0, 0, null);//<-------------HERE
        repaint();//<-------------HERE
    }
}

对于图片:http: //i.stack.imgur.com/F3nHF.png

4

2 回答 2

7

好吧,您的代码中有很多问题...

首先-看@您的 MainScreen 类-“MainScreen extends JFrame”-您不将其用作主框架。您可以在其构造函数中创建新的单独 JFrame:

public MainScreen() {

    JFrame frame = new JFrame();
    frame.setTitle("Project");//Title of the screen
    frame.setSize(800,600);//Size of the window
    frame.setResizable(false);//Is the window resizable?
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//Exit the frame when the default red cross is clicked
    frame.setVisible(true);//is the frame visible?
    frame.getContentPane().add(cardContainer, BorderLayout.CENTER);//add the cardcontainer to flip panels
    frame.setLocationRelativeTo(null);
}

改为这样做:

public MainScreen ()
{
    super();
    setTitle ( "Project" );//Title of the screen
    setSize ( 800, 600 );//Size of the window
    setResizable ( false );//Is the window resizable?
    setDefaultCloseOperation (
            JFrame.EXIT_ON_CLOSE );//Exit the frame when the default red cross is clicked
    setVisible ( true );//is the frame visible?
    getContentPane ()
            .add ( cardContainer, BorderLayout.CENTER );//add the cardcontainer to flip panels
    setLocationRelativeTo ( null );
    repaint (  );
}

如果您覆盖它,您的“paint()”方法(不是paintComponent())将起作用。

下一个问题- 永远不要在 paint* 方法中使用 repaint() 方法......永远不要!它可能会导致接口死锁/卡住。如果您需要调用 repaint - 请在绘制方法之外执行此操作。

我在谈论那部分代码:

//Here the i try to paint the image. No error messages show.
public void paintComponent(Graphics g){//<-------------HERE
    g.drawImage(background, 0, 0, null);//<-------------HERE
    repaint();//<-------------HERE
}

只需在绘画方法中绘制您需要的任何内容,而不是更多。所有重绘逻辑都应该移到它们之外。想想看 - 你正在从油漆中调用重绘方法 - 这将导致再次绘画而不是再次重绘等

还有一个- 你的“paintComponent”方法不会在 JFrame 上工作,因为 JFrame 不扩展 JComponent。所以这个方法根本没有用。有一种绘画方法,但你也不应该使用它。要设置背景图像 - 使用一些框架范围的面板并在其上绘制背景。之后,您可以将任何内容放在该面板上(请看最后的示例)。

还有更多——你在 cardContainer 上有黑色背景的 debugPanel——它会隐藏你在容器或框架上绘制的任何东西(我再说一遍——不要在框架本身上绘画,这是一个坏习惯)。因此,您必须通过将 opaque (setOpaque) 设置为 false 来禁用位于背景上的组件中的任何背景。您可以将 cardContainer 背景设置为 BLACK 并在其上绘制图像。

最后一个- 确保“data/images/title.png”路径是相对于您的应用程序工作目录的。我总是使用另一种加载图像的方式:

Toolkit.getDefaultToolkit ()
        .createImage ( MainScreen.class.getResource ( "some/path/image.png" ) );

此代码将加载相对于包内的类位置放置的图像。这样您就可以在最终的应用程序 jar 中拥有任何图像而不会出现任何问题。但这只是一个建议。

以及在框架内绘制背景的最终代码:

public class MainScreen extends JFrame
{
    public JPanel comboPanel;
    public JComboBox cardCombo;

    public CardLayout cardLayout;
    public JPanel cardContainer;

    public static ImageIcon background =
            new ImageIcon ( MainScreen.class.getResource ( "icons/title.png" ) );

    public MainScreen ()
    {
        super ();
        setTitle ( "Project" );

        comboPanel = new JPanel ();
        cardCombo = new JComboBox ();

        cardLayout = new CardLayout ();
        cardContainer = new BackgroundPanel ( cardLayout );
        cardContainer.setOpaque ( true );
        cardContainer.setBackground ( Color.BLACK );
        getContentPane ().add ( cardContainer, BorderLayout.CENTER );

        initializeGUI ();

        setSize ( 800, 600 );
        setResizable ( false );
        setLocationRelativeTo ( null );
        setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
        setVisible ( true );
    }

    public void initializeGUI ()
    {
        JPanel debugPanel = new JPanel ( new BorderLayout () );
        debugPanel.setOpaque ( false );
        String debug = "Debug Panel";
        cardContainer.add ( debugPanel, debug );
        cardCombo.addItem ( debug );

        JPanel titlePanel = new JPanel ( new BorderLayout () );
        titlePanel.setOpaque ( false );
        String title = "Title Panel";
        cardContainer.add ( titlePanel, title );
        cardCombo.addItem ( title );

        cardLayout.show ( cardContainer, title );
    }

    private class BackgroundPanel extends JPanel
    {
        public BackgroundPanel ( LayoutManager layout )
        {
            super ( layout );
        }

        protected void paintComponent ( Graphics g )
        {
            super.paintComponent ( g );
            g.drawImage ( background.getImage (), 0, 0, BackgroundPanel.this );
        }
    }

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

我还使用 ImageIcon 而不是 Image 来确保在显示框架之前加载图像。否则,您必须手动检查图像加载状态并在加载时更新背景。

PS 不要用注释重载你的代码 - 如果代码足够干净,它们就不需要了:)

于 2012-06-04T12:29:02.867 回答
3

看看这个,在我看来,你好像画错了。在我看来,您的代码的编写方式非常错误,没有任何意义。每当您覆盖您paintComponent(...)的. 此外,您的 CardLayout 的整个实现是任性的,看来您需要再次浏览CardLayout 教程JPanel/JComponentgetPreferredSize()JFrame

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;

public class DrawingImage
{
    private void displayGUI()
    {
        JFrame frame = new JFrame("Drawing Image Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        CustomPanel contentPane = new CustomPanel();
        frame.getContentPane().add(contentPane);

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new DrawingImage().displayGUI();
            }
        });
    }
}

class CustomPanel extends JPanel
{
    private BufferedImage background;

    public CustomPanel()
    {
        try
        {
            background = ImageIO.read(new java.net.URL("http://i.stack.imgur.com/F3nHF.png"));
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    @Override       
    public Dimension getPreferredSize()
    {
        return (new Dimension(800, 600));
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.drawImage(background, 0, 0, this);
    }
}   
于 2012-06-04T15:20:25.443 回答