Creating an Alert Box with Swing/mxj

Jan 23, 2006 at 6:42pm

Creating an Alert Box with Swing/mxj

Hi All,

I’ve put together a simple mxj class to create an alert box using Swing. It compiles and runs fine on our Athlon 64 4000+, running XP with MaxMSP 4.5.6, with JVM Version 1.5.0_04, and displays the dialog upon receiving a bang with little or no noticeable lag.

However, when I run the app on my OS X 10.4.4 machine, a G4 1 gHz, running 4.5.6 with JVM 1.5.0_05, I get the “spinning wheel of death” and Max hangs indefinitely and requires me to force quit. I should clarify that the code compiles fine and gives me no errors on either machine.

Both the patch and the java code are included in the text below. I’ve also attached the .class file as well.

Does anyone know why this might be?

Thanks in Advance,
-Henry

< ----save below as SaveChanges_test.pat----->

max v2;
#N vpatcher 100 100 326 424;
#P window setfont “Sans Serif” 9.;
#P newex 75 140 59 9109513 fromsymbol;
#P message 115 90 49 9109513 name bob;
#P button 105 255 15 0;
#P button 90 237 15 0;
#P button 75 219 15 0;
#P newex 75 169 57 9109513 select 0 1 2;
#P button 75 69 33 0;
#P newex 75 115 85 9109513 mxj SaveChanges;
#P connect 6 0 0 0;
#P connect 1 0 0 0;
#P connect 0 0 7 0;
#P connect 7 0 2 0;
#P connect 2 0 3 0;
#P connect 2 1 4 0;
#P connect 2 2 5 0;
#P pop;

< ----save below as SaveChanges.java and compile----->

//
// SaveChanges.java
//
// 01.21.06, Henry Till (henrytill@gmail.com)
//

import com.cycling74.max.*;
import javax.swing.JOptionPane;

public class SaveChanges extends MaxObject
{
String name = null;

public SaveChanges(Atom[] atoms) {
declareInlets(new int[] { 1 });
declareOutlets(new int[] { 1 });
}

public void bang() {

Object[] options = {“Don’t Save”,
“Cancel”,
“Save”};

int n = JOptionPane.showOptionDialog(null, // null to hatch from parent frame
“Do you want to save changes to “
+ name,
“Save Changes?”,
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[2]);

if (n == JOptionPane.YES_OPTION) {
outlet(0, “2″);

} else if (n == JOptionPane.NO_OPTION) {
outlet(0, “0″);
} else if (n == JOptionPane.CANCEL_OPTION) {
outlet(0, “1″);
} else {
post(“no answer given”);
}
}

public void inlet(int i) { }

public void inlet(float f) { }

public void list(Atom[] list) { }

public void anything(String s, Atom[] args) {
if(s.equals(“name”))
name = Atom.toOneString(args);
}

}

#24118
Jan 23, 2006 at 7:22pm

You have to call nextWindowIsModal() before displaying the Swing window, that should fix it.
Look at the javadocs for MaxSystem, it’s somewhere in there.

Roby

#69298
Jan 23, 2006 at 8:26pm

Hi Roby, Thanks for the reply. The api doc makes it sound as though
this should do the trick.

Just to clarify, would it be correct to put this line:

MaxSystem.nextWindowIsModal();

right before the following block?

int n = JOptionPane.showOptionDialog(null, // null to hatch from
parent frame
“Do you want to save changes to “
+ name,
“Save Changes?”,
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[2]);

This compiled okay, but when I went to run it on OS X, it still hung,
which made me think maybe I am doing this wrong.

-H

#69299
Jan 23, 2006 at 9:40pm

> Just to clarify, would it be correct to put this line:
>
> MaxSystem.nextWindowIsModal();
>
> right before the following block?
>

> This compiled okay, but when I went to run it on OS X, it still hung,
> which made me think maybe I am doing this wrong.
>

What I do is the following:
I declare in my class:
MaxSystem maxsys = new MaxSystem();

and later before displaying the window I put:

maxsys.nextWindowIsModal();

Roby

#69300
Jan 23, 2006 at 10:56pm

Roby et al,

That’s clearly the right way to do it – so I changed my code, and
it’s compiling fine, but still hanging when I run it.

Have you or anybody else successfully displayed an Alert Box using
JOptionPane in mxj on OS X before?

-Henry

#69301
Jan 24, 2006 at 11:08am

Henry Till wrote:
> Have you or anybody else successfully displayed an Alert Box using
> JOptionPane in mxj on OS X before?

Have you tried using SwingUtilities.invokeLater() to handle Swing
display stuff asynchronously in Swing’s own event thread? Thus:

SwingUtilities.invokeLater(new Runnable(){
public void run(){
JOptionPane.showConfirmDialog(null,”Hello”); //eg
}
});


Owen

#69302
Jan 25, 2006 at 6:24pm

Owen,

Thanks a lot for the tip. Using this technique did the trick.

-Henry

#69303
Jan 25, 2006 at 8:56pm

Henry,
Would you be so kind to share your code of the original example
as enhanced with this trick? I am particularly interested in how
you communicate the result of the asynchronously executed OptionPane
call
back to the mxj thread.
thanks
-jennek

#69304
Jan 26, 2006 at 12:19pm

Hi Jennek,

In general you don’t need to – the rest of the action can be done in the
Swing thread, or some other event handling thread. In this specific
case there doesn’t seem to be much choice as it was the very condition
of having the mxj thread wait on the swing thread that seemed to be
causing deadlock.


Owen

#69305
Jan 26, 2006 at 9:05pm

OK, I was worried that calls to outlet would cause more threading
problems,
as they run in in a Max thread. But from the ‘Writing Max externals
in Java’
document from Topher I understand that this is safe to do (v0.3 page 42)
“It is worth noting that when using Java threads inside of your Max
external, any outlet
calls you make back into the Max application will automatically be
deferred for handling
by the low-priority main thread for normal outlet calls and the high-
priority scheduler
thread for outletHigh calls.”

One thing puzzles me: why is there no hang up on WinXP?
Anyway, I am glad to have learned about invokeLater().

For the sake of archiving, I’ll post my edition of your code below.
-jennek

//
// SaveChanges.java
//
// 01.21.06, Henry Till (henrytill@gmail.com)
//

import com.cycling74.max.*;
import javax.swing.*;

public class SaveChanges extends MaxObject {
String name = null;

public SaveChanges(Atom[] atoms) {
declareInlets(new int[] { 1 });
declareOutlets(new int[] { 1 });
}

public void bang() {

SwingUtilities.invokeLater(new Runnable() {
public void run() {

Object[] options = { “Don’t Save”, “Cancel”, “Save” };

int n = JOptionPane
.showOptionDialog(null, // null to hatch from parent
// frame
“Do you want to save changes to ” + name,
“Save Changes?”,
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE, null, options,
options[2]);

if (n == JOptionPane.YES_OPTION) {
outlet(0, “2″);

} else if (n == JOptionPane.NO_OPTION) {
outlet(0, “0″);
} else if (n == JOptionPane.CANCEL_OPTION) {
outlet(0, “1″);
} else {
post(“no answer given”);
}

}
});

}

public void inlet(int i) {
}

public void inlet(float f) {
}

public void list(Atom[] list) {
}

public void anything(String s, Atom[] args) {
if (s.equals(“name”))
name = Atom.toOneString(args);
}

}

#69306
Jan 26, 2006 at 11:13pm

jennek geels wrote:

> One thing puzzles me: why is there no hang up on WinXP?

It seems to have something to do with Carbon-Cocoa interaction. As far
as I can tell, one has to make sure your main thread and the AWT/Swing
thread are never in contention or a deadlock will occur.


Owen

#69307
Jan 29, 2006 at 12:45am

#69308
Jan 29, 2006 at 1:16am

Yes. There is indeed much potential for deadlock when using swing on OS X due to the fact that swing does its event handling via cocoa and max/msp has its own event handlin loop which uses carbon. It definitely took a significant amount of vudu to get swing to work at all on os x.

Regardless. Anytime you display a frame or other UI element you should do it from the swing/awt thread. From suns own docs.

“To avoid the possibility of thread problems, we recommend that you use invokeLater to create the GUI on the event-dispatching thread for all new applications. If you have old programs that are working fine they are probably OK; however you might want to convert them when it’s convenient to do so. “

This is probably particularly important on OS X given the fact that we are dealing with cocoa java embedded in a carbon application. I wish it wasn’t so but i think we need to live with it for the time being!

#69309

You must be logged in to reply to this topic.