I am working on a Java Swing application.
My Requirement :-
In my JFrame, I have a JList with values "One", "Two", "Three" etc. When I select one list item, I want to show "n" buttons where "n" is the value selected.
Example :- If I select "Three" from the list, there should be 3 buttons in the JFrame.
Below is my code :-
public class Details extends JFrame {
String[] navData = new String{"One","Two","Three","Four"};
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Details frame = new Details();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Details() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Toolkit tk = Toolkit.getDefaultToolkit();
int xSize = ((int) tk.getScreenSize().getWidth());
int ySize = ((int) tk.getScreenSize().getHeight());
//frame.setSize(xSize,ySize);
setTitle("Test");
setBounds(0, 0, 776, 457);
setResizable(false);
//setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
final JList list = new JList(navData);
list.setBounds(0, 0, 140, ySize);
contentPane.add(list);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setFixedCellHeight(50);
list.setFixedCellWidth(70);
list.setBorder(new EmptyBorder(10,10, 10, 10));
list.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent arg0) {
int numButtons;
String selectedItem = navData[list.getSelectedIndex()];
switch (selectedItem) {
case "One":
addButtons(1);
break;
case "Two":
addButtons(2);
break;
case "Three":
addButtons(3);
break;
case "Four":
addButtons(4);
break;
default:
break;
}
}
});
list.setSelectedIndex(0);
}
public void addButtons(int n)
{
revalidate();
for(int i = 0; i<n;i++)
{
JButton button = new JButton(" "+navData[i]);
button.setBounds(200 + (i*50), 150, 50, 50);
contentPane.add(button);
}
}
}
- Problem :-
When I change the selected item in the list, the JPanel is not getting updated. In other words, I don't get 3 buttons when I select "Three" from the List. I get only 1 button which was created by the default selection.
I made these changes:
I put the JList in a JPanel, and the JButtons in another JPanel.
I used the FlowLayout for the JList JPanel, and the FlowLayout for the JButtons JPanel. You're free to change these Swing layouts if you wish.
I changed the default to 4 buttons, so the JFrame would pack properly for up to 4 JButtons.
I added a method to remove the JButtons from the JPanel before trying to add JButtons to the JPanel.
I revalidated and repainted the JButton JPanel.
Here's the code:
package com.ggl.testing;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class Details extends JFrame {
private static final long serialVersionUID = -555805219508469709L;
private String[] navData = { "One", "Two", "Three", "Four" };
private JPanel buttonPanel;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Details frame = new Details();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Details() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setTitle("Test");
buttonPanel = new JPanel();
JPanel listPanel = new JPanel();
final JList<String> list = new JList<String>(navData);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setFixedCellHeight(50);
list.setFixedCellWidth(70);
list.setBorder(new EmptyBorder(10, 10, 10, 10));
list.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent event) {
String selectedItem = navData[list.getSelectedIndex()];
switch (selectedItem) {
case "One":
removeButtons(buttonPanel);
addButtons(buttonPanel, 1);
break;
case "Two":
removeButtons(buttonPanel);
addButtons(buttonPanel, 2);
break;
case "Three":
removeButtons(buttonPanel);
addButtons(buttonPanel, 3);
break;
case "Four":
removeButtons(buttonPanel);
addButtons(buttonPanel, 4);
break;
default:
break;
}
}
});
list.setSelectedIndex(3);
listPanel.add(list);
add(listPanel, BorderLayout.WEST);
add(buttonPanel, BorderLayout.CENTER);
pack();
}
public void removeButtons(JPanel panel) {
Component[] components = panel.getComponents();
for (int i = 0; i < components.length; i++) {
panel.remove(components[i]);
}
}
public void addButtons(JPanel panel, int n) {
for (int i = 0; i < n; i++) {
JButton button = new JButton(navData[i]);
panel.add(button);
}
panel.revalidate();
panel.repaint();
}
}
Replace contentPane.setLayout(null); with some kind of layout such as contentPane.setLayout(new GridBagLayout());
Add
contentPane.removeAll() as the first line in addButtons().
You can create a "wrapper" panel for buttons, i.e.
...
private JPanel buttonsWrapper;
...
// in the constructor
buttonsWrapper = new JPanel();
buttonsWrapper.setLayout(null);
buttonsWrapper.setBounds(200, 150, 200, 50);
buttonsWrapper.add(wrapperPanel);
and add buttons to this panel
public void addButtons(int n) {
buttonsWrapper.removeAll();
for(int i = 0; i < n; i++) {
JButton button = new JButton(" " + navData[i]);
button.setBounds((i*50), 0, 50, 50);
buttonsWrapper.add(button);
}
buttonsWrapper.revalidate();
buttonsWrapper.repaint();
}
Related
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);
}
}
}
}
This is a difficult ask, but how do I add an ActionListener to multiple buttons that I have created in a for loop?
Here's my code so far:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Loop extends JFrame {
public Loop() {
this.setSize(700, 300);
this.setLocation(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel jpanel = new JPanel();
jpanel.setBackground(Color.CYAN);
jpanel.setLayout(new GridLayout(0,6));
JButton[] jButton = new JButton[6];
String string[] = {"One","Two","Three","Four","Five","Six"};
this.add(jpanel);
int j=0;
for(int i =0; i<jButton.length;i++) {
while(j < 6) {
jButton[i]= new JButton();
jButton[i].setPreferredSize(new Dimension(50, 50));
jButton[i].setText(string[j++]);
jpanel.add(jButton[i]);
jButton[i].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Works");
}
});
}
}
}
public static void main(String[] args) {
Loop myLoop = new Loop();
myLoop.setVisible(true);
}
}
(It seems from the code that to add the ActionListener in a for loop gives all the buttons the same action. Problem is I want the actions to be different for each button).
Any response would be greatly appreciated.
You can create a list or array of ActionListener's and pass it to the constructor, for example
import java.awt.*;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.*;
public class Loop extends JFrame {
public Loop(java.util.List<ActionListener> listeners) {
this.setSize(700, 300);
this.setLocation(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel jpanel = new JPanel();
jpanel.setBackground(Color.CYAN);
jpanel.setLayout(new GridLayout(0, 6));
JButton[] jButton = new JButton[6];
String[] string = {"One", "Two", "Three", "Four", "Five", "Six"};
this.add(jpanel);
int j = 0;
for (int i = 0; i < jButton.length; i++) {
while (j < 6) {
jButton[i] = new JButton();
jButton[i].setPreferredSize(new Dimension(50, 50));
jButton[i].setText(string[j]);
jpanel.add(jButton[i]);
jButton[i].addActionListener(listeners.get(j));
j++;
}
}
}
public static void main(String[] args) {
java.util.List<ActionListener> listeners = List.of(
e -> System.out.println("actionListener 1"),
e -> System.out.println("actionListener 2"),
e -> System.out.println("actionListener 3"),
e -> System.out.println("actionListener 4"),
e -> System.out.println("actionListener 5"),
e -> System.out.println("actionListener 6")
);
Loop myLoop = new Loop(listeners);
myLoop.setVisible(true);
}
}
It seems from the code that to add the ActionListener in a for loop gives all the buttons the same action.
You are correct. You are creating an anonymous class that implements ActionListener interface. However, each JButton is assigned a separate instance of that class.
There is nothing wrong with assigning the same, single instance to the different JButtons. Inside the code of the actionPerformed method you can identify which JButton was activated by examining the ActionEvent parameter.
The ActionEvent contains a action command string as well as the source, which, in your case, is the actual JButton that was activated.
Personally, I would make your Loop class implement ActionListener and in the actionPerformed method I would determine which JButton was activated from the action command. The below code demonstrates.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Loop extends JFrame implements ActionListener {
public Loop() {
this.setSize(700, 300);
this.setLocation(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel jpanel = new JPanel();
jpanel.setBackground(Color.CYAN);
jpanel.setLayout(new GridLayout(0, 6));
JButton[] jButton = new JButton[6];
String string[] = {"One", "Two", "Three", "Four", "Five", "Six"};
this.add(jpanel);
for (int i = 0; i < jButton.length; i++) {
jButton[i] = new JButton(string[i]);
jButton[i].setPreferredSize(new Dimension(50, 50));
jpanel.add(jButton[i]);
jButton[i].addActionListener(this);
}
}
public void actionPerformed(ActionEvent event) {
String actionCommand = event.getActionCommand();
switch (actionCommand) {
case "One":
break;
case "Two":
break;
case "Three":
break;
case "Four":
break;
case "Five":
break;
case "Six":
break;
default:
}
}
public static void main(String[] args) {
Loop myLoop = new Loop();
myLoop.setVisible(true);
}
}
By default, the action command is assigned the text of the JButton but you can assign a different value via the setActionCommand method.
You could do something like this:
import java.awt.*;
import java.util.stream.Stream;
import javax.swing.*;
#SuppressWarnings("serial")
public class Loop extends JFrame {
public Loop() {
final JPanel jpanel = new JPanel();
/**/ jpanel.setBackground(Color.CYAN);
/**/ jpanel.setLayout(new GridLayout(0, 6));
this.add (jpanel);
Stream.of("One", "Two", "Three", "Four", "Five", "Six")
.forEach(text -> {
final JButton button = new JButton(text);
/**/ button.setPreferredSize(new Dimension(50, 50));
/**/ button.addActionListener((e) -> {System.out.println("Button " + text + " pressed");});
jpanel.add (button);
});
this.setPreferredSize(new Dimension(700, 300));
this.setLocation(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setResizable(false);
this.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> new Loop());
}
}
You need some way of identifying which Button, but you can use 1 shared Listener as shown below.
Please note the use of SwingUtilities.invokeLater(...) to execute on the correct Thread.
import java.awt.*;
import java.awt.event.ActionListener;
import java.util.stream.Stream;
import javax.swing.*;
#SuppressWarnings("serial")
public class Loop extends JFrame {
public Loop() {
final JPanel jpanel = new JPanel();
/**/ jpanel.setBackground(Color.CYAN);
/**/ jpanel.setLayout(new GridLayout(0, 6));
this.add (jpanel);
final ActionListener oneSharedListener = (e) -> System.out.println("Button " + e.getActionCommand() + " pressed");
Stream.of("One", "Two", "Three", "Four", "Five", "Six")
.forEach(text -> {
final JButton button = new JButton(text);
/**/ button.setPreferredSize(new Dimension(50, 50));
/**/ button.addActionListener(oneSharedListener);
/**/ button.setActionCommand(text);
jpanel.add (button);
});
this.setPreferredSize(new Dimension(700, 300));
this.setLocation(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setResizable(false);
this.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> new Loop());
}
}
The JFrame window needs to display a random dice image. When the button is clicked, the random dice image needs to change. I have figured out how to display the random dice image, but I cannot figure out how to use the actionlistener to generate a new random dice image. I am only in my third Java class, so any guidance would be greatly appreciated!
package guiDice;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import java.awt.Color;
import java.awt.Font;
import javax.swing.SwingConstants;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import java.awt.event.ActionListener;
import java.util.Random;
import java.awt.event.ActionEvent;
public class LabGuiDice extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
LabGuiDice frame = new LabGuiDice();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public LabGuiDice() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JButton btnRollem = newDiceRoll();
contentPane.add(btnRollem, BorderLayout.SOUTH);
JLabel lblDice = newDiceImage();
contentPane.add(lblDice, BorderLayout.CENTER);
}
private JLabel newDiceImage() {
Random rnd = new Random();
int rand1 = 0;
rand1 = rnd.nextInt(6)+1;
JLabel lblDice = new JLabel("");
switch (rand1) {
case 1:
lblDice.setHorizontalAlignment(SwingConstants.CENTER);
lblDice.setIcon(new ImageIcon(LabGuiDice.class.getResource("/Dice/die-1.png")));
break;
case 2:
lblDice.setHorizontalAlignment(SwingConstants.CENTER);
lblDice.setIcon(new ImageIcon(LabGuiDice.class.getResource("/Dice/die-2.png")));
break;
case 3:
lblDice.setHorizontalAlignment(SwingConstants.CENTER);
lblDice.setIcon(new ImageIcon(LabGuiDice.class.getResource("/Dice/die-3.png")));
break;
case 4:
lblDice.setHorizontalAlignment(SwingConstants.CENTER);
lblDice.setIcon(new ImageIcon(LabGuiDice.class.getResource("/Dice/die-4.png")));
break;
case 5:
lblDice.setHorizontalAlignment(SwingConstants.CENTER);
lblDice.setIcon(new ImageIcon(LabGuiDice.class.getResource("/Dice/die-5.png")));
break;
case 6:
lblDice.setHorizontalAlignment(SwingConstants.CENTER);
lblDice.setIcon(new ImageIcon(LabGuiDice.class.getResource("/Dice/die-6.png")));
break;
}
return lblDice;
}
private JButton newDiceRoll() {
JButton btnRollem = new JButton("Roll 'Em");
btnRollem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
btnRollem.setBorderPainted(false);
btnRollem.setFont(new Font("Bodoni 72 Smallcaps", Font.PLAIN, 27));
btnRollem.setOpaque(true);
btnRollem.setBackground(new Color(255, 0, 0));
return btnRollem;
}
}
Create a method that generates the integer and sets the icon to the label. But in order to do that, label should be a field in the class, so all methods can access it. For example:
private void rollDice() {
Random random = new Random();
int randomInt = random.nextInt(6) + 1;
String resource = String.format("/Dice/die-%d.png", randomInt);
Icon icon = new ImageIcon(LabGuiDice.class.getResource(resource));
diceIconLabel.setIcon(icon);
}
and then:
btnRollem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
rollDice();
}
});
with full code:
public class LabGuiDice extends JFrame {
private JPanel contentPane;
private JLabel diceIconLabel;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
LabGuiDice frame = new LabGuiDice();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public LabGuiDice() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JButton btnRollem = newDiceRoll();
contentPane.add(btnRollem, BorderLayout.SOUTH);
diceIconLabel = newDiceImage();
contentPane.add(diceIconLabel, BorderLayout.CENTER);
rollDice();
pack();
}
private void rollDice() {
Random random = new Random();
int randomInt = random.nextInt(6) + 1;
String resource = String.format("/Dice/die-%d.png", randomInt);
Icon icon = new ImageIcon(LabGuiDice.class.getResource(resource));
diceIconLabel.setIcon(icon);
}
private JLabel newDiceImage() {
JLabel lblDice = new JLabel("");
lblDice.setHorizontalAlignment(SwingConstants.CENTER);
return lblDice;
}
private JButton newDiceRoll() {
JButton btnRollem = new JButton("Roll 'Em");
btnRollem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
rollDice();
}
});
btnRollem.setBorderPainted(false);
btnRollem.setFont(new Font("Bodoni 72 Smallcaps", Font.PLAIN, 27));
btnRollem.setOpaque(true);
btnRollem.setBackground(new Color(255, 0, 0));
return btnRollem;
}
}
I am trying to create a 2D array of buttons but the buttons I created are all in the same line. I can change lines in 2D arrays of int and float by using System.out.println(). What should I so for buttons? (line 67 to 75)
As well, I don't know how to create actionListeners for buttons in a loop. Should I create a method for acctionLisener? Do they share the same action listener?
import java.awt.*;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JInternalFrame;
public class Hanoi {
private JFrame frame;
JButton[][] buttons= new JButton[3][3];
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Hanoi window = new Hanoi();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Hanoi() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 901, 696);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panelone = new JPanel();
frame.getContentPane().add(panelone, BorderLayout.CENTER);
panelone.setBackground(Color.WHITE);
GridBagLayout gbl_panelone = new GridBagLayout();
gbl_panelone.columnWidths = new int[]{0};
gbl_panelone.rowHeights = new int[]{0};
gbl_panelone.columnWeights = new double[]{Double.MIN_VALUE};
gbl_panelone.rowWeights = new double[]{Double.MIN_VALUE};
panelone.setLayout(gbl_panelone);
JPanel paneltwo = new JPanel();
frame.getContentPane().add(paneltwo, BorderLayout.NORTH);
paneltwo.setBackground(Color.WHITE);
JLabel lblFunHanoiTower = new JLabel("Fun Hanoi Tower");
lblFunHanoiTower.setForeground(Color.BLACK);
lblFunHanoiTower.setBackground(SystemColor.activeCaption);
lblFunHanoiTower.setFont(new Font("Viner Hand ITC", Font.PLAIN, 36));
paneltwo.add(lblFunHanoiTower);
//JButton[][] buttons = new JButton[3][3];
for(int row = 0; row < buttons.length ; row++) {
for(int col= 0; col < buttons[0].length ;col++) {
buttons[row][col] = new JButton(String.valueOf((row+3)+(col*3)));
buttons[row][col].setFont(new Font("Tempus Sans ITC", Font.BOLD, 16));
buttons[row][col].setBackground(SystemColor.controlHighlight);
buttons[row][col].setSize(66, 66);
panelone.add(buttons[row][col]);
}
}
}
}
Rather than modify your code, I have provided an example of GridLayout.
GridLayout divides the area of the JPanel into a grid, i.e. a table of rows and columns, where each "cell" in the grid can contain one component and each cell has the same size. Here is a complete, compilable and runnable example.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Hanoi implements Runnable {
#Override // java.lang.Runnable
public void run() {
showGui();
}
private JPanel createGridPanel() {
// Number of rows will be calculated depending on total number
// of components added but each row will contain no more than
// three components.
GridLayout gridLayout = new GridLayout(0, 3);
JPanel gridPanel = new JPanel(gridLayout);
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
int number = (row + 3) + (col * 3);
String text = String.valueOf(number);
JButton button = new JButton(text);
gridPanel.add(button);
}
}
return gridPanel;
}
private void showGui() {
JFrame frame = new JFrame("Hanoi");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createGridPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Hanoi instance = new Hanoi();
EventQueue.invokeLater(instance);
}
}
And here is a screen capture of the running application.
(Note that I am using JDK 12 on Windows 10.)
You can use a grid layout, i change your original code (as you can see below). I recommend to use some designer for the gui, it more easy and clean. Net beans have a nice grafic interface builder.
public class Hanoi {
private JFrame frame;
JButton[][] buttons= new JButton[3][3];
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Hanoi window = new Hanoi();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Hanoi() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 901, 696);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panelone = new JPanel();
panelone.setLayout(new GridLayout(3,3));
frame.getContentPane().add(panelone);
panelone.setBackground(Color.WHITE);
/*GridBagLayout gbl_panelone = new GridBagLayout();
gbl_panelone.columnWidths = new int[]{0};
gbl_panelone.rowHeights = new int[]{0};
gbl_panelone.columnWeights = new double[]{Double.MIN_VALUE};
gbl_panelone.rowWeights = new double[]{Double.MIN_VALUE};*/
// panelone.setLayout(gbl_panelone);
JPanel paneltwo = new JPanel();
frame.getContentPane().add(paneltwo, BorderLayout.NORTH);
paneltwo.setBackground(Color.WHITE);
JLabel lblFunHanoiTower = new JLabel("Fun Hanoi Tower");
lblFunHanoiTower.setForeground(Color.BLACK);
lblFunHanoiTower.setBackground(SystemColor.activeCaption);
lblFunHanoiTower.setFont(new Font("Viner Hand ITC", Font.PLAIN, 36));
paneltwo.add(lblFunHanoiTower);
//JButton[][] buttons = new JButton[3][3];
for(int row = 0; row < buttons.length ; row++) {
for(int col= 0; col < buttons[0].length ;col++) {
buttons[row][col] = new JButton(String.valueOf((row+3)+(col*3)));
buttons[row][col].setFont(new Font("Tempus Sans ITC", Font.BOLD, 16));
buttons[row][col].setBackground(SystemColor.controlHighlight);
buttons[row][col].setSize(66, 66);
panelone.add(buttons[row][col]);
}
}
}
}