I made a former post explaining a problem I had drawing a image in a cardlayout. I received limited help and did not solve the problem. So I am making this post explaining it again hoping for some valid help.
I am trying to make a title screen for my java game. I made two java files. The first file loads the cardlayout and the next loads the title screen. But Somehow the in the second file I can't get it to draw my background image. I receive no error messages. It simply does not draw anything.
First file:
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
}
}
Second file:
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();
}
}
Could you extract the exact part of code, that has image display problem into SSCCE? And attach the link to used image aswell - it might be corrupted, in that case the problem is not inside the code.
Here you go
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
}
}
And for the picture: https://i.sstatic.net/F3nHF.png
Well, there is a lot of problems in your code...
First of all - look @ your MainScreen class - "MainScreen extends JFrame" - you don't use it as main frame. You create new separate JFrame instead inside its constructor:
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);
}
Do this instead:
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 ( );
}
And your "paint()" method (not paintComponent()) will work if you override it.
Next problem - Never ever use repaint() method inside of paint* methods... never! It might cause an interface deadlock/stuck. If you need to call repaint - do it outside of the paint methods.
I was talking about that part of code:
//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
}
Just paint whatever you need inside paint methods, not more. All repaint logic should be moved outside of them. Just think about it - you are calling repaint method from paint - that will lead to paint again and than to repaint again e.t.c.
One more - your "paintComponent" method won't work on JFrame since JFrame does NOT extend JComponent. So this method has no use at all. There is a paint method, but you shouldn't use it either. To set a background image - use some frame-wide panel and paint background on it. After that you can put any content over that panel (look at the example at the end).
And more - you have debugPanel with BLACK background over cardContainer - it will hide anything you draw on the container or the frame (i will say that once more - do not paint on the frame itself, thats a bad habbit). So you have to disable any backgrounds in the components that lies over the background by setting opaque (setOpaque) to false. You can set cardContainer background to BLACK instead and paint image over it.
And last one - be sure that "data/images/title.png" path is relative to your application working directory. I always use another way of loading images:
Toolkit.getDefaultToolkit ()
.createImage ( MainScreen.class.getResource ( "some/path/image.png" ) );
This code will load image placed relative to class location inside packages. This way you can have any image inside the final application jar without any problems. But thats just an advice.
And the final code that paints background inside frame:
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 ();
}
}
I have also used ImageIcon instead Image to ensure that image is loaded before we show the frame. Otherwise you have to manually check image load state and update the background when it is loaded.
P.S. Do not overload your code with comments - they are not needed if the code is clean enough :)