Reputation: 31
I am a noob in java and am trying to make a kind of text adventure game. I want to be able to have the program have some kind of fade ability as it transitions from one layout of the UI to another.
I really have no idea what the best approach to this problem would be or if its really even feasible, but I have so far been trying to have a Jpanel that covers the entire window and uses a timer to fade in to cover everything else in black, or fades out from black to transparency thereby revealing everything underneath.
I have been testing this idea by trying to fade in/out the program at the start just to get the logic for the fade system working before trying to have it as a transition effect. The fade-out kind of works, but I have the program output the alpha level and the screen is turning black at around alpha 50 out of 255 which is confusing me. The fade-in does not work at all.
Here is the code for the fade method:
static int opacityCounter = 0;
public void fadeOut(JPanel frame){
System.out.println(opacityCounter);
opacityCounter = 0;
fadeTimer = new Timer(50, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.setBackground(new Color(0,0,0,opacityCounter));
opacityCounter++;
gui.window.add(frame);
if(opacityCounter >= 255){
opacityCounter = 255;
fadeTimer.stop();
}
System.out.println(opacityCounter);
}
});
fadeTimer.start();
}
This is the code where the "fadePanel" that covers the window is created and deployed in the method.
fadeScreen = new JPanel();
fadeScreen.setBounds(0,0,800,600);
fadeScreen.setBackground(Color.black);
window.add(fadeScreen);
game.visibilityManager.fadeOut(this.fadeScreen);
To clarify I want something that goes from a UI layout like this:
fades to black, before fading back to a UI that looks like this
This is a minimal reproducible example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test {
JFrame window;
JPanel fadeScreen, screen1, screen2;
JLabel text1, text2;
Timer fadeTimer;
public Test(){
//Frame Window
window = new JFrame();
window.setSize(800,600);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().setBackground(Color.blue);
//Screen 1
screen1 = new JPanel();
screen1.setBounds(100, 100, 600, 125);
screen1.setBackground(Color.white);
text1 = new JLabel("Text1");
screen1.add(text1);
window.add(screen1);
//Screen 2
screen2 = new JPanel();
screen2.setBounds(100, 400, 600, 125);
screen2.setBackground(Color.white);
text2 = new JLabel("Text2");
screen2.add(text2);
window.add(screen2);
//Cover Panel
fadeScreen = new JPanel();
fadeScreen.setBounds(0,0,800,600);
fadeScreen.setBackground(Color.black);
window.add(fadeScreen);
window.setVisible(true);
//Comment out which method you don't want to use
fadeOut(this.fadeScreen);
//fadeIn(this.fadeScreen);
}
//Fade methods
int opacityCounter = 0;
public void fadeOut(JPanel frame){
System.out.println(opacityCounter);
opacityCounter = 0;
fadeTimer = new Timer(50, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.setBackground(new Color(0,0,0,opacityCounter));
opacityCounter++;
window.add(frame);
if(opacityCounter >= 255){
opacityCounter = 255;
fadeTimer.stop();
}
System.out.println(opacityCounter);
}
});
fadeTimer.start();
}
public void fadeIn(JPanel frame){
System.out.println(opacityCounter);
opacityCounter = 255;
fadeTimer = new Timer(50, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.setBackground(new Color(0,0,0,opacityCounter));
opacityCounter--;
window.add(frame);
if(opacityCounter <= 0){
opacityCounter = 0;
fadeTimer.stop();
}
System.out.println(opacityCounter);
}
});
fadeTimer.start();
}
public static void main(String[] args){
new Test();
}
}
Thanks in advance!
Upvotes: 0
Views: 1083
Reputation: 51565
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay close attention to the Concurrency in Swing and the Laying Out Components Within a Container sections.
This is Hovercraft Full Of Eels' answer. All I did was clean up the GUI creation and demonstrate how this would work with more than two JPanels
.
I created five JPanels
and displayed them in order with the fade-out/fade-in effect.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class FadeEffectsTesting {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Fade Effects Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new FadeEffectsTesting().getMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
});
}
public static final String[] PANEL_SEQUENCE = { "Panel 1", "Panel 2", "Panel 3", "Panel 4",
"Panel 5" };
private int sequence = 0;
private CardLayout cardLayout;
private FadeAction action;
private JPanel cardPanel, mainPanel;
public FadeEffectsTesting() {
this.mainPanel = new JPanel(new BorderLayout(5, 5));
this.cardPanel = createCardPanel();
this.action = new FadeAction(cardPanel);
mainPanel.add(cardPanel, BorderLayout.CENTER);
mainPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
}
private JPanel createCardPanel() {
cardLayout = new CardLayout();
JPanel panel = new JPanel(cardLayout);
panel.add(createTextPanel(Color.PINK, PANEL_SEQUENCE[0]),
PANEL_SEQUENCE[0]);
panel.add(createTextPanel(new Color(131, 238, 255),
PANEL_SEQUENCE[1]), PANEL_SEQUENCE[1]);
panel.add(createTextPanel(Color.PINK, PANEL_SEQUENCE[2]),
PANEL_SEQUENCE[2]);
panel.add(createTextPanel(new Color(131, 238, 255),
PANEL_SEQUENCE[3]), PANEL_SEQUENCE[3]);
panel.add(createTextPanel(Color.PINK, PANEL_SEQUENCE[4]),
PANEL_SEQUENCE[4]);
return panel;
}
private JPanel createTextPanel(Color color, String text) {
JPanel panel = new JPanel(new FlowLayout());
panel.setBackground(color);
int gap = 40;
panel.setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
JLabel label = new JLabel(text);
label.setFont(label.getFont().deriveFont(Font.BOLD, 72f));
panel.add(label);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
setFadeAction();
JButton startFadeBtn = new JButton(action);
panel.add(startFadeBtn);
return panel;
}
public void setFadeAction() {
action.setFromPanel(PANEL_SEQUENCE[sequence]);
action.setToPanel(PANEL_SEQUENCE[sequence + 1]);
}
public JPanel getMainPanel() {
return mainPanel;
}
public class FadeAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private static final int FADE_DELAY = 20;
private static final int UNFADE_VALUE = 255;
private JPanel cardPanel;
private JComponent glassPane;
private JPanel coverPanel;
private Timer fadeTimer;
private int alphaValue;
private boolean fadeOut;
private String fromPanel, toPanel;
public FadeAction(JPanel cardPanel) {
super("Start Fade");
this.putValue(MNEMONIC_KEY, KeyEvent.VK_S);
this.cardPanel = cardPanel;
this.alphaValue = 0;
this.fadeOut = true;
}
public void setFromPanel(String fromPanel) {
this.fromPanel = fromPanel;
}
public void setToPanel(String toPanel) {
this.toPanel = toPanel;
}
@Override
public void actionPerformed(ActionEvent event) {
alphaValue = 0;
fadeOut = true;
setEnabled(false);
CardLayout cl = (CardLayout) cardPanel.getLayout();
cl.show(cardPanel, fromPanel);
Window topLevelWindow = SwingUtilities.getWindowAncestor(cardPanel);
glassPane = (JComponent) ((RootPaneContainer) topLevelWindow).getRootPane()
.getGlassPane();
glassPane.setLayout(null);
coverPanel = new JPanel();
coverPanel.setSize(cardPanel.getSize());
glassPane.add(coverPanel);
glassPane.setVisible(true);
fadeTimer = new Timer(FADE_DELAY, e2 -> fadeTimerActionPerformed(e2));
fadeTimer.start();
}
private void fadeTimerActionPerformed(ActionEvent event) {
coverPanel.setBackground(new Color(0, 0, 0, alphaValue));
glassPane.repaint();
if (fadeOut) {
alphaValue += 3;
} else if (alphaValue > 0) {
alphaValue -= 3;
} else {
glassPane.remove(coverPanel);
glassPane.setVisible(false);
((Timer) event.getSource()).stop();
if (++sequence < (PANEL_SEQUENCE.length - 1)) {
setFadeAction();
setEnabled(true);
}
}
if (alphaValue >= UNFADE_VALUE) {
fadeOut = false;
CardLayout cl = (CardLayout) cardPanel.getLayout();
cl.show(cardPanel, toPanel);
}
}
}
}
Upvotes: 0
Reputation: 285460
I would try these things:
For example (to write more code explanation later):
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Test2 extends JPanel {
public static final String PANEL_1 = "panel 1";
public static final String PANEL_2 = "panel 2";
private CardLayout cardLayout = new CardLayout();
private JPanel cardPanel = new JPanel(cardLayout);
private JPanel panel1 = new JPanel();
private JPanel panel2 = new JPanel();
private Action fadeAction = new FadeAction(cardPanel);
public Test2() {
JLabel label = new JLabel("Panel 1");
label.setFont(label.getFont().deriveFont(Font.BOLD, 100f));
panel1.setLayout(new GridBagLayout());
int gap = 40;
panel1.setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
panel1.add(label);
panel1.setBackground(Color.PINK);
label = new JLabel("Panel 2");
label.setFont(label.getFont().deriveFont(Font.BOLD, 100f));
panel2.setLayout(new GridBagLayout());
panel2.setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
panel2.add(label);
panel2.setBackground(new Color(131, 238, 255));
cardPanel.add(panel1, PANEL_1);
cardPanel.add(panel2, PANEL_2);
JButton startFadeBtn = new JButton(fadeAction);
JPanel buttonPanel = new JPanel();
buttonPanel.add(startFadeBtn);
setLayout(new BorderLayout(5, 5));
add(cardPanel, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
}
private static class FadeAction extends AbstractAction {
private static final int FADE_DELAY = 20;
private static final int UNFADE_VALUE = 255;
private JPanel cardPanel;
private JComponent glassPane;
private JPanel coverPanel = new JPanel();
private Timer fadeTimer;
private int counter = 0;
private boolean fade = true;
public FadeAction(JPanel cardPanel) {
super("Start Fade");
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
this.cardPanel = cardPanel;
}
@Override
public void actionPerformed(ActionEvent e) {
counter = 0;
fade = true;
setEnabled(false);
CardLayout cl = (CardLayout) cardPanel.getLayout();
cl.show(cardPanel, PANEL_1);
Window topLevelWindow = SwingUtilities.getWindowAncestor(cardPanel);
glassPane = (JComponent) ((RootPaneContainer) topLevelWindow).getRootPane().getGlassPane();
glassPane.setVisible(true);
glassPane.setLayout(null);
coverPanel.setSize(cardPanel.getSize());
int x = cardPanel.getLocationOnScreen().x - glassPane.getLocationOnScreen().x;
int y = cardPanel.getLocationOnScreen().y - glassPane.getLocationOnScreen().y;
Point coverPanelPoint = new Point(x, y);
coverPanel.setLocation(coverPanelPoint);
glassPane.add(coverPanel);
fadeTimer = new Timer(FADE_DELAY, e2 -> fadeTimerActionPerformed(e2));
fadeTimer.start();
}
private void fadeTimerActionPerformed(ActionEvent e) {
coverPanel.setBackground(new Color(0, 0, 0, counter));
glassPane.repaint();
if (fade) {
counter++;
} else if (counter > 0) {
counter--;
} else {
glassPane.remove(coverPanel);
glassPane.setVisible(false);
setEnabled(true);
((Timer) e.getSource()).stop();
}
if (counter >= UNFADE_VALUE) {
fade = false;
CardLayout cl = (CardLayout) cardPanel.getLayout();
cl.show(cardPanel, PANEL_2);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Test2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Upvotes: 1