views:

329

answers:

2

My View is derived from ViewPart, but I have a listener on it which receives Events from non-GUI threads.

If something is supposed to happen on within the GUI thread, it has to go through asyncExec().

So far so good.

The thing is, the GUI elements are created in createPartControl(), so they can't be final. At the moment I just put them in a AtomicReference which can be final just fine.

What is your approach?

Update

to clarify the problem using the example from one of the answers below:

public class MyView extends ViewPart implements SomeNetWorkActionListener {

    private Text text1;

    private final AtomicReference<Text> text3 = new AtomicReference<Text>();

    public void createPartControl(Composite parent) {
        text1 = new Text(parent, SWT.None);
        final Text text2 = new Text(parent, SWT.None);
        text3.set(new Text(parent, SWT.None));

        parent.getDisplay().asyncExec(new Runnable() {
            public void run() {
                text1.setText("Hello");
                text2.setText("World");
            }
        });
    }

    public void setFocus() {
        text1.forceFocus();
    }

    @Override
    public void someNetworkMessageReceived(MyMessage message) {
        getSite ().getShell ().getDisplay().asyncExec(new Runnable() {
            public void run() {
                //... how to reference text 1 or text 2?
                text3.get().setText(message.toString()); // this is what I do at the moment
            }
        });
    }
}
A: 

I typically use Eclipse Jobs when I want to execute something in a non-GUI thread and then all I need to do is to put the display in the constructor, then reference the final member variable from the run method.

Kire Haglin
+1  A: 

You just access text1. It doesn't need to be wrapped and it doesn't need to be final.

There are two basic places to put your variables: at the class level (here they can't be final because they aren't in the constructor), or within a method where they can be declared final no matter what the method is called. Here is an example of both ways of using variables:

public class MyView extends ViewPart {
    private Text text1;

    public void createPartControl(Composite parent) {
        text1 = new Text(parent, SWT.None);
        final Text text2 = new Text(parent, SWT.None);

        parent.getDisplay().asyncExec(new Runnable() {
            public void run() {
                text1.setText("Hello");
                text2.setText("World");
            }
        });
    }

    public void setFocus() {
        text1.forceFocus();
    }

    public void someNetworkMessageReceived(MyMessage message) {
        getSite().getShell().getDisplay().asyncExec(new Runnable() {
            public void run() {
                text1.setText(message.toString());
            }
        });
    }
}

Anonymous inner classes behave just as all other inner classes do. When you instantiate an inner class, java transparently passes a reference to the outer class(es) into the inner class. This allows you to access any of the fields in the outer class from within the inner class. Since the inner class holds a reference to the outer class there is no way the outer class can get garbage collected or go out of scope before the inner class does. This is why you do not need to make text1 final. It will always be available for inner classes to use.

When you declare a variable inside a method, it is a different story. The anonymous inner class declared in createPartControl() will probably outlast the scope of the method. It might not, but Java doesn't take any chances. When the method goes out of scope the reference to text2 will be lost and the inner class would have been out of luck. To fix this Java requires you to use the final modifier on text2. What final does is that it guarantees that variable will always point to the same object in memory. Since Java now has a guarantee where that object will be in memory, it can pass in that location into the inner class. For all practical purposes it is like it is creating a new variable called text1 of type Text inside the inner class thereby letting you access it long after the method goes out of scope.

In your case you would just make all the UI components that need to be accessed from within someNetworkMessageReceived() instance variables just like text1 is.

Hopefully this clears up your confusion with the final modifier.

rancidfishbreath
I used your example to illustrate my point, see above.
Mauli
Updated answer in response to the new illustration.
rancidfishbreath
I'm so embarrassed right now, you are of course right. My original problem had actually something to do with anonymous inner classes, so what you say applies there. I guess I just was a bit to fixated on the whole final thing. Can I delete my question now? :-)
Mauli