Related
When I click background selector on my main panel, it takes a while to load the JPanel and I wanted to show a loading JLabel whilst the background selector panel is loading, then disappear when the panel finally shows up. I tried to implement this in my buttons action listener. But for some reason when I remove the backgroundPanel() method from the action listener (aka panel is not being loaded when JButton is clicked but rather just the JLabel showing up), the label shows up when the button is clicked, but normally the label does not appear. I cannot understand why.
Window class:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
/**
*
*/
public class Window {
public static JFrame frame;
GameWindow game;
BackgroundSelector background;
static DifficultySelector difficulty;
public static MainBackgroundImage main; // start window
JProgressBar progressBar = new JProgressBar();
private boolean loaded = false;
public Window() throws IOException {
frame = new JFrame("Brick Builder Game"); // creates JFrame
game = new GameWindow(); // creates new GAME window
main = new MainBackgroundImage(); // creates MAIN screen
background = new BackgroundSelector(); // creates BACKGROUND SELECTOR window
difficulty = new DifficultySelector(); // creates DIFFICULTY SELECTOR window
main.setLayout(null);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.setVisible(true);
frame.setResizable(false);
frame.getContentPane().add(main); // adds MAIN screen to frame
JButton start = new JButton();
Image startImg = ImageIO.read(getClass().getResource("start.png"));
start.setIcon(new ImageIcon(startImg));
start.setBounds(150,270,200,40);
start.setOpaque(false);
start.setBorderPainted(false);
JButton backgroundSelector = new JButton();
Image selectorImg = ImageIO.read(getClass().getResource("selector.png"));
backgroundSelector.setIcon(new ImageIcon(selectorImg));
backgroundSelector.setBounds(150, 320,200,40);
backgroundSelector.setOpaque(false);
backgroundSelector.setBorderPainted(false);
JButton quit = new JButton();
Image quitImg = ImageIO.read(getClass().getResource("quit.png"));
quit.setIcon(new ImageIcon(quitImg));
quit.setBounds(150,370,200,40);
quit.setOpaque(false);
quit.setBorderPainted(false);
JLabel loading = new JLabel();
loading.setBounds(150,400,100,20);
main.repaint();
start.setBackground(Color.white);
backgroundSelector.setBackground(Color.white);
quit.setBackground(Color.white);
start.setFocusable(false);
quit.setFocusable(false);
backgroundSelector.setFocusable(false);
start.setAlignmentX(Component.CENTER_ALIGNMENT);
quit.setAlignmentX(Component.CENTER_ALIGNMENT);
backgroundSelector.setAlignmentX(Component.CENTER_ALIGNMENT);
main.add(start); // adds JButton
main.add(quit);
main.add(backgroundSelector);
main.add(loading);
main.add(progressBar);
start.addActionListener(e -> difficultyPanel());
quit.addActionListener(e -> {
frame.dispose();
});
backgroundSelector.addActionListener(e -> {
loading.setText("Loading...");
backgroundPanel();
});
//backgroundSelector.addActionListener(e -> backgroundPanel());
}
public static void mainPanel(){
frame.getContentPane().removeAll();
frame.getContentPane().add(main);
frame.validate();
}
public void backgroundPanel(){
//loaded = false;
frame.getContentPane().removeAll();
background = new BackgroundSelector();
frame.getContentPane().add(background);
frame.revalidate();
}
public void difficultyPanel(){
frame.getContentPane().removeAll();
difficulty = new DifficultySelector();
frame.getContentPane().add(difficulty);
frame.requestFocusInWindow();
frame.revalidate();
}
public static void main (String[]args) throws IOException {
new Window();
}
}
Background selector class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyListener;
/**
* This class creates the background selector JPanel which allows the player to choose a background
* of their choice. A choice of 6 backgrounds is given to the player to choose from.
*
*/
public class BackgroundSelector extends JPanel{
DifficultySelector difficulty = new DifficultySelector();
private final ClassLoader cl = Thread.currentThread().getContextClassLoader();
private final Image image = Toolkit.getDefaultToolkit().getImage(cl.getResource("black.jpg"));
JLabel label;
// creates the radioButtons which display the backgrounds to choose from
JRadioButton radioButton;
JRadioButton radioButton2;
JRadioButton radioButton3;
JRadioButton radioButton4;
JRadioButton radioButton5;
JRadioButton radioButton6;
public static boolean option1 = false;
public static boolean option2 = false;
public static boolean option3 = false;
public static boolean option4 = false;
public static boolean option5 = false;
public static boolean option6 = false;
/**
* Constructor which adds the radio buttons to a button group and displays them on the JPanel using a flow layout.
*
*/
public BackgroundSelector(){
label = new JLabel("Please select a background", JLabel.CENTER);
label.setFont(new Font("Verdana", Font.BOLD, 18));
label.setForeground(Color.white);
setLayout(new FlowLayout());
ButtonGroup group = new ButtonGroup();
group.add(radioButton);
group.add(radioButton2);
group.add(radioButton3);
group.add(radioButton4);
group.add(radioButton5);
group.add(radioButton6);
option1();
option2();
option3();
option4();
option5();
option6();
add(label);
}
/**
* Paints background image of panel to black chalk image.
* #param g
*/
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
image.getScaledInstance(500, 500,Image.SCALE_SMOOTH);
while(!prepareImage(image, this)) {
prepareImage(image, this);
}
g.drawImage(image,0,0,null);
}
/**
* Converts the url to an image which will be used as the icon for the JRadioButton.
*
* #param url The url of the image.
* #return The image with a specific height and width.
*/
public String URL(String url){
return "<html><body><img src='" + url + "'width=128 height=128>";
}
/**
* Adds radioButton to the JPanel, when clicked, creates a new game with the space background.
*
*/
public void option1() {
String url = URL("https://www.nasa.gov/sites/default/files/styles/full_width/public/thumbnails/image/main_image_star-forming_region_carina_nircam_final-1280.jpg");
radioButton = new JRadioButton(url);
add(radioButton);
radioButton.addActionListener(e -> {
Window.frame.getContentPane().removeAll();
//game.changeFilepath("space.jpg");
Window.frame.getContentPane().add(difficulty);
Window.frame.requestFocusInWindow();
Window.frame.revalidate();
option1 = true;
});
}
/**
* Adds radioButton to the JPanel, when clicked, creates a new game with the bricks background.
*
*/
public void option2(){
String url = URL("https://appgrooves.com/cdn/mc/GAME_ARCADE/7_w1200.jpg");
radioButton2 = new JRadioButton(url);
add(radioButton2);
radioButton2.addActionListener(e -> {
Window.frame.getContentPane().removeAll();
//game.changeFilepath("space.jpg");
Window.frame.getContentPane().add(difficulty);
Window.frame.requestFocusInWindow();
Window.frame.revalidate();
option2 = true;
});
}
/**
* Adds radioButton to the JPanel, when clicked, creates a new game with the stars background.
*
*/
public void option3(){
String url = URL("https://upload.wikimedia.org/wikipedia/commons/2/26/Oldest_star_in_solar_neighbourhood.jpg");
radioButton3 = new JRadioButton(url);
add(radioButton3);
radioButton3.addActionListener(e -> {
Window.frame.getContentPane().removeAll();
//game.changeFilepath("stars.jpg");
Window.frame.getContentPane().add(difficulty);
Window.frame.requestFocusInWindow();
Window.frame.revalidate();
option3 = true;
});
}
/**
* Adds radioButton to the JPanel, when clicked, creates a new game with the bubbles background.
*
*/
public void option4(){
String url = URL("https://cdn.pocket-lint.com/assets/images/131835-phones-news-feature-cropped-best-iphone-wallpapers-image72-7pqcs1gy9h.jpg");
radioButton4 = new JRadioButton(url);
add(radioButton4);
radioButton4.addActionListener(e -> {
Window.frame.getContentPane().removeAll();
//game.changeFilepath("stars.jpg");
Window.frame.getContentPane().add(difficulty);
Window.frame.requestFocusInWindow();
Window.frame.revalidate();
option4 = true;
});
}
/**
* Adds radioButton to the JPanel, when clicked, creates a new game with the forest background.
*
*/
public void option5(){
String url = URL("https://images.hdqwalls.com/download/blue-forest-minimal-4k-kz-2048x2048.jpg");
radioButton5 = new JRadioButton(url);
add(radioButton5);
radioButton5.addActionListener(e -> {
Window.frame.getContentPane().removeAll();
//game.changeFilepath("stars.jpg");
Window.frame.getContentPane().add(difficulty);
Window.frame.requestFocusInWindow();
Window.frame.revalidate();
option5 = true;
});
}
/**
* Adds radioButton to the JPanel, when clicked, creates a new game with the japanese purple background.
*
*/
public void option6(){
String url = URL("https://www.pixelstalk.net/wp-content/uploads/images5/Cool-Japanese-Backgrounds-HD-Free-download.jpg");
radioButton6 = new JRadioButton(url);
add(radioButton6);
radioButton6.addActionListener(e -> {
Window.frame.getContentPane().removeAll();
//game.changeFilepath("stars.jpg");
Window.frame.getContentPane().add(difficulty);
Window.frame.requestFocusInWindow();
Window.frame.revalidate();
option6 = true;
});
}
}
Just add the following method to the background selector :)
and call it on background() method in window
public void resetLayout() {
radioButton.setSelected(false);
radioButton2.setSelected(false);
radioButton3.setSelected(false);
radioButton4.setSelected(false);
radioButton5.setSelected(false);
radioButton6.setSelected(false);
}
really ugly, could be better, but works!
Not been able to run the code leads to a number of assumptions.
Based on you description, I would say you are blocking the Event Dispatching Thread while loading the image, this is going to prevent the UI from been updated.
See Concurrency in Swing for more details. I'd recommend using a SwingWorker to actually load the image.
You should also be making use of layout managers, you'd find CardLayout especially helpful for switching between components.
For example...
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class MainPane extends JPanel {
public interface Observer {
public void start();
public void quit();
public void didLoadBackground(BufferedImage img);
}
enum View {
MAIN, START
}
private BufferedImage background;
private CardLayout cardLayout;
public MainPane() throws IOException {
cardLayout = new CardLayout();
setLayout(cardLayout);
background = ImageIO.read(getClass().getResource("/images/Mando01.jpeg"));
add(new OptionsPane(new Observer() {
#Override
public void start() {
show(View.START);
}
#Override
public void quit() {
SwingUtilities.windowForComponent(MainPane.this).dispose();
}
#Override
public void didLoadBackground(BufferedImage img) {
JOptionPane.showMessageDialog(MainPane.this, "You have a pretty picture", "Notice", JOptionPane.INFORMATION_MESSAGE);
}
}), View.MAIN);
add(new GamePane(), View.START);
}
public void add(Component component, View view) {
add(component, view.name());
}
public void show(View view) {
cardLayout.show(this, view.name());
}
#Override
public Dimension getPreferredSize() {
if (background != null) {
return new Dimension(background.getWidth(), background.getHeight());
}
return super.getPreferredSize();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background == null) {
return;
}
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g.drawImage(background, x, y, this);
}
}
public class OptionsPane extends JPanel {
private MainPane.Observer observer;
public OptionsPane(MainPane.Observer observer) {
setOpaque(false);
setLayout(new GridBagLayout());
JButton start = new JButton("Start");
start.setOpaque(false);
start.setBorderPainted(false);
start.setForeground(Color.WHITE);
JButton backgroundSelector = new JButton("Background");
backgroundSelector.setOpaque(false);
backgroundSelector.setBorderPainted(false);
backgroundSelector.setForeground(Color.WHITE);
JButton quit = new JButton("Quit");
quit.setOpaque(false);
quit.setBorderPainted(false);
quit.setForeground(Color.WHITE);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weighty = 1;
gbc.anchor = GridBagConstraints.SOUTH;
gbc.insets = new Insets(4, 4, 4, 4);
add(start, gbc); // adds JButton
gbc.weighty = 0;
gbc.gridy++;
add(backgroundSelector, gbc);
gbc.gridy++;
add(quit, gbc);
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.start();
}
});
quit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.quit();
}
});
backgroundSelector.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// This "could" use the glassPane, but that's
// an additional complexity
JPanel panel = new JPanel(new GridBagLayout());
JLabel label = new JLabel("Loading...");
label.setHorizontalAlignment(JLabel.CENTER);
JProgressBar progressBar = new JProgressBar(0, 100);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.fill = gbc.HORIZONTAL;
panel.setBorder(new EmptyBorder(8, 8, 8, 8));
panel.add(label, gbc);
panel.add(progressBar, gbc);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = gbc.REMAINDER;
gbc.gridheight = gbc.REMAINDER;
add(panel, gbc);
revalidate();
repaint();
SwingWorker<BufferedImage, Void> worker = new SwingWorker<BufferedImage, Void>() {
#Override
protected BufferedImage doInBackground() throws Exception {
for (int progress = 0; progress <= 100; progress++) {
Thread.sleep(50);
setProgress(progress);
}
return null;
}
};
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (worker.getState() == SwingWorker.StateValue.DONE) {
remove(panel);
revalidate();
repaint();
try {
observer.didLoadBackground(worker.get());
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(OptionsPane.this, "Failed to load image", "Error", JOptionPane.ERROR_MESSAGE);
}
} else if ("progress".equalsIgnoreCase(name)) {
progressBar.setValue((int)evt.getNewValue());
}
}
});
worker.execute();
}
});
}
}
public class GamePane extends JPanel {
public GamePane() {
setOpaque(false);
setLayout(new GridBagLayout());
add(new JLabel("Let's get this party started"));
}
}
}
Now, if you want progress feedback when loading an image, that's a much more complex solution, see Using JProgressBar while converting image to byte array for more details
okay but now I am running into another issue. With card layout i cannot add key listener, setFocusable or requestFocusableInWindow so my paddle is not moving when i start the game
Stop using KeyListener, it's not an appropriate mechanism for what you're trying to achieve, instead, use the key bindings API, this will remove the need for all the related KeyListener hacks
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
public class MainPane extends JPanel {
public interface Observer {
public void start();
public void quit();
public void didLoadBackground(BufferedImage img);
}
enum View {
MAIN, START
}
private BufferedImage background;
private CardLayout cardLayout;
public MainPane() throws IOException {
cardLayout = new CardLayout();
setLayout(cardLayout);
background = scaled(ImageIO.read(getClass().getResource("/images/Mando01.jpeg")));
add(new OptionsPane(new Observer() {
#Override
public void start() {
show(View.START);
}
#Override
public void quit() {
SwingUtilities.windowForComponent(MainPane.this).dispose();
}
#Override
public void didLoadBackground(BufferedImage img) {
JOptionPane.showMessageDialog(MainPane.this, "You have a pretty picture", "Notice", JOptionPane.INFORMATION_MESSAGE);
}
}), View.MAIN);
add(new GamePane(), View.START);
}
protected BufferedImage scaled(BufferedImage original) {
BufferedImage scaled = new BufferedImage(original.getWidth() / 2, original.getHeight() / 2, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = scaled.createGraphics();
g2d.transform(AffineTransform.getScaleInstance(0.5, 0.5));
g2d.drawImage(original, 0, 0, this);
g2d.dispose();
return scaled;
}
public void add(Component component, View view) {
add(component, view.name());
}
public void show(View view) {
cardLayout.show(this, view.name());
}
#Override
public Dimension getPreferredSize() {
if (background != null) {
return new Dimension(background.getWidth(), background.getHeight());
}
return super.getPreferredSize();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background == null) {
return;
}
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g.drawImage(background, x, y, this);
}
}
public class OptionsPane extends JPanel {
private MainPane.Observer observer;
public OptionsPane(MainPane.Observer observer) {
setOpaque(false);
setLayout(new GridBagLayout());
JButton start = new JButton("Start");
start.setOpaque(false);
start.setBorderPainted(false);
start.setForeground(Color.WHITE);
JButton backgroundSelector = new JButton("Background");
backgroundSelector.setOpaque(false);
backgroundSelector.setBorderPainted(false);
backgroundSelector.setForeground(Color.WHITE);
JButton quit = new JButton("Quit");
quit.setOpaque(false);
quit.setBorderPainted(false);
quit.setForeground(Color.WHITE);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weighty = 1;
gbc.anchor = GridBagConstraints.SOUTH;
gbc.insets = new Insets(4, 4, 4, 4);
add(start, gbc); // adds JButton
gbc.weighty = 0;
gbc.gridy++;
add(backgroundSelector, gbc);
gbc.gridy++;
add(quit, gbc);
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.start();
}
});
quit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.quit();
}
});
backgroundSelector.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// This "could" use the glassPane, but that's
// an additional complexity
JPanel panel = new JPanel(new GridBagLayout());
JLabel label = new JLabel("Loading...");
label.setHorizontalAlignment(JLabel.CENTER);
JProgressBar progressBar = new JProgressBar(0, 100);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.fill = gbc.HORIZONTAL;
panel.setBorder(new EmptyBorder(8, 8, 8, 8));
panel.add(label, gbc);
panel.add(progressBar, gbc);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = gbc.REMAINDER;
gbc.gridheight = gbc.REMAINDER;
add(panel, gbc);
revalidate();
repaint();
SwingWorker<BufferedImage, Void> worker = new SwingWorker<BufferedImage, Void>() {
#Override
protected BufferedImage doInBackground() throws Exception {
for (int progress = 0; progress <= 100; progress++) {
Thread.sleep(50);
setProgress(progress);
}
return null;
}
};
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (worker.getState() == SwingWorker.StateValue.DONE) {
remove(panel);
revalidate();
repaint();
try {
observer.didLoadBackground(worker.get());
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(OptionsPane.this, "Failed to load image", "Error", JOptionPane.ERROR_MESSAGE);
}
} else if ("progress".equalsIgnoreCase(name)) {
progressBar.setValue((int) evt.getNewValue());
}
}
});
worker.execute();
}
});
}
}
public class GamePane extends JPanel implements DeltaAction.Observer {
public class Box {
private Shape box = new Rectangle2D.Double(0, 0, 50, 50);
private Point p = new Point();
public void paint(Graphics2D g2d) {
g2d = (Graphics2D) g2d.create();
g2d.setColor(Color.BLUE);
g2d.translate(p.getX(), p.getY());
g2d.fill(box);
g2d.dispose();
}
public Point getLocation() {
return new Point(p);
}
public void setLocation(Point p) {
this.p = p;
}
public Rectangle2D getBounds() {
return new Rectangle2D.Double(p.getX(), p.getY(), box.getBounds2D().getHeight(), box.getBounds2D().getHeight());
}
}
protected enum KeyInput {
PRESSED_UP, RELEASED_UP,
PRESSED_DOWN, RELEASED_DOWN,
PRESSED_LEFT, RELEASED_LEFT,
PRESSED_RIGHT, RELEASED_RIGHT;
}
private Box box = new Box();
private int xDelta = 0;
private int yDelta = 0;
private Timer timer;
public GamePane() {
setOpaque(false);
setLayout(new GridBagLayout());
add(new JLabel("Let's get this party started"));
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), KeyInput.PRESSED_UP);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), KeyInput.RELEASED_UP);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), KeyInput.PRESSED_DOWN);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), KeyInput.RELEASED_DOWN);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), KeyInput.PRESSED_LEFT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), KeyInput.RELEASED_LEFT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), KeyInput.PRESSED_RIGHT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), KeyInput.RELEASED_RIGHT);
am.put(KeyInput.PRESSED_UP, new DeltaAction(DeltaAction.Direction.UP, true, this));
am.put(KeyInput.RELEASED_UP, new DeltaAction(DeltaAction.Direction.UP, false, this));
am.put(KeyInput.PRESSED_DOWN, new DeltaAction(DeltaAction.Direction.DOWN, true, this));
am.put(KeyInput.RELEASED_DOWN, new DeltaAction(DeltaAction.Direction.DOWN, false, this));
am.put(KeyInput.PRESSED_LEFT, new DeltaAction(DeltaAction.Direction.LEFT, true, this));
am.put(KeyInput.RELEASED_LEFT, new DeltaAction(DeltaAction.Direction.LEFT, false, this));
am.put(KeyInput.PRESSED_RIGHT, new DeltaAction(DeltaAction.Direction.RIGHT, true, this));
am.put(KeyInput.RELEASED_RIGHT, new DeltaAction(DeltaAction.Direction.RIGHT, false, this));
timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Point location = box.getLocation();
location.x += xDelta;
location.y += yDelta;
box.setLocation(location);
Rectangle2D bounds = box.getBounds();
if (bounds.getX() < 0) {
location.x = 0;
} else if (bounds.getX() + bounds.getWidth() > getWidth()) {
location.x = (int)(getWidth() - bounds.getWidth());
}
if (bounds.getY() < 0) {
location.y = 0;
} else if (bounds.getY() + bounds.getHeight()> getHeight()) {
location.y = (int)(getHeight() - bounds.getHeight());
}
box.setLocation(location);
repaint();
}
});
addComponentListener(new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent e) {
timer.stop();
}
#Override
public void componentShown(ComponentEvent e) {
System.out.println("Hello");
timer.start();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
box.paint(g2d);
g2d.dispose();
}
#Override
public void directionApplied(DeltaAction.Direction direction, boolean activate) {
switch (direction) {
case UP:
yDelta = activate ? -4 : 0;
break;
case DOWN:
yDelta = activate ? 4 : 0;
break;
case LEFT:
xDelta = activate ? -4 : 0;
break;
case RIGHT:
xDelta = activate ? 4 : 0;
break;
}
}
}
public class DeltaAction extends AbstractAction {
public interface Observer {
public void directionApplied(Direction direction, boolean activate);
}
public enum Direction {
UP, DOWN, LEFT, RIGHT;
}
private Direction direction;
private boolean activate;
private Observer observer;
public DeltaAction(Direction direction, boolean activate, Observer observer) {
this.direction = direction;
this.activate = activate;
this.observer = observer;
}
#Override
public void actionPerformed(ActionEvent e) {
observer.directionApplied(direction, activate);
}
}
}
I am getting so many bugs with card layout, its ruining my whole application
This has nothing to do with CardLayout but you choices in how you designed you original application. Layouts are your friends, make the time to learn how to use them
I don't see how I can update the background panel if its ALREADY added to the card pane, the only way I can think of is destroying it and adding a new one each time (which is what i have but is taking very long to load)
Then don't - this is my whole point, you need to change the way you think about the problem.
To change the background image of the background pane, all you need to do is change the reference to the background image the panel is using.
I'd have a "base" pane, which would use a BorderLayout and contain the "background" pane. The "background" pane would then have the CardLayout set to it and it would then become the parent container for all the other components.
When the user selects a new image, you'd make use of the "observer pattern" to generate a notification back to the "base" pane which would then assign the new image to the background pane.
I've run out of room to post any new updates, so this the last one I can provide via a simple gist
I am trying to create a GUI and in that GUI I have different JLabels with a value. I want to be able to click on a JLabel to edit it in my JTextfield (only have 1) and after I press enter it should leave Editing the JLabel. At the moment if I try to edit a JLabel it will change but when I click on the next one the old one will also still change.
This is my code:
public class GUI {
JFrame frame;
int n1=1;
int n2=1;
int n3=1;
GUI(){
frame=new JFrame();//creating instance of JFrame
JLabel l1=new JLabel(Integer.toString(n1));
JLabel l2=new JLabel(Integer.toString(n2));
JLabel l3=new JLabel(Integer.toString(n3));
JTextField t=new JTextField();
l1.setBounds(40,50,100, 40);
l2.setBounds(40,100,100, 40);
l3.setBounds(40,150,100, 40);
t.setBounds(20,200,100, 40);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
l1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
l1.setText(t.getText());
n1=parseInt(t.getText());
}
});
}
});
l2.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
l2.setText(t.getText());
n2=parseInt(t.getText());
}
});
}
});
frame.setSize(400,500);//400 width and 500 height
frame.setLayout(null);//using no layout managers
frame.setVisible(true);//making the frame visible
}
public static void main(String[] args) {
new GUI();
}
}
Thanks in advance.
Don't add action listeners for each click. Clicking on a label should record the state of your UI -- that that label is now being edited, and set up the value in the JTextField. Then enter should transfer the value to the JLabel which was recorded as selected.
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GUI {
JLabel currentEditLabel = null;
JFrame frame;
int n1 = 1;
int n2 = 1;
int n3 = 1;
GUI() {
frame = new JFrame();//creating instance of JFrame
JLabel l1 = new JLabel(Integer.toString(n1));
JLabel l2 = new JLabel(Integer.toString(n2));
JLabel l3 = new JLabel(Integer.toString(n3));
JTextField t = new JTextField();
l1.setBounds(40, 50, 100, 40);
l2.setBounds(40, 100, 100, 40);
l3.setBounds(40, 150, 100, 40);
t.setBounds(20, 200, 100, 40);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (currentEditLabel != null) {
currentEditLabel.setText(t.getText());
currentEditLabel = null;
}
}
});
addMouseListener(l1, t);
addMouseListener(l2, t);
addMouseListener(l3, t);
frame.setSize(400, 500);//400 width and 500 height
frame.setLayout(null);//using no layout managers
frame.setVisible(true);//making the frame visible
}
private void addMouseListener(JLabel label, JTextField t) {
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
currentEditLabel = (JLabel) e.getComponent();
t.setText(currentEditLabel.getText());
}
});
}
public static void main(String[] args) {
new GUI();
}
}
Figuring out how to set n1, n2, ... is left as an exercise, as is how to indicate in the UI that no label is selected (hint: should you allow input in the JTextField when no label has been selected?)
As #kleopatra says, using no layout manager is not good practice, as if your panel is resized (perhaps your program will be run on a mobile device, for instance) your components may become hidden, See this discussion.
Here's your code using GridLayout, a simple layout manager.
Points to note:
I've removed the absolute positioning and sizing of the components and the frame.
The frame is now resizable, so you can see what the layout manager does as the size changes.
The JFrame is packed before displaying it.
To get a layout which does exactly what you want you can look at GridBagLayout, and also think about nesting containers with simple layout managers.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GUI {
JLabel currentEditLabel = null;
JFrame frame;
int n1 = 1;
int n2 = 1;
int n3 = 1;
GUI() {
frame = new JFrame();
JLabel l1 = new JLabel(Integer.toString(n1));
JLabel l2 = new JLabel(Integer.toString(n2));
JLabel l3 = new JLabel(Integer.toString(n3));
JTextField t = new JTextField();
GridLayout layout = new GridLayout(4, 1, 10, 10);
frame.setLayout(layout);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
frame.setResizable(true);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (currentEditLabel != null) {
currentEditLabel.setText(t.getText());
currentEditLabel = null;
}
}
});
addMouseListener(l1, t);
addMouseListener(l2, t);
addMouseListener(l3, t);
frame.pack();
frame.setVisible(true);//making the frame visible
}
private void addMouseListener(JLabel label, JTextField t) {
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
currentEditLabel = (JLabel) e.getComponent();
t.setText(currentEditLabel.getText());
}
});
}
public static void main(String[] args) {
new GUI();
}
}
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!
I would try these things:
Use the GlassPane of the top-level window and make a section of it darker where you want to cover things up, using a Swing Timer.
Use a CardLayout to swap the underlying components, and make the swap when the covering JPanel is darkest.
Then undarken the covering panel after the swap.
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);
});
}
}
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);
}
}
}
}
I am coding a GUI containing a JScrollPane that displays an image that gets updated (with potential modification of its dimensions). The image is in an ImageIcon in a JLabel. The image size is retrieved using ImageIcon.getIconWith() and getIconHeight(). And the JLabel preferred size is updated with those dimensions.
When the application is started for the first time, the JScrollPane and its scrollbars have the right dimensions to view the whole image (potentially using scrolling). But when the image gets updated the JScrollPane and the scrollbars assume the image has the dimensions of the previous image. How do I get the JScrollPane to update correctly ?
Here is a curated version of my GUI. Visualizer.java uses the GUI VisualizerGUI.java. When the "Run" button is pushed, a new image is randomly generated using ImageDrawer.drawImage() (simulates the behavior of the real application) and the content of the JScrollPane is updated using the function VisualizerGUI.setTransitionsImage(String imgPath).
Visualizer.java:
import java.util.*;
import java.io.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Visualizer implements ActionListener {
private VisualizerGUI gui = null;
public Visualizer() {
gui = VisualizerGUI.createAndStart(this);
}
public static void main(String[] args) {
Visualizer viz = new Visualizer();
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Run command")) {
run();
}
}
public void run() {
updateGUIwithSolution();
}
public void updateGUIwithSolution() {
gui.initGUIupdate();
try {
ImageDrawer.drawImage();
gui.setTransitionsImage("image.png");
} catch (Exception e) {
System.out.println("Error while generating image");
e.printStackTrace();
}
gui.finalizeGUIupdate();
}
}
VisualizerGUI.java:
import java.util.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.lang.reflect.InvocationTargetException;
public final class VisualizerGUI {
private JFrame frame;
private JButton runButton;
private JButton nextButton;
private JScrollPane transitionsDisplay;
private JTabbedPane executionsDisplay;
private JTabbedPane tracesDisplay;
private JTextArea textInfoArea;
public VisualizerGUI() {}
private void initGUI(ActionListener actionsHandler) {
//Create and set up the window.
frame = new JFrame("Visualizer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel controlPanel = new JPanel(new FlowLayout());
runButton = new JButton("Run");
runButton.addActionListener(actionsHandler);
runButton.setActionCommand("Run command");
controlPanel.add(runButton);
nextButton = new JButton("Next");
nextButton.addActionListener(actionsHandler);
nextButton.setActionCommand("Find next solution");
controlPanel.add(nextButton);
transitionsDisplay = new JScrollPane();
executionsDisplay = new JTabbedPane();
tracesDisplay = new JTabbedPane();
JSplitPane ETspliter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, executionsDisplay, tracesDisplay);
JSplitPane graphsSpliter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, transitionsDisplay, ETspliter);
textInfoArea = new JTextArea();
textInfoArea.setLineWrap(true);
textInfoArea.setWrapStyleWord(true);
textInfoArea.setEditable(false);
JScrollPane textInfoAreaSP = new JScrollPane(textInfoArea);
JSplitPane topSpliter = new JSplitPane(JSplitPane.VERTICAL_SPLIT, graphsSpliter, textInfoAreaSP);
transitionsDisplay.setPreferredSize(new Dimension(200,200));
executionsDisplay.setPreferredSize(new Dimension(200,200));
tracesDisplay.setPreferredSize(new Dimension(200,200));
textInfoAreaSP.setPreferredSize(new Dimension(200,100));
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(controlPanel, BorderLayout.NORTH);
frame.getContentPane().add(topSpliter, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public static VisualizerGUI createAndStart(ActionListener actionsHandler) {
VisualizerGUI gui = new VisualizerGUI();
final Runnable guiRunner =
new Runnable() {
public void run() {
gui.initGUI(actionsHandler);
// gui.pack();
}
};
try {
javax.swing.SwingUtilities.invokeAndWait(guiRunner);
} catch (InterruptedException e) {
System.out.println(">>> WARNING <<< InterruptedException while creating the GUI");
} catch (InvocationTargetException e) {
System.out.println(">>> WARNING <<< InvocationTargetException while creating the GUI");
}
return gui;
}
public void clear() {
initGUIupdate();
finalizeGUIupdate();
}
public void initGUIupdate() {
// frame.setVisible(false);
transitionsDisplay.setViewportView(null);
executionsDisplay.removeAll();
tracesDisplay.removeAll();
textInfoArea.setText(null);
}
public void pack() {
frame.pack();
}
public void finalizeGUIupdate() {
// frame.validate();
// frame.repaint();
// frame.setVisible(true);
}
public void setTransitionsImage(String imgPath) {
ImageIcon icon = new ImageIcon(imgPath);
icon.getImage().flush();
int width = icon.getIconWidth();
int height = icon.getIconHeight();
JLabel label = new JLabel();
label.setVerticalAlignment(SwingConstants.CENTER);
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setIcon(icon);
label.setPreferredSize(new Dimension(width,height));
//label.setPreferredSize(null);
transitionsDisplay.setViewportView(label);
label.revalidate();
label.repaint();
transitionsDisplay.getViewport().revalidate();
transitionsDisplay.getViewport().repaint();
transitionsDisplay.revalidate();
// transitionsDisplay.validate();
transitionsDisplay.repaint();
frame.revalidate();
// frame.validate();
frame.repaint();
}
public void setTransitionsImageInED(String imgPath) {
final Runnable guiRunner =
new Runnable() {
public void run() { setTransitionsImage(imgPath); }
};
// javax.swing.SwingUtilities.invokeLater(guiRunner);
try {
javax.swing.SwingUtilities.invokeAndWait(guiRunner);
} catch (InterruptedException e) {
System.out.println(">>> WARNING <<< InterruptedException while creating the GUI");
} catch (InvocationTargetException e) {
System.out.println(">>> WARNING <<< InvocationTargetException while creating the GUI");
}
}
}
ImageDrawer.java:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageDrawer {
public static void drawImage() throws Exception {
try {
int width = 20 + (int)(Math.random() * 1000);
int height = 20 + (int)(Math.random() * 1000);
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D ig2 = bi.createGraphics();
ig2.setPaint(Color.blue);
ig2.fillRect(0, 0, width, height);
ig2.setPaint(Color.red);
ig2.fillRect(5, 5, width - 10, height - 10);
ig2.setPaint(Color.blue);
ig2.drawLine(0, 0, width, height);
ig2.drawLine(0, height, width, 0);
ImageIO.write(bi, "PNG", new File("image.png"));
} catch (IOException ie) {
ie.printStackTrace();
}
}
}
Can someone explain why I have this problem? Thanks!
transitionsDisplay.setPreferredSize(new Dimension(200,200));
executionsDisplay.setPreferredSize(new Dimension(200,200));
tracesDisplay.setPreferredSize(new Dimension(200,200));
textInfoAreaSP.setPreferredSize(new Dimension(200,100));
Don't use setPreferredSize(...). Each Swing component is responsible for determining its own size.
The image size is retrieved using ImageIcon.getIconWith() and getIconHeight(). And the JLabel preferred size is updated with those dimensions.
Not necessary. Again the JLabel will determine its own size based on the size of the Icon. This is done dynamically as the image/icon changes.
The scrollbars of the scrollpane will appear when the preferred size of the label is greater than the size of the scrollpane. Just let the layout managers do their job.
I have a JButton which I want to set the background to a color.
JButton button = new JButton();
button.setVisible(true);
button.setPreferredSize(new Dimension(student_scroll.getWidth(), 50));
button.setBorder(BorderFactory.createLineBorder(Color.WHITE, 1));
button.setBackground(Color.BLACK);
button.setForeground(Color.WHITE);
button.setOpaque(true);
I used this for mac and it showed up as I wanted it to be. However, upon trying it on windows, the foreground is white(as it should) but the background is empty.
Setting background color to JButton
says to add button.setContentAreaFilled(false); which I did but had no effect. Most others say to add button.setOpaque(true);which I also did already.
What else do I have to do so that it will show up with a black background?
EDIT
As requested, the SSCCE:
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MainSwing extends JFrame {
private static final long serialVersionUID = -8231889836024827530L;
public static void main(String[] args) {
try {
System.setProperty("apple.laf.useScreenMenuBar", "true");
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Test");
UIManager.put("ScrollBarUI", "main.CustomScrollBarUI");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(ClassNotFoundException e) {
System.out.println("ClassNotFoundException: " + e.getMessage());
}
catch(InstantiationException e) {
System.out.println("InstantiationException: " + e.getMessage());
}
catch(IllegalAccessException e) {
System.out.println("IllegalAccessException: " + e.getMessage());
}
catch(UnsupportedLookAndFeelException e) {
System.out.println("UnsupportedLookAndFeelException: " + e.getMessage());
}
SwingUtilities.invokeLater( new Runnable() {
public void run() {
JFrame frame = new JFrame() {
Container c = getContentPane();
JButton button = new JButton("Hello");
{
button.setText("Hello");
button.setVisible(true);
button.setPreferredSize(new Dimension(100, 50));
button.setBorder(BorderFactory.createLineBorder(Color.WHITE, 1));
button.setBackground(Color.BLACK);
button.setForeground(Color.WHITE);
button.setOpaque(true);
c.add(button);
}
};
frame.setSize(500, 500);
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
It seems that the problem has something to do with the line: UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); as when I remove it, the buttons are black.
I'm guessing from those UIManager key/value pairs that the PLAF is the OS X based Aqua PLAF. And that seems to be part of the problem here. Here it is without the content area filled on Windows.
import java.awt.*;
import javax.swing.*;
public class MainSwing extends JFrame {
public static void main(String[] args) {
try {
System.setProperty("apple.laf.useScreenMenuBar", "true");
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Test");
UIManager.put("ScrollBarUI", "main.CustomScrollBarUI");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace(); // more info for less LOC!
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame() {
Container c = getContentPane();
JButton button = new JButton("Hello");
{
c.setLayout(new GridLayout(0,1));
c.add(new JButton("Hi"));
button.setText(UIManager.getSystemLookAndFeelClassName());
button.setVisible(true);
button.setPreferredSize(new Dimension(400, 100));
button.setBorder(BorderFactory.createLineBorder(Color.WHITE, 1));
button.setContentAreaFilled(false);
button.setBackground(Color.BLACK);
button.setForeground(Color.WHITE);
button.setOpaque(true);
c.add(button);
}
};
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
It seems that the problem has something to do with the line: UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); as when I remove it, the buttons are black.
So that is extra information we didn't have before you created the SSCCE (which is why you should always post a SSCCE with your question).
It also tells you the problem is not with your code but with the LAF. The Windows LAF ignores the setBackground(...) method and paints its own background.
One option would be to add an Icon to the button of your desired color. Then you can configure the text to be painted in the center of the button:
import java.awt.*;
import javax.swing.*;
public class ColorIcon implements Icon
{
private Color color;
private int width;
private int height;
public ColorIcon(Color color, int width, int height)
{
this.color = color;
this.width = width;
this.height = height;
}
public int getIconWidth()
{
return width;
}
public int getIconHeight()
{
return height;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
g.setColor(color);
g.fillRect(x, y, width, height);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI()
{
JPanel panel = new JPanel( new GridLayout(2, 2) );
for (int i = 0; i < 4; i++)
{
Icon icon = new ColorIcon(Color.RED, 50, 50);
JButton label = new JButton( icon );
label.setText("" + i);
label.setHorizontalTextPosition(JButton.CENTER);
label.setVerticalTextPosition(JButton.CENTER);
panel.add(label);
}
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(panel);
f.setSize(200, 200);
f.setLocationRelativeTo( null );
f.setVisible(true);
}
}
Then is should work on all LAF's.