I'm trying to add a background to different JPanels (henceforth they will be called Window). These Windows are classes I created and make them inherit JPanel. Then depending on the state of the program one Window is set as the content panel of the program's JFrame. The problem comes when in some Windows the background gets set and in others not. The background setting is performed ussing the paintComponent(Graphics g) method, but despite I've tried to fix the bug, I didnt' success.
Here is the code I think might be useful for those who wanna help:
Main Loop:
public class Game{
//here comes other stuff (constructor, main, other methods...)
private void run(){
while(true){
if(GameState.changed){
Screen.getInstance().seeWindow(state);
GameState.changed = false;
}else {
Screen.getInstance().requestFocus(state);
}
}
}
}
Screen class:
package view;
import game.GameState;
import view.wins.*;
import javax.swing.*;
import java.awt.*;
public class Screen extends JFrame {
private final int WIDTH;
private final int HEIGHT;
private static Screen instance = null;
private JComponent titleWindow, menuWindow, settingsWindow;
private Screen(){
WIDTH = 1152;
HEIGHT = 768;
setTitle("Game");
setDefaultCloseOperation(EXIT_ON_CLOSE);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
this.setLocation(dim.width/2-WIDTH/2, (dim.height - 50)/2-HEIGHT/2);
Dimension size = new Dimension(WIDTH, HEIGHT);
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setResizable(false);
setVisible(true);
}
public static Screen getInstance() {
if(instance == null){
instance = new Screen();
}
return instance;
}
public void seeWindow(GameState state){
switch(state){
case TITLE -> setContentPane(getTitleWindow());
case MENU -> setContentPane(getMenuWindow());
case SETTINGS -> setContentPane(getSettingsWindow());
}
pack();
}
public void requestFocus(GameState state){
switch (state){
case TITLE -> getTitleWindow().requestFocus();
case MENU -> getMenuWindow().requestFocus();
case SETTINGS -> getSettingsWindow().requestFocus();
}
}
private JComponent getTitleWindow(){
if(titleWindow == null){
titleWindow = new TitleWindow();
}
return titleWindow;
}
private JComponent getMenuWindow(){
if(menuWindow == null){
menuWindow = new MenuWindow();
}
return menuWindow;
}
private JComponent getSettingsWindow(){
if(settingsWindow == null){
settingsWindow = new SettingsWindow();
}
return settingsWindow;
}
}
Window abstract class:
package view.wins;
import utilz.GFXManager;
import view.Screen;
import javax.swing.*;
import java.awt.*;
import java.util.Observer;
public abstract class Window extends JComponent implements Observer {
private Image background;
public Window(String background){
setLayout(new BorderLayout());
setPreferredSize(Screen.getInstance().getPreferredSize());
setBackground(background);
setFocusable(true);
}
protected void setBackground(String backgroundName){
this.background = GFXManager.getInstance().getImage("backgrounds/" + backgroundName + ".png");
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, null);
}
}
A Window where the background is correctly set:
package view.wins;
import game.GameState;
import game.Game;
import jdk.swing.interop.SwingInterOpUtils;
import logic.TitleLogic;
import utilz.GFXManager;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Observable;
import java.util.Observer;
public class TitleWindow extends Window implements Observer {
private final String BELOW_TITLE_TEXT;
private final ImageIcon TITLE_ICON;
private JLabel lblTitleIcon, lblBelowTitle;
private KeyController keyController;
public TitleWindow(){
super("title_background");
BELOW_TITLE_TEXT = "Press enter to start";
TITLE_ICON = new ImageIcon(GFXManager.getInstance().getImage("texts/title.png"));
TitleLogic.getInstance().addObserver(this);
setLayout(new BorderLayout());
addKeyListener(new KeyController());
add(getLblTitleIcon(), BorderLayout.CENTER);
add(getLblBelowTitle(), BorderLayout.SOUTH);
}
private JLabel getLblTitleIcon(){
if(lblTitleIcon == null){
lblTitleIcon = new JLabel(TITLE_ICON);
}
return lblTitleIcon;
}
private JLabel getLblBelowTitle(){
if(lblBelowTitle == null){
lblBelowTitle = new JLabel(BELOW_TITLE_TEXT, SwingConstants.CENTER);
lblBelowTitle.setFont(new Font("MS Gothic", Font.PLAIN, 24));
lblBelowTitle.setForeground(new Color(30,230,120));
}
return lblBelowTitle;
}
private KeyController getKeyController(){
if(keyController == null){
keyController = new KeyController();
}
return keyController;
}
@Override
public void update(Observable o, Object arg) {
if(TitleLogic.getInstance().isTickColorChange()){
getLblBelowTitle().setForeground(new Color(120, 30, 230));
}else{
getLblBelowTitle().setForeground(new Color(30,230,120));
}
}
private class KeyController extends KeyAdapter {
@Override
public void keyTyped(KeyEvent e) {
if(e.getKeyChar() == '\n'){
Game.getInstance().setState(GameState.MENU);
}else if(e.getKeyChar() == 'c'){
TitleLogic.getInstance().tickColorChange();
}
}
}
}
A Window where the background isn't set:
package view.wins;
import game.GameState;
import game.Game;
import logic.MenuLogic;
import view.objs.Button;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Observable;
import java.util.Observer;
public class MenuWindow extends Window implements Observer {
private JPanel btnPanel;
private Button btnStartNewGame, btnLoadGame, btnSettings, btnExit;
private Controller controller;
public MenuWindow(){
super("title_background");
MenuLogic.getInstance().addObserver(this);
setLayout(new BorderLayout());
add(getBtnPanel(), BorderLayout.CENTER);
}
private JPanel getBtnPanel(){
if(btnPanel == null){
btnPanel = new JPanel(new GridLayout(4,1));
btnPanel.add(getBtnStartNewGame());
btnPanel.add(getBtnLoadGame());
btnPanel.add(getBtnSettings());
btnPanel.add(getBtnExit());
}
return btnPanel;
}
private Button getBtnStartNewGame(){
if(btnStartNewGame == null){
btnStartNewGame = new Button("mediumLong", "Start new game", getController());
}
return btnStartNewGame;
}
private Button getBtnLoadGame(){
if(btnLoadGame == null){
btnLoadGame = new Button("mediumLong", "Load game", getController());
}
return btnLoadGame;
}
private Button getBtnSettings(){
if(btnSettings == null){
btnSettings = new Button("mediumLong", "Settings", getController());
}
return btnSettings;
}
private Button getBtnExit(){
if(btnExit == null){
btnExit = new Button("mediumLong", "Exit", getController());
}
return btnExit;
}
private Controller getController(){
if(controller == null){
controller = new Controller();
}
return controller;
}
@Override
public void update(Observable o, Object arg) {
}
private class Controller extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
if(e.getSource().equals(getBtnStartNewGame())){
}else if(e.getSource().equals(getBtnLoadGame())){
}else if(e.getSource().equals(getBtnSettings())){
Game.getInstance().setState(GameState.SETTINGS);
}else if(e.getSource().equals(getBtnExit())){
System.exit(0);
}
}
@Override
public void mouseEntered(MouseEvent e) {
((Button)e.getSource()).changeHighlight();
}
@Override
public void mouseExited(MouseEvent e) {
((Button)e.getSource()).changeHighlight();
}
}
}
Button is a class of my own.
If anyone wants to test it for his own or see more code here is the github repository.
I tried everything and more. I've noticed that the Graphics of MenuWindow aren't initialized, so the problem could come because that window isn't rendered. I don't know.