my dog learned polymorphism*
The moose likes Swing / AWT / SWT and the fly likes Class Communications Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Java » Swing / AWT / SWT
Bookmark "Class Communications" Watch "Class Communications" New topic
Author

Class Communications

Michael Eller
Ranch Hand

Joined: Feb 28, 2004
Posts: 32
Hi,

I have a small project I am working on.
Right now it has two classes...one is the main class the other is a class that implements a JMenuBar. The main class creates an instance of the class implementing the JMenuBar. Some menu items are created dynamically based on the contents of a file. All this works fine.

What I want to do now is have something change on the main window (implemented by the main class) when the user clicks on a specific menu item.

Here is what I have so far:

The class that creates the menu:
public class WorkoutMenu implements ActionListener {

JMenuBar menuBar;
JMenu menu;
JMenuItem quitItem, viewItem;
ArrayList<String> userArray = new ArrayList<String>();
WorkoutRoutines wr;

public JMenuBar WorkoutMenu() {
. . .
//create the ViewMenu dynamically
this.makeViewMenu(menuBar);
. . .
return menuBar;
}

The menubar gets made and the event handlers work:

public void actionPerformed(ActionEvent event) {

if (event.getActionCommand() == "Exit") {

System.exit(0);

}

if (event.getActionCommand() == "Mike") {

wr.testText = "Mike is here";
wr.update();

}

}

In the above code, I want the wr.testText to update the label on the main frame.

This does not work....how can I get this to work correctly?

Thanks,
Mike
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38033
    
  22
Please use code tags (beneath the message window; it makes code much easier to read.

Get rid of the "implements ActionListener" and the actionPerformed() method. Put the actions where they belong, on the MenuItems. Add this sort of code to your constructor.System.exit(0) is rather drastic, and only safe for the simplest of applications. If you have several threads, they might be stopped in mid-task causing data corruption.

I'll let you work out how to update text if the viewItem is clicked.
Michael Eller
Ranch Hand

Joined: Feb 28, 2004
Posts: 32
OK,
I see the code button below.

So I made the changes you suggested.
In the events for the dynamic menus, all works well. I can even get a text value from the main window class.
But I cannot change what is there.
For testing, I created a method in the main class that would change the value of text string of the label. Calling that function, even to just do a simple println....causes a very long list of error messages...the first being this:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at WorkoutMenu$2.actionPerformed(WorkoutMenu.java:52)


Here is the code that is doing this:

WorkoutMenu.java
This method creates the new menu item and adds the actionlistener. This works fine. The call to changeUser(s) causes all the damage.


In WorkoutRoutines (the main class), the changeUser method looks like this:


Right now I am just trying to get it to print something to the console. But that is not happening.
I need a hint...or two

Thanks,
Mike
Michael Eller
Ranch Hand

Joined: Feb 28, 2004
Posts: 32
Ok, when I changed the "changeUser" method to static....it worked.
However, it still does not update the Label inside a panel on the main frame.
So that is where I am now, changing what is in the frame.

Thanks,
Mike
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38033
    
  22
I am afraid it is too late for me to think straight about changing users. Maybe tomorrow . . .

but . . .

There is something which doesn't feel right about changing a method to be static. Have you actually got a WorkoutRoutines object? You realise that your changeUser() method doesn't do anything to the label you are using for user name?
Michael Eller
Ranch Hand

Joined: Feb 28, 2004
Posts: 32
I understand that....changing what is in the JPanel...or displayed on the frame is what I want to do. That is my question here how do I do that?
Would it be OK to post all the code for both files...they are none too big.

Mike
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38033
    
  22
Yes, I think posting the whole code would be a good idea.
Michael Eller
Ranch Hand

Joined: Feb 28, 2004
Posts: 32
OK,
First is the main class WorkoutRoutines.java: Here I want the method changeUser to change the text of string in the testPanel. The comments in each file are put there for this posting to help you understand what I want to do.
I think this should be trivial as even if the code is in one file, I should be able to change what is presented to the user...I would think this is common. I am just not seeing how to do it.




And here is the WorkoutMenu class: Here dynamic menu items are created for the View menu. That works fine. I want the event handler to alter what is presented on the frame of the main class.

Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38033
    
  22
That'll teach me. I ought to have read your post properly. I got a NullPointerException too.

You have no obvious constructor in the Menu class, so you are never initialising "wr". You need a constructor, and you need to initialise "wr". That will probably sort out your problems.

You have some bad style in your code; you have a method with a JMenuBar return type whose name is the same as the name of the class. It is very easy in this case to mistake that method for a constructor.

Your methods and fields in the Routines class should not be static, with the single exception of the main method. Delete static and give all the fields private access. Change the body of the run() method in the Runnable in invokeLater to read:

new WorkoutRoutines().createAndShowGUI();

In the createGUI method, move the bit about setVisible to the last statement. And change the new WorkoutMenu() call to have "this" passed as an argument.

In the changeUser method write whicheverLabel.setText(testText);

You will be pleasantly surprised!

I fulminate about NullPointerExceptions (NPEs) every now and again on the Ranch, like here. Another reason I have found more recently is that you can't write "throw null;" next time you get an NPE, remember that lot. Some people say NPEs cause them more annoyance than anything else in Java programming.

[edit]Slight grammatical changes[/edit]
[ March 26, 2008: Message edited by: Campbell Ritchie ]
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38033
    
  22
More threads about NPEs which might be of interest: this one, and this one. The link of Tony Morris's is no longer available.
Michael Eller
Ranch Hand

Joined: Feb 28, 2004
Posts: 32
OK,
I have three things before I set to this.
First, Thank you for the info on the coding style, technique, etc. This is one of my biggest concerns. The problem is all the tutorials out there do things differently and it is hard to determine which is the right way/best way to approach things.

Next, you say I do not initialize "wr". How can I do that, it is a reference to the main class...if I initialize it with "new", another main class will be created...this is not what I want.

Third, I was following the Sun Java tutorial...this is where I got the "static void createAndShowGUI" from...and if I use variables that are not static, then I get errors. So how to approach this?

I am working on the other stuff.
MTF

Thank you,
Mike
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38033
    
  22
There is this unfortunate habit some book writers have of putting all sorts of code into the main method; it gets them out of the bother of creating an object which means they can get more code per square inch of page, but not creating an object means they aren't really using object-oriented programming. Since the main method is static, it cannot invoke instance ("non-static") members of the class. So you would have to make everything else static.
The Java tutorial does the same, but if you look in other places, like where the bit about invokeLater actually comes from, here, you see "new MyApp()" appears in both versions. So that is creating a new object. What you want.

You want a constructor for every class which has fields (at least I think you do); initialise all the fields in the constructor. That reduces the risk of an NPE; I presume you have seen the threads about NPEs I quoted earlier.

The easiest way to pass a reference to your WorkoutRoutines object is to invoke the WorkoutMenu constructor like this "new WorkoutMenu(this)" from inside a non-static part of the WorkoutRoutines object. That will work, but even that makes me suspicious; it doesn't feel right.


If you follow what I suggested before, you will get your app to work; I wrote a file called wouser and had it show "Campbell is now in charge" on the JLabel. But I think you need to pull the whole thing apart. Suggest you create several new classes:

  • WorkoutDemo. This class will have a main method in. Create a new object of the Workout class.
  • MenuFactory. This will have methods to create JMenuItem objects. The methods can be static. Pass things like the title (String) listener (ActionListener) and get a complete JMenuItem object back. Then add it to the JMenu.
  • WorkoutFileReader. You can use a Scanner object to read a text file and return a List<String> or similar.
  • WorkoutDisplay. This sets up a JFrame, the panel and label and puts the menu items on the menu, etc, etc.
  • You may wish to use custom-made classes for your own panel, etc. public class WorkoutPanel extends JPanel . . .
  • A Workout class which can store the names and all the data you require. Separate the data from the display.
  • The WorkoutDemo class can call the other classes and can can pass references from one class to another so they can communicate to one another.

    Sorry it seems such a big job now.
    Good luck!
    Michael Eller
    Ranch Hand

    Joined: Feb 28, 2004
    Posts: 32
    Ok,
    I have been playing around with this...still not getting it right.

    Lets say I have three classes: class1, class2, and class3.
    class1 has the main method and creates instances of itself, class2, and class3. Now, if I need class2 to change something within class3....how can I do that. I cannot create another class3 by using the constructor. I just want to be able to access a method in class3 that changes a member variable of that class3 from class2.

    Can I do this?

    Lets say I have a panel with some textfields. If I have a class that reads something from the user, then makes a call to the class that implements the panel with the textfields to change the text in them. This should be common actions....isn't it?

    Could you provide an example or link to one?

    I vaguely remember doing this years ago with some statement at the beginning of the class.

    Thanks,
    Mike
    Campbell Ritchie
    Sheriff

    Joined: Oct 13, 2005
    Posts: 38033
        
      22
    You might want to use class1 to receive a message from class2 then call a method in class3.
    Does that help?
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Class Communications
     
    Similar Threads
    Help File Focus Issue
    convert swing to applet
    Resize problem with JMenuBar
    OO Question
    Creating one class from another