0

Here I have a GUI window and it basically ask the user to select a JRadioButton and type something in a JTextField, then choose confirm/cancel.

It is a project which we have to make a UML-to-Java text file. User would enter class information and choose a UML relationship, and this programme have to print out the Java clsas text on a JTextField. Just like when you create a new class in eclipse.

what I want to do is make a boolean[] to store an array of booleans, when user selects JRadioButton_A it'll store true and when user select JRadioButton_B it'll store false.And also I want the things typed in JTextField to be checked by a checkName(), if the method returns false, the string will be stored in an ArrayList.

Below is my code - there's some problems in getName() method and the boolean[] for storing true and false. When user needs to input name again, it would save the discarded sting/boolean into the array. (Sorry for my bad english!) Is there any better way to make this programme? I feel like I am complicating things and there should be a simpler way to make it.

Here's the UI stuffs asking user to enter class information. User have to select public/private and then type in class name and JTextField

private class Handler implements ActionListener{
    public void actionPerformed(ActionEvent event){
        String name = inputClassName.getText();
        classObject.addName(name);
        while (classObject.checkName(name) == true){
            JOptionPane.showMessageDialog(null, "Class name invalid. " +
                    "\nEntered name should not contain java keywords or equal to other existing names. " +
                    "\nPlease try again."); // doesn't work
            name = inputClassName.getText();
            classObject.addName(name);
        }// end if
        JOptionPane.showMessageDialog(null, "Class saved."); // doesn't work
        name = inputClassName.getText();
        classObject.addName(name);

    }// end actionPerformed()
}// end Handler class

private class Handler2 implements ActionListener{
    public void actionPerformed(ActionEvent event){
        boolean b = true;
        b = classObject.setPP();
        }
    }

private class Handler3 implements ActionListener{
    public void actionPerformed(ActionEvent event){
        boolean b = false;
        b = classObject.setPP();
        }
    }

Here's the methods for storing the inputs to the ArrayList and boolean[]

Scanner input = new Scanner(System.in);
JavaKeywords keyObject = new JavaKeywords();

private ArrayList<String> className = new ArrayList<String>();
private String name = new String();
private int size = className.size();
private Boolean[] bArray = new Boolean[size];


public boolean checkName(String name){
    boolean check = true;
    for (int i=0; i<=size; i++){
        if (keyObject.containsKeyword(className.get(i)) || name.equals(className.get(i))){

            boolean o = false;
            check = o;
        }// end if
    }// end for
    return check;
}// end checkName
    
public boolean setPP(){
    boolean b = true;
    return b;
}

public void addPP(Boolean[] bArray){
    this.bArray = bArray;
    for (int i=0; i>=size; i++){
        bArray[i] = setPP();
    }
}// add a Array of boolean. for className[i], its class type = item[i] in bArray. 
             // public = true, private = false
public String getPublicPrivate(){
    String p = "";
    for (int i =0; i<=size; i++){
        if(bArray[i]=true)
            p = "public";
        else
            p = "private";
    }
    return p;
}

Solved

Solution: store the string className and boolean isPrivate in a class and make the class into an ArrayList can save me from all the trouble. But then i faced anther problem, that is the checkName() doesn't work after I changed my code. here is the ActionListener

private class Handler implements ActionListener{
    public void actionPerformed(ActionEvent event){
        
        VirtualClass virtualObject = new VirtualClass();
        classObject.addClass(virtualObject);
        String name = inputClassName.getText();
        virtualObject.className = name;
        
        if (classObject.checkName(name) == false){
            JOptionPane.showMessageDialog(null, "Class name invalid. " +
                    "\nEntered name should not contain java keywords or equal to other existing names. " +
                    "\nPlease try again."); // Always return "invalid" message 
        } else {
            JOptionPane.showMessageDialog(null, "Class saved."); 
            name = inputClassName.getText();
            virtualObject.className = name;
        }
        
        if (event.getSource() == publicButton) {
            virtualObject.isPrivate = false;
        } else if (event.getSource() == privateButton) {
            virtualObject.isPrivate = true;
        }

    }// end actionPerformed()

and here is the checkName() method

public boolean checkName(String name){
    boolean check = true;
    for (int i=0; i<=size; i++){
        if (keyObject.containsKeyword(classes.get(i).className) || name.equals(classes.get(i).className)){
            boolean o = false;
            check = o;
        }// end if
    }// end for
    return check;
}// end checkName

For containsKeyword() in checkName() I've used a JavaKeywords class from How to check if the class name is valid? by @MrLore.

Community
  • 1
  • 1
Sue
  • 199
  • 1
  • 3
  • 10
  • Post relevant code instead of full program. – kosa Oct 23 '13 at 19:52
  • I guess I don't understand what the array is actually for. If your only parameter is two-state like either public or private, why not flag as a single boolean that is public? Then if public is false, you can assume it is private. Additionally I don't completely understand what your getting/setting is intended to do. It looks like you just need a single setter like `setPP(boolean p) { public = p; }`. – Radiodef Oct 23 '13 at 19:56
  • Nambari - edited. Radiodef - Thank you! I just feel like I've been complicating the program but I couldn't think of a smarter way. I guess i was just being stupid... – Sue Oct 23 '13 at 20:01
  • I guess I was using the array because this program allow users to create multiple classes, so the boolean refers to class type public/private needs to have a linkage with the className. So if its an array, I can use the index to find the class type of the class... if this makes sense – Sue Oct 23 '13 at 20:04
  • 1
    If you need more than two states or want the states more concretely represented you can always use an enum. Either way you want a single variable to represent the multiple states. As a side note, you can use a single ActionListener and evaluate the source to simplify stuff like that too: `if (e.getSource() == radioButton1) {} else if (e.getSource() == radioButton2) {}`. – Radiodef Oct 23 '13 at 20:04
  • I've offered an answer to your question of keeping the array indexes together but you're basically right that yes if you are keeping a list of names then you'll also need to keep separate lists of all the other attributes. Using a class is the simplest solution to this. Otherwise you'll just have to keep the indexes parallel yourself. Either way, like @MadProgrammer and I have also suggested, you should do all of the creation and setting in your final entry event instead of trying to manage the public/private inside the radio button actions. – Radiodef Oct 23 '13 at 20:24
  • Thanks!! Didn't see this comment as it's hidden by a banner or something. – Sue Oct 23 '13 at 20:35
  • I guess keeping all the index paralelll would be very very troublesome...so I think @MadProgrammer 's suggestion to create objects for each set of result would be a better way. BTW I've changed my code and got rid of the two unnessarsary handler classes, and put all the public/private things inside the ClassName class. :) – Sue Oct 23 '13 at 20:39
  • You *can* keep separate lists/arrays, you would just have to make sure you are only adding stuff to the lists at the same time. Creating a simple object to hold both fields just makes the logic much simpler. – Radiodef Oct 23 '13 at 20:45
  • Just tried your code on eclipse. I understand your solution now. That's really a much simpler way to store the variables!! I've never thought of the idea of creating an ArrayList of a classs. That's really cool – Sue Oct 23 '13 at 20:50
  • Yep, you can create an ArrayList of anything, same as you can make arrays of any other objects. And you're welcome! – Radiodef Oct 23 '13 at 20:53
  • Thanks thanks!!You and @MadProgrammer saved my project :P – Sue Oct 23 '13 at 21:00

2 Answers2

1

Probably what I would do is create a simple class to represent your fields so you don't have to use multiple lists at all.

public class VirtualClass {
    public boolean isPrivate;
    public String className = "Object";
}

ArrayList<VirtualClass> classes = new ArrayList<VirtualClass>(0);

public void addClass(VirtualClass clazz) {
    classes.add(clazz);
}

Otherwise you will have to create a second list of some kind to hold the public/private. You will just have to change them in parallel.

// in actionPerformed

ClassObject.VirtualClass clazz = new ClassObject.VirtualClass();

clazz.isPrivate = rbPrivate.isSelected();
clazz.className = tfClassName.getText();

classObject.addClass(clazz);

And just ignore the listening on the radio buttons since you technically do not need their states until you go to add the class to the list.

To access the fields later you just need to

for (VirtualClass clazz : classes) {
    System.out.println((clazz.isPrivate ? "private" : "public") + " " + clazz.className);
}

// or something like

for (int i = 0; i < classes.size(); i++) {
    System.out.println(classes.get(i).className + ":");
    if (classes.get(i).isPrivate) {
        System.out.println(" private");
    } else {
        System.out.println(" public");
    }
}
Radiodef
  • 35,285
  • 14
  • 78
  • 114
  • Thank you. Your comments are very helpful. I've get rid of the checkName() problem! but still I cannot figure out how to link up 'isPrivate' and the className 'clazz' so that the programme can eventually print out "public/private className". – Sue Oct 23 '13 at 20:33
  • The reference clazz is just discarded in my example. The object references are kept in the list and you can access them later whenever you want. I added a quick example of basic iteration. – Radiodef Oct 23 '13 at 20:38
  • I would like to ask for your AddClass() method, there's an parameter clazz of VirtualClass type. Do i have to create a new object name every time when user have a new input? – Sue Oct 23 '13 at 21:32
  • The addClass method goes in your class of whatever classObject is of, wherever you are keeping the list. In all of those cases, the reference clazz is just a temporary reference you are using to pass the object in and add it to your ArrayList. Java is "pass by reference" for objects which means that when you pass an object as a parameter to a method, only the reference (called a pointer in other languages such as C++) is passed in to the method. The object itself is not copied. All of the references refer to the same object in memory that was created with the first `new VirtualClass()`. – Radiodef Oct 23 '13 at 21:55
  • I guess to try to answer your question more directly, yeah you have to create a new object. Whenever your user submits a new entry, you would create a new object in that method and hand it in to be added to the list. The *reference* you create inside the method is discarded when the method returns, but when you add it to the list the object continues to exist because there is still a reference to it (the one in the list). – Radiodef Oct 23 '13 at 22:07
  • I guess I understand what you mean. Is it that as long as i have `VirtualClass virtualObject = new VirtualClass(); classObject.addClass(virtualObject);` inside the `actionHandler` class, i'm safe? – Sue Oct 23 '13 at 23:01
  • even though the virtualClass object is named the same, but they're stored in different places(diff. reference). So the code above can create a new object of virtualClass without overwriting the objects? – Sue Oct 23 '13 at 23:03
  • Yes. Each time the method is called, a new object is created. The name you give it inside the method body is only for inside the method body for that execution of the method. Every time a method is executed, everything you create inside it is brand new. Normally an object created inside the scope of a method will disappear when the method returns but in this case you add it to a list so it continues to exist. The name you give it when you create it with `new` basically doesn't matter. The 'unnamed' list element is the reference that continues to exist. – Radiodef Oct 23 '13 at 23:18
  • Also I guess I should correct my previous statement that Java is "pass by reference" for objects since technically Java is still "pass by value" in this case. The object reference itself is passed as a value to a new object reference. Some nitpickers would correct me. – Radiodef Oct 23 '13 at 23:51
  • Thanks. I've learnt a lot about java from you. I can see that my concepts are not clear enough... so whenever an now object is created, java'll have the new object stored to a new reference, and this reference itself is passed as a value to a new object reference. (but i guess what i need to know is that each item in the lists of object is stored in a brand new reference, is it?) – Sue Oct 24 '13 at 04:53
  • BTW, I've changed the programme and used objects to store `String className` and `boolean isPrivate`. Now there's a problem: no matter what class name I entered in the `JTextField`, it always pops up the "class name invalid" `messageDialog`. Please help? I'll post the code to the question – Sue Oct 24 '13 at 04:57
  • Looks like the problem is just this line `keyObject.containsKeyword(className.get(i))` where you probably mean to check containsKeyword on the input name and not the existing list. – Radiodef Oct 24 '13 at 22:03
  • I guess that's not the problem. `keyObject.containsKeyword()` is actually a method from `JavaKeywords` class from http://stackoverflow.com/questions/13979172/how-to-check-if-the-class-name-is-valid . I am afraid that it's because i failed to store the value in the virtual class object. and here's a detailed question of my question with more relevant codes: http://stackoverflow.com/questions/19565573/failed-to-store-variables-in-a-arraylist-of-class-object?noredirect=1#comment29041013_19565573 – Sue Oct 25 '13 at 05:09
  • I've tried to use it to check the existing list as well but then it showed "class saved" regardless of the input. and I didnt have the expected result print on screen (a JTextArea to show the public/private class type & class name for user to copy it) – Sue Oct 25 '13 at 05:12
0

I'm not entirely convinced by your over all approach. What I think "should"/"could" happen is, the user enters all the information you ask, they hit "accept", you valid the information that the user has entered and if it is correct, you create a new object representing the results of this input as you need.

I would, personally, avoid using an array of booleans, or at least, expose them differently. The main problem I have with it is keeping it all straight in my head, what does the element at 0 actually mean?

Instead, I would provide getter/setters on the ClassName class that allowed me to set/get particular properties. You could, of course, keep the values in an array internally, but anyone using the class wouldn't need to know how you store these values.

The problem with your check name Handler is the fact you are blocking the Event Dispatching Thread with your while-loop

This will stop you program from responding to user input (and painting itself)

        while (classObject.checkName(name) == true){
            JOptionPane.showMessageDialog(null, "Class name invalid. " +
                    "\nEntered name should not contain java keywords or equal to other existing names. " +
                    "\nPlease try again."); // doesn't work
            name = inputClassName.getText();
            classObject.addName(name);
        }// end if

Swing is a single threaded framework, meaning that all interactions and changes to the UI are expected to be executed within the context of the EDT. Equally, anything that blocks or stops this thread from processing the Event Queue, will stop it from responding to new events, including repaint requests, making your program hang

Instead, you should simply check the name within a if-else statement. If it's valid, create the new ClassName object, if it's not, display a message and let the method exit.

Check out Concurrency in Swing for more details

MadProgrammer
  • 323,026
  • 21
  • 204
  • 329
  • This is correct, I didn't notice that. The while loop will reevaluate itself infinitely and freeze the program since being inside the event means it doesn't give the chance to edit the text. The better procedure for this is to `if (classObject.checkName(name)) { showMessageDialog(...); return; }` and then do the reevaluation on the next attempt at entry. – Radiodef Oct 23 '13 at 20:17
  • Thank you. didn't realise the while-loop problem. And I think your approach is a better way too. If I create an new object for each set of class name and class type, is it that I should create an ArrayList to store all the objects created? But would it be more complicated as I have to call each object and then use the methods inside when I need to print out the results? – Sue Oct 23 '13 at 20:28
  • See my answer which is an implementation of what I think @MadProgrammer is also suggesting. And you don't need to explicitly use setters and getters unless the fields are private. If they are public you can access them directly. – Radiodef Oct 23 '13 at 20:31