I have a JLabel[10] and I want to detect which label has been clicked and print which label of the label that has been clicked.
I created a JLabel array of 10.
Wrote a for loop to place an Image to every position of the label.
Added a MouseListener to check which label has been clicked.
The problem is I can't do this to get the source of my jLabelArr. The program will ask me to change my it to final.
if(e.getSource() == jLabelArr[i])
Full code
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class JavaLabels extends JFrame {
private JLabel[] jLabelArr;
private JPanel jLabelPanel = new JPanel();
public JavaLabels() {
setLayout(new FlowLayout());
jLabelArr = new JLabel[10];
for(int i =0; i < 10; i++) {
jLabelArr[i] = new JLabel(new ImageIcon("resources/image"));
jLabelPanel.add(jLabelArr[i]);
jLabelArr[i].addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if(e.getSource() == jLabelArr[i]) {
System.out.println("Label" + i + "was clicked");
}
}
});
}
add(jLabelPanel);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
pack();
setSize(400,600);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new JavaLabels();
}
}
For what you wanted there's nothing more than create a final int variable that will equal to the position of the for cycle
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class JavaLabels extends JFrame {
private JLabel[] jLabelArr;
private JPanel jLabelPanel = new JPanel();
public JavaLabels() {
setLayout(new FlowLayout());
jLabelArr = new JLabel[10];
for(int i =0; i < 10; i++) {
jLabelArr[i] = new JLabel(new ImageIcon("resources/image"));
jLabelPanel.add(jLabelArr[i]);
final int p = i;
jLabelArr[i].addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Label" + p + "was clicked");
}
});
}
add(jLabelPanel);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
pack();
setSize(400,600);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new JavaLabels().setVisible(true);
}
}
-> if(e.getSource() == jLabelArr[i]) is not needed in this case
1
public class JavaLabels extends JFrame {
private JLabel[] jLabelArr;
private JPanel jLabelPanel = new JPanel();
public JavaLabels() {
setLayout(new FlowLayout());
jLabelArr = new JLabel[10];
for (int i = 0; i < 10; i++) {
jLabelArr[i] = new JLabel(new ImageIcon("resources/image"));
jLabelPanel.add(jLabelArr[i]);
jLabelArr[i].addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
onMouseClicked(e);
}
});
}
add(jLabelPanel);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
pack();
setSize(400, 600);
setLocationRelativeTo(null);
setVisible(true);
}
private void onMouseClicked(MouseEvent e) {
for (int i = 0; i < 10; i++)
if (e.getSource() == jLabelArr[i]) {
System.out.println("Label" + i + "was clicked");
}
}
public static void main(String[] args) {
new JavaLabels();
}
}
2
Implement MouseListener to JavaLabels class and jLabelArr[i].addMouseListener(this);
Related
I am trying to make a tic tac toe game in java but my GUI is just not showing up. It makes a board and you are able to press buttons to play tic tac toe. I am new to java so I have no idea what is wrong. It has no errors and I use repl. What is wrong?
import javax.swing.JFrame;
import java.awt.event.ActionListener;
import java.awt.Color;
import java.awt.event.ActionEvent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.awt.GridLayout;
public class Main extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private JPanel panel = new JPanel();
private XOButtons[] buttons = new XOButtons[9];
private int turn = 0;
#Override
public void actionPerformed(ActionEvent actionEvent) {
XOButtons source = (XOButtons)actionEvent.getSource();
if(turn == 0){
source.toggleX();
setTitle("O Turn");
} else if(turn == 1){
source.toggleO();
setTitle("X's Turn");
}
turn = (turn + 1) % 2;
}
public static void main(String[] args) {
new TicTacToe();
}
public void TicTacToe() {
setTitle("Tic Tac Toe");
setSize(600,600);
setLocation(100,100);
getContentPane().setBackground(Color.CYAN);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel.setLayout(new GridLayout(3,3,5,5));
panel.setBackground(Color.BLUE);
for(int i=0; i < buttons.length; i++) {
buttons[i] = new XOButtons();
buttons[i].addActionListener(this);
panel.add(buttons[i]);
}
add(panel);
setVisible(true);
}
}
Here is my second java file:
import javax.swing.JFrame;
import java.awt.event.ActionListener;
import java.awt.Color;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.ImageIcon;
public class XOButtons extends JButton {
private static final long serialVersionUID = 1L;
private ImageIcon xIcon = new ImageIcon(getClass().getResource("x.png"));
private ImageIcon oIcon = new ImageIcon(getClass().getResource("o.png"));
public void toggleX() {
if(getIcon() == null) {
setIcon(xIcon);
} else {
setIcon(null);
}
}
public void toggleO() {
if(getIcon() == null) {
setIcon(oIcon);
} else {
setIcon(null);
}
}
}
Also, I have x.png and o.png loaded in.
There are a few problems and less than optimal ways of solving the problem in that code, but this problem was caused by turning the class name (TicTacToe) into Main and changing the constructor into a method.
This is what results when that is corrected.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
public class TicTacToe extends JFrame implements ActionListener {
private final JPanel panel = new JPanel();
private final XOButtons[] buttons = new XOButtons[9];
private int turn = 0;
public TicTacToe() {
setTitle("Tic Tac Toe");
setSize(600, 600);
setLocation(100, 100);
getContentPane().setBackground(Color.CYAN);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel.setLayout(new GridLayout(3, 3, 5, 5));
panel.setBackground(Color.BLUE);
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new XOButtons();
buttons[i].addActionListener(this);
panel.add(buttons[i]);
}
add(panel);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent actionEvent) {
XOButtons source = (XOButtons) actionEvent.getSource();
if (turn == 0) {
source.toggleX();
setTitle("O Turn");
} else if (turn == 1) {
source.toggleO();
setTitle("X's Turn");
}
turn = (turn + 1) % 2;
}
public static void main(String[] args) {
new TicTacToe();
}
}
class XOButtons extends JButton {
private ImageIcon xIcon = null;
private ImageIcon oIcon = null;
XOButtons() {
try {
xIcon = new ImageIcon(new URL("https://i.stack.imgur.com/in9g1.png"));
oIcon = new ImageIcon(new URL("https://i.stack.imgur.com/wCF8S.png"));
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
public void toggleX() {
if (getIcon() == null) {
setIcon(xIcon);
} else {
setIcon(null);
}
}
public void toggleO() {
if (getIcon() == null) {
setIcon(oIcon);
} else {
setIcon(null);
}
}
}
With Swing, I've created a window and want a letter to flash on the screen depending on the BPM (Beats per minute) the user inputs, and I was wondering how I would go about timing the flashing accurately. I tried using a Swing Timer but it is not very accurate and I see a lot of pauses or lag. I've heard something about using System.nanoTime() and System.currentTimeMillis() but have no clue how to implement them to create a timer. Any help would be appreciated!
Note.java
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.event.*;
import java.awt.*;
public class Note extends JFrame implements ActionListener {
JPanel mainScreen = new JPanel();
JPanel south = new JPanel();
JPanel north = new JPanel();
//emptyNumberMain = how many empty panels you want to use
public int emptyNumberMain = 2;
JPanel[] emptyMain = new JPanel[emptyNumberMain];
JLabel title = new JLabel("Fretboard Trainer!");
JButton start = new JButton("Start!");
public static void main(String[] args) {
new Note();
}
public Note() {
super("Random Note!");
setSize(300,300);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
//creates emptyNumberMain amount of empty panels
for (int i = 0; i < emptyNumberMain; i++) {
emptyMain[i] = new JPanel();
}
mainScreen.setLayout(new BorderLayout());
south.setLayout(new GridLayout(1,1));
south.add(emptyMain[0]);
south.add(start);
south.add(emptyMain[1]);
north.setLayout(new GridLayout(1,2));
north.add(title);
title.setHorizontalAlignment(JLabel.CENTER);
title.setFont(title.getFont().deriveFont(32f));
start.addActionListener(this);
mainScreen.add(north, BorderLayout.NORTH);
mainScreen.add(south, BorderLayout.SOUTH);
add(mainScreen);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == start) {
dispose();
new RandomNote();
}
}
}
RandomNote.java
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import java.util.Random;
import javax.swing.Timer;
import javax.swing.JSlider;
import java.awt.event.*;
import java.awt.*;
public class RandomNote extends JFrame {
JPanel noteScreen = new JPanel();
JPanel center = new JPanel();
JPanel southSlider = new JPanel();
JLabel bpm = new JLabel();
//emptyNumber = how many empty panels you want to use
int emptyNumber = 2;
JPanel[] empty = new JPanel[emptyNumber];
JLabel rndNote = new JLabel();
JSlider slider = new JSlider(0,200,100);
Timer timer2 = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
bpm.setText(Integer.toString(slider.getValue()));
timer.setDelay((int) ((60.0/slider.getValue()) * 1000));
}
});
public RandomNote() {
super("Random Notes!");
timer.start();
timer2.start();
setSize(500,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
//creates variable emptyNumber amount of empty panels
for (int i = 0; i < emptyNumber; i++) {
empty[i] = new JPanel();
}
noteScreen.setLayout(new BorderLayout());
center.setLayout(new GridLayout(1,1));
center.add(rndNote);
southSlider.setLayout(new GridLayout(3,1));
slider.setLabelTable(slider.createStandardLabels(20));
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.setMinorTickSpacing(5);
slider.setMajorTickSpacing(20);
southSlider.add(slider);
southSlider.add(bpm);
rndNote.setHorizontalAlignment(JLabel.CENTER);
rndNote.setFont(rndNote.getFont().deriveFont(32f));
noteScreen.add(center, BorderLayout.CENTER);
noteScreen.add(southSlider, BorderLayout.SOUTH);
add(noteScreen);
setVisible(true);
}
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
rndNote.setText(noteOutput());
}
});
public static String noteOutput() {
Random rand = new Random();
String[] note = {"A", "B", "C", "D", "E", "F", "G"};
int randNum = rand.nextInt(7);
return note[randNum];
}
}
The immediate thing that jumps out at me is this...
Timer timer2 = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
bpm.setText(Integer.toString(slider.getValue()));
timer.setDelay((int) ((60.0/slider.getValue()) * 1000));
}
});
Why do you need to update the text and reset the timer every 100 milliseconds?
So, the simple answer would be to use a ChangeListener on the JSlider to determine when the slider's value changes. I'd recommend having a look at How to Use Sliders for more details
As a runnable concept...
import java.awt.AlphaComposite;
import java.awt.Color;
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.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private AnimatableLabel label;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
label = new AnimatableLabel("BMP");
label.setHorizontalAlignment(JLabel.CENTER);
add(label, gbc);
label.start();
JSlider slider = new JSlider(10, 200);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
label.setBPM(slider.getValue());
}
});
slider.setValue(60);
add(slider, gbc);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class AnimatableLabel extends JLabel {
private Timer pulseTimer;
private Timer fadeTimer;
private double bpm = 60;
private double alpha = 0;
private Long pulsedAt;
public AnimatableLabel(String text, Icon icon, int horizontalAlignment) {
super(text, icon, horizontalAlignment);
setBackground(Color.RED);
initTimer();
}
public AnimatableLabel(String text, int horizontalAlignment) {
super(text, horizontalAlignment);
setBackground(Color.RED);
initTimer();
}
public AnimatableLabel(String text) {
super(text);
setBackground(Color.RED);
initTimer();
}
public AnimatableLabel(Icon image, int horizontalAlignment) {
super(image, horizontalAlignment);
setBackground(Color.RED);
initTimer();
}
public AnimatableLabel(Icon image) {
super(image);
setBackground(Color.RED);
initTimer();
}
public AnimatableLabel() {
setBackground(Color.RED);
initTimer();
}
public void start() {
updateTimer();
}
public void stop() {
pulseTimer.stop();
fadeTimer.stop();
}
protected void initTimer() {
pulseTimer = new Timer((int)(getDuration()), new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pulsedAt = System.currentTimeMillis();
alpha = 1.0;
repaint();
}
});
pulseTimer.setInitialDelay(0);
pulseTimer.setCoalesce(true);
fadeTimer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (pulsedAt == null) {
return;
}
long fadingDuration = System.currentTimeMillis() - pulsedAt;
alpha = 1.0 - (fadingDuration / getDuration());
if (alpha > 1.0) {
alpha = 1.0;
} else if (alpha < 0.0) {
alpha = 0.0;
}
repaint();
}
});
fadeTimer.setCoalesce(true);
}
protected double getDuration() {
return (60.0 / bpm) * 1000.0;
}
protected void updateTimer() {
fadeTimer.stop();
pulseTimer.stop();
pulseTimer.setDelay((int)getDuration());
pulseTimer.start();
fadeTimer.start();
}
public void setBPM(double bpm) {
this.bpm = bpm;
setText(Double.toString(bpm));
updateTimer();
}
public double getBPM() {
return bpm;
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive((float)alpha));
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();
super.paintComponent(g);
}
}
}
I'm developing a swing application. In that I've a JFrame which add JTextfield and JButton dynamically on the button click.and remove the created components if the user clicks the same button.
In the below screen image , when user clicks ADD button new row was added, and text was changed to REMOVE like in 2nd image.
New Row added and previous button text changed to REMOVE.
Now, if I click the REMOVE button, then the newly added row has to dispose and then button has to change the text again to ADD.
I've tried till adding the components, but I stuck up with removing the newly added row.
Anyone please guide me to achieve this.
Below is my code.
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ButtonAddDynamic implements ActionListener {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ButtonAddDynamic().createAndShowGUI();
}
});
}
private JFrame frame;
private JPanel panel = new JPanel(new GridBagLayout());
private GridBagConstraints constraints = new GridBagConstraints();
private List fields = new ArrayList();
private List fieldButton = new ArrayList();
private List fieldFile = new ArrayList();
private static int countReport = 0;
String files = null;
int y = 2;
protected void createAndShowGUI() {
try {
UIManager
.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
} catch (InstantiationException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
String[] labels = { "VALIDATION FORM" };
for (String label : labels)
addColumn(label);
frame = new JFrame("Add Button Dynamically");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(panel));
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// Set the default button to button1, so that when return is hit, it
// will hit the button1
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
}
private void addColumn(String labelText) {
constraints.gridx = fields.size();
constraints.gridy = 1;
panel.add(new JLabel(labelText), constraints);
constraints.gridy = 2;
final JTextField field = new JTextField(40);
field.setEditable(false);
panel.add(field, constraints);
fields.add(field);
// constraints.gridy=3;
constraints.gridx = fields.size() + fieldButton.size();
final JButton button = new JButton("ADD");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (button.getText().equals("ADD")) {
button.setText("REMOVE");
addRowBelow();
frame.pack();
} else if (button.getText().equals("REMOVE")) {
button.setText("ADD");
frame.pack();
}
}
});
panel.add(button, constraints);
fieldButton.add(button);
panel.revalidate(); // redo layout for extra column
}
private void addRowBelow() {
y++;
constraints.gridy = y;
// System.out.println(fields.size());
for (int x = 0; x < fields.size(); x++) {
constraints.gridx = x;
final JTextField field = new JTextField(40);
field.setEditable(false);
panel.add(field, constraints);
constraints.gridx = x + 1;
final JButton button = new JButton("ADD");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (button.getText().equals("ADD")) {
button.setText("REMOVE");
addRowBelow();
frame.pack();
} else if (button.getText().equals("REMOVE")) {
button.setText("ADD");
frame.pack();
}
}
});
panel.add(button, constraints);
}
}
public void actionPerformed(ActionEvent ae) {
if ("Add Another TextField and Button".equals(ae.getActionCommand())) {
addRowBelow();
frame.pack();
frame.setLocationRelativeTo(null);
}
}
}
Trying to use GridBagLayout is making this very complicated for you. A nested layout scheme is much easier to work with when you are doing this type of thing.
See this MCVE:
I'm not sure I understood your intended functionality 100% correct but I don't think it's as important as the layouts.
My layout scheme is as follows:
This is nice because BoxLayout will handle the vertical listing without much hullabaloo. Instead of having to wrangle with GridBagConstraints, the text field and button are contained together by a panel.
import javax.swing.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Insets;
public class FieldList implements Runnable, ActionListener {
public static void main(String... args) {
SwingUtilities.invokeLater(new FieldList());
}
final int maxFields = 2;
JFrame frame;
JPanel listing;
#Override
public void run() {
frame = new JFrame("Text Field Listing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel content = new JPanel(new BorderLayout());
content.add(new JLabel("Input Form", JLabel.CENTER), BorderLayout.NORTH);
listing = new JPanel();
listing.setLayout(new BoxLayout(listing, BoxLayout.Y_AXIS));
content.add(listing, BorderLayout.CENTER);
frame.setContentPane(content);
addNewField();
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
void addNewField() {
FieldButtonPair field = new FieldButtonPair();
field.button.addActionListener(this);
listing.add(field);
frame.pack();
}
void removeLastField() {
listing.remove(listing.getComponentCount() - 1);
frame.pack();
}
#Override
public void actionPerformed(ActionEvent ae) {
AddRemoveButton source = (AddRemoveButton)ae.getSource();
if(source.state == AddRemoveButton.State.ADD) {
if(listing.getComponentCount() < maxFields) {
addNewField();
source.setState(AddRemoveButton.State.REMOVE);
}
} else if(source.state == AddRemoveButton.State.REMOVE) {
removeLastField();
source.setState(AddRemoveButton.State.ADD);
}
}
}
class FieldButtonPair extends JPanel {
JTextField field;
AddRemoveButton button;
FieldButtonPair() {
super(new BorderLayout());
field = new JTextField();
add(field, BorderLayout.CENTER);
button = new AddRemoveButton();
add(button, BorderLayout.EAST);
}
#Override
public Dimension getPreferredSize() {
Dimension pref = super.getPreferredSize();
pref.width = Math.max(480, pref.width);
return pref;
}
}
class AddRemoveButton extends JButton {
enum State { ADD, REMOVE }
State state = State.ADD;
AddRemoveButton() {
setText(state.name());
}
void setState(State state) {
setText(state.name());
this.state = state;
}
#Override
public Dimension getPreferredSize() {
Dimension pref = super.getPreferredSize();
Font f = getFont();
FontMetrics fm = getFontMetrics(f);
int w = fm.stringWidth(State.REMOVE.name());
Insets ins = getInsets();
pref.width = (ins.left + w + ins.right);
return pref;
}
}
I have an array of JLabels[7] and I filled all JLabels with same image and added them to a JPanel.
When I click on a JLabel position(e.g I click on JLabel[5]) the console will print out "you have clicked JLabel 5" and change the JLabel image from imageOne to imageTwo.
I realized something about my codes which is after I clicked on a JLabel (e.g I click on JLabel[5]), the image changes from imageOne to imageTwo and the console print out "you have clicked JLabel 5" but if I clicked again and again on JLabel[5], the program will not detect my mouse click event and the console will not print out "you have clicked JLabel 5".
How do I make it such a way that after image has changed on the first click on a JLabel, it will still contiune and detect no mater how many times I clicked on the same JLabel again?.
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class LearningSwing {
public Image imageOne() {
BufferedImage img = null;
try {
img = ImageIO.read(new File("imageOne.jpg"));
} catch (Exception e) {
}
return img;
}
public Image imageTwo() {
BufferedImage img = null;
try {
img = ImageIO.read(new File("imageTwo.jpg"));
} catch (Exception e) {
}
return img;
}
public static void main(String[] args) {
final JLabel[] jLabelArr = new JLabel[7];
final JPanel jPanel = new JPanel(new FlowLayout());
JFrame frame = new JFrame();
final LearningSwing learningSwing = new LearningSwing();
for(int i = 0; i< 7; i++) {
jLabelArr[i] = new JLabel(new ImageIcon(learningSwing.imageOne()));
jPanel.add(jLabelArr[i]);
jLabelArr[i].addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
for(int i = 0; i < 7; i ++) {
if(e.getSource() == jLabelArr[i]) {
System.out.println("You clicked on JLabel" + i);
jPanel.remove(i);
jLabelArr[i] = new JLabel(new ImageIcon(learningSwing.imageTwo()));
jPanel.add(jLabelArr[i],i);
jPanel.revalidate();
jPanel.repaint();
}
}
}
});
}
frame.add(jPanel);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setSize(400,600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
In your code you are removing the old JLabel when the listener invokes mouseClicked, and you are recreating it again with the new image. This causes the JLabel to lose the listener.
You could instead change the image of the label as follows:
#Override
public void mouseClicked(MouseEvent e) {
for (int i = 0; i < 7; i++) {
if (e.getSource() == jLabelArr[i]) {
System.out.println("You clicked on JLabel" + i);
jLabelArr[i].setIcon(new ImageIcon(learningSwing.imageTwo()));
}
}
}
No, you don't need to re-add any listeners. You need to not swap JLabels. Instead, keep your JLabels where they are and just swap ImageIcons. The key here is this: don't make things more difficult for yourself.
e.g.,
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class LearningSwing2 extends JPanel {
private static final String[] IMAGE_PATHS = {"imageOne.jpg", "imageTwo.jpg"};
private static final int LABEL_COUNT = 7;
private List<Icon> icons = new ArrayList<>();
private JLabel[] imageLabels = new JLabel[LABEL_COUNT];
public LearningSwing2() throws IOException {
for (String imagePath : IMAGE_PATHS) {
BufferedImage img = ImageIO.read(new File(imagePath));
icons.add(new ImageIcon(img));
}
for (int i = 0; i < imageLabels.length; i++) {
imageLabels[i] = new JLabel(icons.get(0));
imageLabels[i].addMouseListener(new LabelListener());
}
}
private class LabelListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent mEvt) {
JLabel label = (JLabel) mEvt.getSource();
for (int i = 0; i < imageLabels.length; i++) {
if (label == imageLabels[i]) {
System.out.println("You pressed image label " + i);
}
}
label.setIcon(icons.get(1));
}
}
private static void createAndShowGui() {
LearningSwing2 mainPanel;
try {
mainPanel = new LearningSwing2();
JFrame frame = new JFrame("LearningSwing2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I'm working on a school project where we have to create a virtual smartphone, to run on a computer.
My problem is that I need to create a keyboard on the screen (like on an smartphone), which you can then use by clicking with your mouse. I could just create every single JButton, but that will take a really long time. So I was hopping that someone knew some sort of algorithm that creates all the buttons and places them correctly on the screen.
Thank you in advance :)
You could construct the buttons through the use of for loops. One loop for every keyboard row is a plausible approach.
String row1 = "1234567890";
String row2 = "qwertyuiop";
// and so forth
String[] rows = { row1, row2, .. };
for (int i = 0; i < rows.length; i++) {
char[] keys = rows[i].toCharArray();
for (int j = 0; i < keys.length; j++) {
JButton button = new JButton(Character.toString(keys[j]));
// add button
}
}
// add special buttons like space bar
This could be done more elegantly through a more OOP approach, but this basic loop system will work.
This simple example might help you:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class MainFrame extends JFrame
{
private JTextField txt;
private PopUpKeyboard keyboard;
public MainFrame()
{
super("pop-up keyboard");
setDefaultCloseOperation(EXIT_ON_CLOSE);
txt = new JTextField(20);
keyboard = new PopUpKeyboard(txt);
txt.addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
Point p = txt.getLocationOnScreen();
p.y += 30;
keyboard.setLocation(p);
keyboard.setVisible(true);
}
});
setLayout(new FlowLayout());
add(txt);
pack();
setLocationByPlatform(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new MainFrame().setVisible(true);
}
});
}
private class PopUpKeyboard extends JDialog implements ActionListener
{
private JTextField txt;
public PopUpKeyboard(JTextField txt)
{
this.txt = txt;
setLayout(new GridLayout(3, 3));
for(int i = 1; i <= 9; i++) createButton(Integer.toString(i));
pack();
}
private void createButton(String label)
{
JButton btn = new JButton(label);
btn.addActionListener(this);
btn.setFocusPainted(false);
btn.setPreferredSize(new Dimension(100, 100));
Font font = btn.getFont();
float size = font.getSize() + 15.0f;
btn.setFont(font.deriveFont(size));
add(btn);
}
#Override
public void actionPerformed(ActionEvent e)
{
String actionCommand = e.getActionCommand();
txt.setText(txt.getText() + actionCommand);
}
}
}
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String alphabet = "abcdefghijklmnopqrstuvwxyz";
JFrame myFrame = new JFrame();
JPanel myPanel = new JPanel();
for (int i = 0; i < alphabet.length(); i++) {
myPanel.add(new JButton(alphabet.substring(i, i + 1)));
}
myFrame.add(myPanel);
myFrame.pack();
myFrame.setVisible(true);
}
This is a fast example of how to do it :).