Accessing GUI JTextField objects that are dynamically generated - java

I am writing a program that contains a JButton. Every time the button is clicked, a new JTextField is added to a JPanel.
My problem is that, after the user has created all the JTextFields and filled them with information, I need to get the text of each field. How can I get access to the JTextFields when they are dynamically generated, as they don't have instance names? Is there a better way to get the text of each one, without knowing their instance name.
Here is the code of the actionPerformed event of the JButton...
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
JTextField x = new JTextField();
x.setColumns(12);
p.add(x);
validate();
}

You say you want to get the text from each field. So, when you create the new instances x, why don't you keep a collection of them, such as adding the JTextFields to an ArrayList?
Alternatively, assuming that p is a JPanel, you should be able to get all the children, which would be the JTextFields that you're adding. Try using getComponents() like so...
Component[] children = p.getComponents();
for (int i=0;i<children.length;i++){
if (children[i] instanceof JTextField){
String text = ((JTextField)children[i]).getText():
}
}

You can find them all by looping through the components of the panel (or whatever "p" is). If necessary, check if each is a text box. That is, do p.getComponents and then loop through the returned array. Like:
Component[] components=p.getComponents();
for (Component c : components)
{
if (c instanceof JTextField)
{
String value=((JTextField)c).getText();
... do whatever ...
}
}
If they are interchangeable, that should be all you need. If you need to distinguish them, I think the cleanest thing to do would be to create your own class that extends JTextField and that has a field for a name or sequence number or whatever you need.

Related

Changing ActionListener to append StringBuilder

Within two statements that have drastically shortened my code I need to add a statement that adds the text of a JButton to a StringBuilder. The ActionListener statement exists to disable the JButtons when clicked (a nice aesthetic), but I want to include if possible the ability to append the StringBuilder within the ActionListener as well. The following is the two parts of this code.
theModel.randomLetters();
ActionListener disableButton = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if (!(event.getSource() instanceof JButton)) {
return;
}
theModel.currentWord.append((JButton)event.getSource());
((JButton)event.getSource()).setEnabled(false);
}
};
for (int i = 0; i < 16; i++) {
JButton dice = new JButton(theModel.letters.get(i));
dice.addActionListener(disableButton);
boggleGrid.add(dice);
}
The .addActionListener(disableButton) adds the above ActionListener to each button when it is produced by the for loop. However,
theModel.currentWord.append((JButton)event.getSource());
is what I thought would properly append the StringBuilder "currentWord" with whatever value the clicked button holds (hence "((JButton)event.getSource())"). There are no errors per say but I have written separate lines of code in my main class to test whether there are any changes to the StringBuilder when any buttons are clicked. There isn't.
Where and what do I need to do to properly add the value of the clicked JButton to currentWord?
Using (JButton)event.getSource() will cause the StringBuilder to invoke the objects toString method. This isn't what you want, instead, either use the JButton's text property or the ActionEvent's actionCommand property, for example...
theModel.currentWord.append(((JButton)event.getSource()).getText());
or
theModel.currentWord.append(event.getActionCommand());
instead
Unless you specify the JButton's actionCommand yourself, it will use the buttons text as the actionCommand

how to identify a button in a group of loop generated buttons?

I have a group of loop generated buttons made with this code
this.panelCuerpo.setLayout(new GridLayout(4,5));
for(int i = 1; i<=20; i++){
final JToggleButton b = new JToggleButton(new ImageIcon("/images/available.png"));
panelCuerpo.add(b);
b.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Images/available1.png")));
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt){
if(b.isSelected()){
b.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Images/busy1.png")));
cantidadBoletas++;
}else{
b.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Images/available1.png")));
cantidadBoletas--;
}
System.out.println(cantidadBoletas);
}
});
}
The problem here is that I can't use setText() to compare later cause there's no property to hide that text. How can I compare it later?
PS. Each button has a consecutive number, it's easy to assign that number. The real problem lies in where to put it.
You could:
Use the Action API, which lets you trigger the selected state of the associated button. This allows you to de-couple the button from the underlying "action" it should take. Take a look at How to Use ActionsHow to Use Actions for more details
Use the actionCommand property of the JButton. This allows you to have some kind of "identifier" associated with the button which is independent of the text
Use an array or List to maintain a reference to the buttons
You can maintain a List<JToggleButton> of JToggleButton and fetch element later by the index. Apart from that instead of adding ActionListener in loop you can implement ActionListener which can be used for all buttons and you just need to write b.addActionListener(this); in loop.
NOTE : better to start from i = 0 instead of 1

How to tell which item fired a mouse listener

HI all,
I'm trying to write a simple star rating component. I'm fairly new to the Java language and I'm not sure if what i want to accomplish can even be done in Java. Is it possible for me to add a JLabel inside an array of JLabel, and each JLabel in the array will have a mouse event listener. Now is it possible to set it up so that when the mouse event fires on say Label[3] that i can get the index value of it?
Here is how I built my Panel
public Rating(Integer max,int size) {
JLabel position = new JLabel[max];
this.setLayout(new FlowLayout());
for(int i=0; i != max;i++){
position[i]=new JLabel(icons.getIcon("star-empty", size));
position[i].setOpaque(true);
position[i].addMouseListener(this);
add(position[i]);
}
}
#Override
public void mouseEntered(MouseEvent e) {
JLabel a= (JLabel) e.getComponent();
//****Have some code in here to tell me where in the position array the event came from????***
int index = ?????
}
Thoughts/Idea/Suggestions please.
Note I thought of using buttons, but it looks messy and would love to find a way with ImageIcons.
THanks.
Instead of using the same listener for each label like you did:
position[i].addMouseListener(this);
...you can create a special listener class that takes the index number, and allows you to find it later:
position[i].addMouseListener(new RatingMouseListener(i));
Each label will have a separate instance of the listener with a different index value. The code for the inner class would look like something like this:
private class RatingMouseListener extends MouseAdapter {
private final int index;
public RatingMouseListener(int index) {
this.index = index;
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("Mouse entered for rating " + index);
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println("Mouse exited for rating " + index);
}
}
Then, you just override any method in MouseAdapter.
Also, like other people said, you might want to use JButtons instead of JLabels because they have better support for action events. You can still give them icons.
You could name each JLabel according to its index using its setName method, then use the MouseEvent's getComponent method to get the originating JLabel back, use getName on it and there's your index. That would be one way, but would involve storing the index information in two places (implicitly in its placement in the array, and explicitly as the label's name), so it's pretty much begging for inconsistency to arise.
You could also search through the array for the JLabel reference you get from getComponent, but that's not so great either, especially for large arrays.
The way I usually do it is:
int i;
for (i = 0; i <max; i++)
if (position[i] == e.getcomponent())
break;
now position[i] is the label you are looking for.
Just know that JButtons can look any way you'd like. They can have ImageIcons and don't even have to look like buttons.
Why is the index important? You know how to get the component, so just loop through the array to get the index.
Note I thought of using buttons, but it looks messy and would love to find a way with ImageIcons.
How does using a button solve the problem of determining the index? However, I also agree using a button is better than a label and then you would use an ActionListener instead of a MouseListener. You can make the button look like a label by using:
button.setBorderPainted( false );
Now if you use an ActionListener you can use the setActionCommand(...) method to store the index value of the button. Then in the event you use the getActionCommand(...) method.

InputVerifier and multiple fields

I am working on a form that provides "real-time" validation to the user and I have one problem.
The goal is to put a label near the field (in this case a JSpinner), to show the user if the data is accepted or denied, in the same way that javascript-based validators do.
The problem is that for archieving this, I need to set the value for the corresponding label and the only way I have found to do this is to create as many verifiers as fields, this way:
class MyVerifier extends InputVerifier{
static final double MAX_VALUE = 30;
#Override
public boolean verify(JComponent input) {
JTextField tf = (JTextField) input;
Double value = Double.parseDouble(tf.getText().replace(',', '.'));
return (value>1);
}
#Override
public boolean shouldYieldFocus(JComponent input) {
boolean isValid = super.shouldYieldFocus(input);
if (isValid) {
jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("resources/accept.png")));
jLabel1.setText("");
} else {
jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("resources/exclamation.png")));
jLabel1.setText("The number of items must be greater than 1");
}
return true;
}
}
Then, the same code for jLabel2... It must be another way to do this.
Thanks in advance.
You could have a Hashmap for the text field and its related label component. Then in the shouldYieldFocus method you retrieve the related label for the text field being validated. You can then set the text/icon of the label appropriately.
You would probably also need a secound Hashmap containg the label and the text message for the error.
You could also use a JDialog as a popup next to the JComponent you are validating. This popup JDialog will have a JLabel that will encapsulate the message you want to display next to the respective Jcomponent. All you have to do is to calculate the position of the popup relative to the Jcomponent you are validating.
You can find a good example here

How to get a handle to all JCheckBox objects in order to loop?

I'm very new to Java and am having some issues looping through JCheckBoxes on a UI. The idea is that I have a bunch of checkboxes (not in a group because more than one can be selected.) When I click a JButton, I want to build a string containing the text from each selected checkbox. The issue I'm having is that our instructor told us that the checkboxes need to be created via a method, which means (see code below) that there isn't a discrete instance name for each checkbox. If there were, I could say something like
if(checkBox1.isSelected()) {
myString.append(checkBox.getText());
}
That would repeat for checkBox2, checkBox3, and so on. But the method provided to us for adding checkboxes to a panel looks like this:
public class CheckBoxPanel extends JPanel {
private static final long serialVersionUID = 1L;
public CheckBoxPanel(String title, String... options) {
setBorder(BorderFactory.createTitledBorder(BorderFactory
.createEtchedBorder(), title));
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
// make one checkbox for each option
for (String option : options) {
JCheckBox b = new JCheckBox(option);
b.setActionCommand(option);
add(b);
}
}
}
This is called like this:
toppingPanel = new CheckBoxPanel("Each Topping $1.50", "Tomato", "Green Pepper",
"Black Olives", "Mushrooms", "Extra Cheese",
"Pepperoni", "Sausage");
So I now have a panel that contains a border with the title "Each Topping $1.50", and 7 visible checkboxes. What I need to do is get a list of all the selected toppings. We are not supposed to use an ActionListener for each checkbox, but rather get the list when a button is clicked. I'm feeling really clueless here, but I just can't figure out how to get the isSelected property of the checkboxes when the individual checkboxes don't have instance names.
Ideally I'd like to somehow add all the checkboxes to an array and loop through the array in the button's action listener to determine which ones are checked, but if I have to check each one individually I will. I just can't figure out how to refer to an individual checkbox when they've been created dynamically.
I'm assuming you're not allowed to alter the CheckBoxPanel code at all. Which seems like a useless exercise, because in the real world, you'd think that if CheckBoxPanel where a class being provided to you (e.g. in a library) it would include a way of getting the selected options. Anyway, due to the limitation, you could do something like this:
for( int i=0; i<checkBoxPanel.getComponentCount(); i++ ) {
JCheckBox checkBox = (JCheckBox)checkBoxPanel.getComponent( i );
if( checkBox.isSelected() ) {
String option = checkBox.getText();
// append text, etc
}
}
I suggest you maintain a list of checkboxes:
List<JCheckBox> checkboxes = new ArrayList<JCheckBox>();
and before add(b) do:
checkboxes.add(b);
You may then iterate through the list of checkboxes in the buttons action-code using a "for-each" loop construct:
for (JCheckBox cb : checkboxes)
if (cb.isSelected())
process(cb.getText()); // or whatever.
Alternatively, if you need to keep track of the specific index:
for (int i = 0; i < checkboxes.size(); i++)
if (checkboxes.get(i).isSelected())
....
I would suggest that you dont put each of the checkboxes in a List when you create them. Instead, in your shared ActionListener, you maintain a Set of all selected checkboxes. Use the getSource method on the ActionEvent to identify which checkbox the user selected and then cast it to a JCheckBox. If isSelected() returns true for the item in question, attempt to add it to your selectedItems Set. If it is not, then attempt to remove it.
You can then just iterate over the subset of all items (only those that are selected) and print them to the console.

Categories

Resources