How to avoid implementing component over and over - java

For example, I have 20 different JTextField and lets say I need to set text to all "random", so I don't want to do like:
field1.setText("Random");
field2.setText("Random");
field3.setText("Random");
.
.
.
field20.setText("Random");
Is there a way to avoid this?

This is quite a basic question. You can do this :
Stream.of(field1,field2,...,field3).forEach(f -> f.setText("Random"));
or without Java 8 :
JTextField fields = Arrays.asList(field1,field2,...,field3);
for (JTextField field : fields)
field.setText("Random");
Or, if you don't need to keep a reference to your fields :
for (int i=0 ; i<20 ; i++) {
JTextField field = new JTextField("Random");
// place your field in the UI
}

Try something like:
JTextField[] textFields = new JTextField[20];
for (int i =0; i< fields.length; i++) {
//init here text fields
textFields[i].setText("Random");
}

Create the JTextFields in an array or a Collection and then iterate over the contents of the array.
For instance:
List<JTextField> myTextFields = new ArrayList<JTextField>();
for (int i = 0; i < 20; i++) {
myTextFields.add(new JTextField()); //Instantiate the textfields
//Do whatever other initialization, if you can do it in a loop (like position, etc.)
myTextFields.get(i).setText("Random"); //Set text on all of them.
}

Just to also cover the possibility which was not mentioned so far:
You could (although you really should not in most cases) inherit from JTextField and do your business e.g. in the constructor. Or you can use a factory-method.
(sample below is untested code written with one hand)
class MyTextField extends JTextField {
public MyTextField() {
setText("Random");
}
}
/* in other file */
class MyTextFildFactory {
public static JTextField createTextField() {
JTextField field = new JTextField();
field.setText("Random");
return field;
}
}

Related

Sending a variable from ActionListener, so another ActionListener can use it

I see there are some questions already asked about this topic but I haven't come up to an answer for my. I am writing a code where user types something in JTextField, and after clicking a button, his word is replaced with the number of asterisks with the same number of characters his word had e.g "table" would be replaced by "****". i did it this way:
ask.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String guess = "";
String given = textGive.getText();
for (int i=0; i<given.length(); i++){
String asterisk = "*";
guess += asterisk;
textGive.setText(guess);
}
}
});
I know that I did not do this in a great way, but I did not know how to do it better. Any recommendations?
Now, I want somehow to save both Strings, the original word and the asterisk one outside the scope so I can access it in another ActionListener and modify it further.
Before writing first ActionListener i did write String guess = "" and String given = "" but it seems as it did not do anything.
So, in my second ActionListener i want to send him the string given I received when the user typed his word.
guess.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String attempt = textGuess.getText();
char att = attempt.charAt(0);
for (int i=0; i<5; i++){
if (given.charAt(i)==att){
textGuess.setText("Ok!");
}
}
}
});
Eclipse gives me error saying:
"Cannot refer to the non-final local variable given defined in an enclosing scope".
I understand that I need to make given final in order to acces it further, but how to do that if the variable depends on text input from first ActionListener? Is there some other solution for this problem? I've recently started using java, so I do not know the language so well.
Anything that you want visible to class should be placed in instance fields, not in local variables. For instance, the given variable should be a private non-static field declared in the class, and not a variable buried within your listener's actionPerformed method.
e.g.,
public class Foo extends JPanel {
private JButton ask = new JButton("Ask");
private JTextField textGive = new JTextField(10);
private String given = ""; // visible throughout the class
public Foo() {
add(textGive);
add(ask);
ActionListener listener = e -> {
String guess = "";
// String given = textGive.getText(); //visible only within this method
given = textGive.getText();
guess = given.replaceAll("\\w", "*");
textGive.setText(guess);
};
ask.addActionListener(listener);
textGive.addActionListener(listener); // also give the same listener to the JTextField
}

Calling multiple objects with a method in Java

I'm trying to create a calendar using Java GUI and I want to create a method to create the cells of each date. Is there any way to create a method to create a bunch of JTextAreas without manually creating each individual cell?
Creating a cell one by one I do:
public void createCell() {
cell1 = new JTextArea(CELL_DIMENSIONS, CELL_DIMENSIONS);
}
You have many ways of doing that one possibility would be to create a List inside the method with the assistance of a for loop and make the method return it for you to use somewhere else.
public List<JTextArea> createMultipleCells(int numOfCells) {
List<JTextArea> cells = new LinkedList<JTextArea>();
for(int i = 0; i < numOfCells; i++){
cells.add(new JTextArea(CELL_DIMENSIONS, CELL_DIMENSIONS));
}
return cells;
}
Same thing with an array:
public JTextArea[] createMultipleCells(int numOfCells) {
JTextArea[] cells = new JTextArea[numOfCells];
for(int i = 0; i < numOfCells; i++){
cells[i] = new JTextArea(CELL_DIMENSIONS, CELL_DIMENSIONS);
}
return cells;
}

Get text from JRadioButton that isn't part of a ButtonGroup

My program is a GUI. I have this method where when a button is clicked. It populates the next screen with JRadioButtons dynamically.
private void setExamButtonActionPerformed(java.awt.event.ActionEvent evt)
{
if(evt.getActionCommand().equals("Set Exam"))
{
CardLayout cL = (CardLayout)cardPanels.getLayout();
cL.show(cardPanels, "setExamPanel");
}
try
{
//InputStream code
String theMessage = myObject.getMessage();
String delims = "(?=(0*([0-9]{1,2}|100)))";
String[] questions = theMessage.split(delims);
System.out.println(Arrays.toString(questions));
for (int j = 1; j < questions.length; j++)
{
settingQuestionBoxes = new JCheckBox(questions[j]);
settingQuestionTextField = new JTextField("");
jPanel1.add(settingQuestionBoxes);
jPanel1.add(settingQuestionTextField);
jPanel1.revalidate();
jPanel1.repaint();
}
//close streams and socket code
}
catch(Exception e)
{
System.out.println(e);
}
}
Then I have this other method from another screen where the data that is populated from the previous method goes to.
private void setExamQuestionButtonActionPerformed(java.awt.event.ActionEvent evt)
{
if(evt.getActionCommand().equals("Set Exam Question"))
{
ArrayList<JToggleButton> settingQuestionBoxes = new ArrayList<JToggleButton>();
for(JToggleButton questions: settingQuestionBoxes)
{
if(questions.isSelected())
{
System.out.println(questions.getActionCommand());
}
}
CardLayout cL = (CardLayout)cardPanels.getLayout();
cL.show(cardPanels, "instructorPanel");
}
}
So basically when i call this System.out.println(questions.getActionCommand()) I'm trying to see the text from the JRadiobutton that was clicked on.
Right now when I run the program and select a button. Nothing happens.
Put the buttons into a List<JToggleButton> such as an ArrayList<JToggleButton> and then iterate through the list when the information is needed.
for (JToggleButton btn : myButtonList) {
if (btn.isSelected() {
String actionCommand = btn.getActionCommand();
// use the actionCommand here
}
}
Note that JToggleButton is the parent class for JRadioButton and using it would allow you to add JRadioButtons, JCheckBoxes, and JToggleButtons to the list. Since your JRadioButton is not part of a ButtonGroup, perhaps you should be using a JCheckBox instead.
Edit
You now have posted this code, stating it doesn't work:
// Section (A)
ArrayList<JToggleButton> settingQuestionButton = new ArrayList<JToggleButton>();
// Section (B)
for(JToggleButton questions: settingQuestionButon)
{
if(questions.isSelected())
{
System.out.println(questions.getActionCommand());
}
}
Is this code, both (A) and (B), all together in your program? If so, it would make sense that it doesn't work. You should have (A) in a constructor or some set up method. You should follow (A) with code that creates your JRadioButtons or JCheckBoxes, that sets their actionCommand String, that places them in the GUI, and that adds them to the ArrayList.
The part (B) code, the enhanced for loop would need to be in code that is called in response to an event, perhaps in a JButton or radio button's ActionListener.
Please check out this information and fill us in on the details. Please consider creating and posting an sscce illustrating your problem for us.
Edit 2
Your code is confusing in that you appear to have two completely variables of different types with the exact same name, and you appear to be assuming that this will give the variable magical properties that will allow it to know what it's "twin" might be doing. Java doesn't work that way, and in fact variable names are not nearly all that important or smart to allow them any such functionality. Rather your code must be smart.
I'm assuming that more than one of your JCheckBoxes will be checked, and that you want to check which ones are checked at some point in your program. If so, then in your class you should have a List or ArrayList field, something like
private List<JToggleButton> questionsList = new ArrayList<JToggleButton>();
This way this field will available throughout the class.
Then where you create your JCheckBoxes, you add them to this list:
private void setExamButtonActionPerformed(java.awt.event.ActionEvent evt)
{
if(evt.getActionCommand().equals("Set Exam"))
{
CardLayout cL = (CardLayout)cardPanels.getLayout();
cL.show(cardPanels, "setExamPanel");
}
try
{
String theMessage = myObject.getMessage();
String delims = "(?=(0*([0-9]{1,2}|100)))";
String[] questions = theMessage.split(delims);
for (int j = 1; j < questions.length; j++)
{
settingQuestionBox = new JCheckBox(questions[j]); // *** renamed to make more sense
settingQuestionBox.setActionCommand(questions[j]); // **** add actionCommand String
questionsList.add(settingQuestionBox); // ****** add JCheckBox to List
settingQuestionTextField = new JTextField("");
jPanel1.add(settingQuestionBox);
jPanel1.add(settingQuestionTextField);
jPanel1.revalidate();
jPanel1.repaint();
}
//close streams and socket code
}
catch(Exception e)
{
// System.out.println(e);
e.printStackTrace(); // ***** more informative
}
}
Then elsewhere in your code
setExamQuestionButtonActionPerformed(java.awt.event.ActionEvent evt)
{
if(evt.getActionCommand().equals("Set Exam Question"))
{
// ArrayList<JToggleButton> settingQuestionBoxes = new ArrayList<JToggleButton>();
for(JToggleButton questions: questionsList)
{
if(questions.isSelected())
{
System.out.println(questions.getActionCommand());
}
}
CardLayout cL = (CardLayout)cardPanels.getLayout();
cL.show(cardPanels, "instructorPanel");
}
}
And of course you'll need to take care that the ActionListener is added to a button

How to create dynamically JButton value in DesignGridLayout library?

i create grid layout using DesignGridLayout java library (here).
in the sampe if create 3 column layout. using this code :
layout.row().add(new JButton("Button 1")).add(new JButton("Button 2")).add(new JButton("Button 3"));
or using method that return object :
layout.row().add(button()).add(button()).add(button());
...
...
public JButton button() {
return new JButton("Button");
}
The question is, how to create dynamically JButton value? May be name,icon or anything?
I already try my own code like this :
for (int i=0; i<4; i++) {
JButton button = new JButton();
layout.row().add(button).add(button).add(button);
}
it return :
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Do not add the same component twice
My purpose for different value in each component which added in panel is, i want to create gallery that populate
different image, and i load that images using looping, like this :
for(int i=0; i<files.length; i++) {
...
ImageIcon imgSource = new ImageIcon(new File(myPath));
JLabel labelGallery = new JLabel(imgSource);
...
}
Any solution?
Thanks before :)
In your example,
layout.row().add(button).add(button).add(button);
has the effect of attempting to add the same JButton instance to the row repeatedly.
In the example cited,
layout.row().grid().add(button()).add(button());
invokes an auxiliary method, button(), to create a new instance each time it appears:
public static JButton button() {
return new JButton("Button");
}
As mentioned by #trashgod, Swing does not allow to add the same component twice to a panel.
If you want to add several components, created within a loop, to the same row, you can do it as follows:
IRow row = layout.row().grid();
for (int i = 0; i < n; i++) {
JButton button = createButton(i);
row.add(button);
}
That will create only one row with n buttons inside.

Multiple JButtons, one Eventlistener in Java

I have a 2D-Array of JButtons
JButton[][] ledBtns = new JButton[8][8];
And in a loop, I do all the init stuff. Now I want to add an EventListener to each JButton, that fires when the Button os clicked. Then I want to change the image on the Button.
for(int i = 0; i < ledBtns.length; i++){
for(int j = 0; j < ledBtns[i].length; j++){
//init stuff
ledBtns[i][j].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
changeImage();
}
});
}
}
Now 'changeImage()' will be called, but I need to know what button called it.
I can't use parameters, if I do it tells me to declare them as 'final'.
Is there any other way than writing 64 methods, that do exactly the same, and adding them manually to each of the JButtons?
The ActionEvent class has a getSource() method used to get the component that generated the event.
The easiest way to do this is to just declare two temporary final ints, and reference those.
for(int i = 0; i < ledBtns.length; i++){
for(int j = 0; j < ledBtns[i].length; j++){
//init stuff
final int finalI = i;
final int finalJ = j;
ledBtns[i][j].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
changeImage(finalI,finalJ);
}
});
}
You can set the JButton object's "name" property and, according to mre's answer, you can call the getSource() method. So you can identity whick button is clicked
Another option is to have your class implement ActionListner (ie, implements ActionListner).
Then when you cycle through your buttons in your loop, you can just say
ledBtns[i][j].addActionListener(this).
Of course, then you have to figure out which object was the source of the event (usually by using if...else blocks). Now that could get unwieldy for 64 objects, but for lesser items, it isn't usually a problem.
Or, you could have the actionPerformed method call change image and pass in the button object, etc to do your work on.
What I've suggested is just another option. I'd do what makes the most sense for your code and is the cleanest and most readable.

Categories