Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

basic GUI question

120 views
Skip to first unread message

jrobinss

unread,
Jul 8, 2009, 1:13:52 PM7/8/09
to

Hi all, I'm very sorry about the simplicity of this question, but I
don't seem to get around it.

First, this is what I want:
a command-line interface (CLI) program that displays a dialog asking
something from the user. The user has the choice, either answer the
graphic dialog or else type in "stop" in the CLI (which hides or
destroys the GUI).

Seems simple enough. The principle is to launch the CLI, upon
receiving command "start" launch the GUI in a separate thread, and
wait both for user input in the dialog and in CLI.

My problems, of course, stem from the famous EDT. I've taken the
opportunity to read up on it (not enough I suppose), but I still can't
get it right. Either my dialog is ok, but the CLI hangs, or the CLI
responds, but the dialog is erratic, with freezes (an behavior
described on several web sites and attributes to bad thread
management).

Question: who can give me the code? :-)

More detailed question: here are some code samples that obviously
don't work, otherwise I wouldn't be here; Any comments welcome.
Note: I've suppressed some code building the CLI, so it's not an
SSCCE. I suspect that there are enough wrongs in what I'm posting to
start correcting. If not, I'll post an SSCCE.


public class DialogTest {
[ ... main and other stuff...]

private Thread dialogThread_ = null;
private Frame myFrame_ = buildFrame();
private Frame buildFrame() {
// builds a kind of GUI, its correctness is not important here
JFrame frame = new JFrame("my frame");
JTextField myTxtField = new JTextField(10);
Object[] messageElements = {"Some question", myTxtField};
JOptionPane optionPane = new JOptionPane(messageElements,
JOptionPane.QUESTION_MESSAGE,
JOptionPane.YES_NO_OPTION);
frame.setContentPane(optionPane);
return frame;
}
private void onInput(String input) { // some callback
System.out.println("input=" + input);
}

/**
* this implementation doesn't provide any means for the user to
* stop the GUI using CLI, because it waits for a GUI answer.
*/
public void processCommandBasic(CliCommand cmd) {
if (cmd == CliCommand.start) {
String answer = JOptionPane.showInputDialog(myFrame_,
"What?");
onInput(answer);
} else {
myFrame_.setVisible(false);
}
}

/**
* this implementation hands back the hand to the CLI,
* but freezes the first time the user tries to input.
*/
public void processCommandWithMyFrame(CliCommand cmd) {
if (cmd == CliCommand.start) {
myFrame_.pack();
myFrame_.setVisible(true); // input to be handled by frame
} else {
myFrame_.setVisible(false);
}
}

/**
* this freezes and hangs the first time it's called.
*/
public void processCommandUsingJOptionPane(CliCommand cmd) {
if (cmd == CliCommand.start) {
dialogThread_ = new Thread() {
@Override
public void run() {
String answer =
JOptionPane.showInputDialog(myFrame_, "What?");
onInput(answer);
}
};
SwingUtilities.invokeLater(dialogThread_);
} else {
myFrame_.setVisible(false);
}
}

/**
* this works the same as the previous one, but with a frame.
*/
public void processCommandUsingFrame(CliCommand cmd) {
if (cmd == CliCommand.start) {
Runnable showDialog = new Runnable() {
public void run() {
myFrame_.pack();
myFrame_.setVisible(true);
}
};
SwingUtilities.invokeLater(showDialog);
} else {
myFrame_.setVisible(false);
}
}
}

--
JRobinss

Simon

unread,
Jul 8, 2009, 1:45:44 PM7/8/09
to
jrobinss schrieb:

> Hi all, I'm very sorry about the simplicity of this question, but I
> don't seem to get around it.
>
> First, this is what I want:
> a command-line interface (CLI) program that displays a dialog asking
> something from the user. The user has the choice, either answer the
> graphic dialog or else type in "stop" in the CLI (which hides or
> destroys the GUI).
>
> Seems simple enough. The principle is to launch the CLI, upon
> receiving command "start" launch the GUI in a separate thread, and
> wait both for user input in the dialog and in CLI.
>
> My problems, of course, stem from the famous EDT. I've taken the
> opportunity to read up on it (not enough I suppose), but I still can't
> get it right. Either my dialog is ok, but the CLI hangs, or the CLI
> responds, but the dialog is erratic, with freezes (an behavior
> described on several web sites and attributes to bad thread
> management).
>
> Question: who can give me the code? :-)
>
> More detailed question: here are some code samples that obviously
> don't work, otherwise I wouldn't be here; Any comments welcome.
> Note: I've suppressed some code building the CLI, so it's not an
> SSCCE. I suspect that there are enough wrongs in what I'm posting to
> start correcting. If not, I'll post an SSCCE.
>

I'm a bit confused about your code because I don't see the part where
the CLI input is read. I believe however, that this (Thread?) is where
your problem is.

Anyway, does the attached code work for you? It creates the dialog in
one thread (the EDT) and creates a separate thread for the CLI. Both
threads notify each other when they have a result. I don't have an
elegant solution to avoid the Thread.stop() in the end, except maybe
making this thread a daemon thread. I am not aware of any more elegant
method to stop a thread while it is reading input (Closing the stream?
Rather not.).

Some remarks regarding your version:
- At least in one place you are creating a Thread where you only need a
Runnable.
- For most people it is easier to follow your code if it follows Java
code conventions. E.g. is CliCommand.start a constant (=static final)?
Then use UPPERCASE names etc.

Cheers,
Simon


import java.util.Scanner;

import javax.swing.JDialog;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class Test {

private static Object lock = new Object();
private static String answer = null;
private static JDialog dialog;

public static void main(String[] argv) {

SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
dialog = new JDialog();
JTextField field = new JTextField(10);
dialog.getContentPane().add(field);
dialog.setModal(true);
dialog.pack();
dialog.setVisible(true);
synchronized (lock) {
if (answer == null) {
Test.answer = field.getText();
} else {
System.err.println("CLI has set answer. "+
"Ignoring answer from GUI.");
}
lock.notify();
}
}
});

Thread cliThread = new Thread("CLI-Thread") {
@Override
public void run() {
System.out.println("Please type your answer: ");
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
synchronized (lock) {
Test.answer = input;
lock.notify();
}
}
};
cliThread.start();

synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (dialog.isVisible()) {
dialog.setVisible(false);
}
if (cliThread.isAlive()) {
// don't do this, only for demo
cliThread.stop();
}
System.out.println("Answer = " + answer);
}
System.exit(0);
}
}

markspace

unread,
Jul 8, 2009, 1:54:14 PM7/8/09
to
jrobinss wrote:
> If not, I'll post an SSCCE.

Please post an SSCCE. There's just a bit too much missing here.
However I did notice a few things.


> private Frame myFrame_ = buildFrame();
> private Frame buildFrame() {
> // builds a kind of GUI, its correctness is not important here


Correctness is important. This is not built on the EDT. This object
must be constructed on the EDT.


> * this works the same as the previous one, but with a frame.
> */
> public void processCommandUsingFrame(CliCommand cmd) {
> if (cmd == CliCommand.start) {
> Runnable showDialog = new Runnable() {


This is not too bad. invokeLater() takes a Runnable, not a thread, so
this is better than the one that makes a thread. However you must do
more than call "pack()" on the EDT. The whole object and all its
subcomponents must be created on the EDT. Move the call to
"buildFrame()" to here.


> public void run() {
> myFrame_.pack();
> myFrame_.setVisible(true);
> }
> };
> SwingUtilities.invokeLater(showDialog);
> } else {

> myFrame_.setVisible(false);

setVisible() is NOT thread safe. Call this on the EDT.


Fix those and give us a driver for this code which exhibits the problem.
You probably don't need much more than a main method which calls a few
of these methods to make a complete program. We don't need full source
code, just enough that it duplicates the problem you are seeing.

Daniel Pitts

unread,
Jul 9, 2009, 12:17:44 AM7/9/09
to
jrobinss wrote:
> Hi all, I'm very sorry about the simplicity of this question, but I
> don't seem to get around it.
>
> First, this is what I want:
> a command-line interface (CLI) program that displays a dialog asking
> something from the user. The user has the choice, either answer the
> graphic dialog or else type in "stop" in the CLI (which hides or
> destroys the GUI).
>
> Seems simple enough. The principle is to launch the CLI, upon
> receiving command "start" launch the GUI in a separate thread, and
> wait both for user input in the dialog and in CLI.
>
> My problems, of course, stem from the famous EDT. I've taken the
> opportunity to read up on it (not enough I suppose), but I still can't
> get it right. Either my dialog is ok, but the CLI hangs, or the CLI
> responds, but the dialog is erratic, with freezes (an behavior
> described on several web sites and attributes to bad thread
> management).
>
> Question: who can give me the code? :-)
>
> More detailed question: here are some code samples that obviously
> don't work, otherwise I wouldn't be here; Any comments welcome.
> Note: I've suppressed some code building the CLI, so it's not an
> SSCCE. I suspect that there are enough wrongs in what I'm posting to
> start correcting. If not, I'll post an SSCCE.

import javax.swing.*;
import java.awt.*;
import java.io.IOException;

/**
* @author Daniel Pitts
*/
public class Input {

public static void main(String...args) throws IOException {
EventQueue.invokeLater(new Runnable() {
public void run() {
JOptionPane.showConfirmDialog(null, "Config");
System.exit(0);
}
});
System.in.read();
System.exit(0);
}
}

--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Andrew Thompson

unread,
Jul 9, 2009, 3:48:39 AM7/9/09
to
On Jul 9, 3:54 am, markspace <nos...@nowhere.com> wrote:
> jrobinss wrote:
> > If not, I'll post an SSCCE.
>
> Please post an SSCCE.  There's just a bit too much missing here.

Good advice.

> >     private Frame buildFrame() {
> ..
> ....This is not built on the EDT.

It is AWT (so it should not have to be built on the EDT).

--
Andrew T.
pscode.org

jrobinss

unread,
Jul 9, 2009, 5:51:38 AM7/9/09
to

Thanks all for your replies!

I'll now do some testing. Then I'll report the results here. If I'm
still stuck, I'll post an SSCCE.

The reason I didn't post an SSCCE is that for the CLI part I use a
custom utility class that I wrote that takes user input and manages
command recognition, exit messages etc. So it would have been
cumbersome to post it. Again, next time I will, if the first answers
are not enough to get me going.

BTW, I'm aware that enums should be upper case, only here I use them
directly as commands, and I'd rather the "usage" command provided
lower-case commands to the user. So it's a shortcut for enums who have
a string that's different from their name.

More later...
--
JRobinss

Andrew Thompson

unread,
Jul 9, 2009, 6:41:14 AM7/9/09
to
On Jul 9, 7:51 pm, jrobinss <julien.robins...@gmail.com> wrote:
>...If I'm still stuck, I'll post an SSCCE.

>
> The reason I didn't post an SSCCE is that for the CLI part I use a
> custom utility class that I wrote that takes user input and manages
> command recognition, exit messages etc. So it would have been
> cumbersome to post it. Again, next time I will, ...

No, don't do that. A request for an SSCCE is not
an invitation to 'dump all your code' to the forum.

Please *read* the SSCCE document before posting
any code that you think is an SSCCE.
<http://pscode.org/sscce.html>

--
Andrew T.
pscode.org

markspace

unread,
Jul 9, 2009, 10:48:07 AM7/9/09
to


No, he actually builds a JFrame in the method. He's just using a super
type of JFrame (Frame) for some odd reason. Could be a typo.


markspace

unread,
Jul 9, 2009, 10:53:38 AM7/9/09
to
jrobinss wrote:
> Thanks all for your replies!
>
> I'll now do some testing. Then I'll report the results here. If I'm
> still stuck, I'll post an SSCCE.
>
> The reason I didn't post an SSCCE is that for the CLI part I use a
> custom utility class that I wrote that takes user input and manages
> command recognition, exit messages etc. So it would have been
> cumbersome to post it. Again, next time I will, if the first answers
> are not enough to get me going.


As Andrew said, please DON'T. Write a short little command interpreter
that only takes two commands (start and stop) and just show us that,
with a short example of creating a GUI component. We don't want to see
your whole code base. Just an example that reproduces the problem.


>
> BTW, I'm aware that enums should be upper case, only here I use them
> directly as commands, and I'd rather the "usage" command provided
> lower-case commands to the user.


enum Commands { START, STOP }

String name = START.toString().toLowerCase();

Andrew Thompson

unread,
Jul 9, 2009, 11:07:28 AM7/9/09
to
> type of JFrame (Frame) for some odd reason.  ...

Good point. :D

Just goes to show you how closely I examine code
that is 'not an SSCCE'. ;)

--
Andrew T.
pscode.org

jrobinss

unread,
Jul 9, 2009, 12:22:50 PM7/9/09
to

[note to andrew: I think I understand what an SSCCE is, and I've spent
some time reducing its size before posting it]

Ok, here's an SSCCE. Its behavior currently is that, upon "start", a
user dialog is created and displayed. When the dialog is validated,
the result is echoed on the command-line. The command "stop" closes
the dialog. One can do "start", OK and "stop" any number of times
(however it's not robust to several consecutive "start"s).

That's what it should do, and what it does after a while. In fact, the
first time the dialog is demanded, it seems to have a problem running:
it doesn't show, then it freezes, and the only solution to get it
active is to hit enter in the CLI several times. After that subsequent
requests work fine.

Question is: why? How to make it work?

BTW, I'm aware that there will be a number of remarks on the code,
even without the threading issue. No problem... :-)


Oh and thanks to Simon for introducing me to java.util.Scanner. I
didn't know about it, and was still getting input with
new BufferedReader(new InputStreamReader(System.in)).readLine();
It's nicer with Scanner.

(SSCCE indented with only two spaces, otherwise I had trouble limiting
to 80 chars)
============
package jrobinss.cli_dialog;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.Scanner;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class DialogSSCCE {

// CLI stuff
// ---------

/**
* lowercase because they are used as user commands
*/
enum UserCommands {
start,
stop
}

public static void main(String[] args) {
new DialogSSCCE().doOperations();
System.exit(-1);
}

private void doOperations() {
while (true) {
String userStr = getUserInput();
// command "x" is for exit
if ("x".equalsIgnoreCase(userStr)) {
return;
}
doOperation(userStr);
}
}

private String getUserInput() {
System.out.println("Please enter your input... "
+ Arrays.toString(UserCommands.values()));


Scanner scanner = new Scanner(System.in);

return scanner.nextLine();
}

private void doOperation(String str) {
Scanner scanner = new Scanner(str);
if (scanner.hasNext()) {
String word = scanner.next();
if (word != null && ! "".equals(word)) {
try {
UserCommands cmd = UserCommands.valueOf(word);
processCommand(cmd);
} catch (Exception e) {
System.out.println("Sorry, can't understand command " + word
+ ", available commands are: "
+ Arrays.toString(UserCommands.values
()));
}
}
}
}

// now for the GUI part
// --------------------

private JFrame myFrame_ = null;
private JOptionPane myOptionPane_ = null;
private JTextField myTxtField_ = null;
private void buildFrame() {
myFrame_ = new JFrame("my frame");
myTxtField_ = new JTextField(10);
Object[] messageElements = {"Enter something", myTxtField_};
myOptionPane_ = new JOptionPane(messageElements,
JOptionPane.QUESTION_MESSAGE,
JOptionPane.YES_NO_OPTION);
myOptionPane_.addPropertyChangeListener(new MyPptyChangeListener
());
myFrame_.setContentPane(myOptionPane_);
myFrame_.pack();
}

private class MyPptyChangeListener implements PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent evt) {
if (myFrame_ == null) {
return;
}
String prop = evt.getPropertyName();

if (myFrame_ != null
&& myFrame_.isVisible()
&& (evt.getSource() == myOptionPane_)
&& (JOptionPane.VALUE_PROPERTY.equals(prop) ||
JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))) {
Object value = myOptionPane_.getValue();
if (value == JOptionPane.UNINITIALIZED_VALUE) {
return;
}

String result = null;
if (value.equals(JOptionPane.YES_OPTION)) {
result = myTxtField_.getText();
} else {
System.out.println("GUI cancelled, no result");
}
clearAndHide(); // destroys the GUI!
if (result != null) {
System.out.println("got GUI result=" + result);
}
}
}
}

private void clearAndHide() {
if (myFrame_ != null) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
myFrame_.setVisible(false);
myFrame_ = null;
}
});
}
}

private void processCommand(UserCommands cmd) {
if (cmd == UserCommands.start) {


Runnable showDialog = new Runnable() {
public void run() {

buildFrame();
myFrame_.setVisible(true);
}
};
SwingUtilities.invokeLater(showDialog);
} else {
assert(cmd == UserCommands.stop);
clearAndHide();
}
}
}
===========

Thanks for reading. :-)
--
JRobinss

jrobinss

unread,
Jul 9, 2009, 12:24:02 PM7/9/09
to

Daniel Pitts wrote:
[solution deleted]

Sorry for being obtuse, but I copy-pasted your code into Eclipse, and
its execution only waits for any input by the user, and then exits.

The EDT seems to never be activated.

This is purely an experimentation result. I suppose for you it
produces an "OK" dialog?

--
JRobinss

jrobinss

unread,
Jul 9, 2009, 12:24:47 PM7/9/09
to

Andrew Thompson wrote:
> markspace wrote:
>>> private Frame buildFrame() {

>> ....This is not built on the EDT.
>
> It is AWT (so it should not have to be built on the EDT).

I tried creating my frame on the EDT, it changed nothing. :-(

--
JRobinss

jrobinss

unread,
Jul 9, 2009, 12:26:15 PM7/9/09
to

Simon wrote:
>
> Anyway, does the attached code work for you?

I doesn't compile. :-)
(only because you use @override for an interface method
implementation, I just checked, I'm still with Java 5 so it isn't
accepted)

BTW, to the best of my knowledge the Thread:stop() method is
deprecated, and should be replaced with interrupt().

I ran your code, and saw only the CLI, no GUI. When I typed something
in, it obviously triggered the EDT, because I ran into an NPE, so I
changed your line
if (dialog.isVisible()) {
dialog.setVisible(false);
}
to
if (dialog != null && dialog.isVisible()) {
(the dialog wasn't yet created)

With this corrected, upon startup I only see the CLI, and when I type
in some input, the program exits. (same as Daniel's code in fact)

Could it be that the execution from Eclipse is in cause? I haven't
tested from the command-line... Seems unlikely.
--
JRobinss

markspace

unread,
Jul 9, 2009, 12:35:37 PM7/9/09
to
jrobinss wrote:
> [note to andrew: I think I understand what an SSCCE is, and I've spent
> some time reducing its size before posting it]
>
> Ok, here's an SSCCE. Its behavior currently is that, upon "start", a


I haven't read your SSCCE yet, but I thought I'd show you my solution. I
notice you have one extra niggle that was mentioned earlier (the
property change listener).


package serverwithgui;

import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/**
*
* @author Brenden
*/
public class ServerWithGui {

public static void main(String[] args) throws Exception
{
BufferedReader input = new BufferedReader( new InputStreamReader(
System.in ) );
for(;;) {
System.out.print(" cmd> ");
System.out.flush();
String s = input.readLine();
if (s != null) {
if ("start".equals(s)) {
Gui.start();
} else if ("stop".equals(s)) {
Gui.stop();
} else {
System.err.println("Didn't recognize: " + s);
}
} else { // s == null
break; // exit for(;;) loop
}
} // for(;;)
}

}

class Gui {

// Utility class: "start()" and "stop()"

private Gui() {} // non-instantiable, use start and stop methods

private static JFrame jf;

public static void start()
{
startGuiOnEdt();
}

public static void stop()
{
stopGuiOnEdt();

}

private static void startGuiOnEdt()
{
SwingUtilities.invokeLater( new Runnable() {

public void run()
{
createAndShowGui();
}
} );
}

private static void createAndShowGui() {
jf = new JFrame( "Please answer the question.");
JPanel p = new JPanel();
p.add( new Label( "What is your quest?"));

final JTextField f = new JTextField( 20 );
f.addActionListener( new ActionListener() {

public void actionPerformed(ActionEvent e)
{
System.out.println( f.getText() );
f.setText( "" );
}
} );

p.add( f );
jf.add( p );

jf.pack();
jf.setLocationRelativeTo( null );
jf.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
jf.setVisible( true );
}

private static void stopGuiOnEdt()
{
SwingUtilities.invokeLater( new Runnable() {

public void run()
{
stopGui();
}
} );
}

private static void stopGui()
{
jf.setVisible( false );
jf.dispose();
jf = null;
}
}

markspace

unread,
Jul 9, 2009, 1:04:46 PM7/9/09
to
jrobinss wrote:

> BTW, I'm aware that there will be a number of remarks on the code,
> even without the threading issue. No problem... :-)


Yes. Your property change listener is just bizarre. You need help with
Swing, not multi-threading. Read the docs on JOptionPane, since you're
trying to use one:

<http://java.sun.com/javase/6/docs/api/javax/swing/JOptionPane.html>

Quote:

"Direct Use:
To create and use an JOptionPane directly, the standard pattern is
roughly as follows:

JOptionPane pane = new JOptionPane(arguments);
pane.setXxxx(...); // Configure
JDialog dialog = pane.createDialog(parentComponent, title);
dialog.show();
Object selectedValue = pane.getValue();
if(selectedValue == ...."


See how much easier that is than your huge property change listener?
Use pane.createDialog(), I don't think stuffing the JOptionPane into a
JFrame will work very well. At least, the above DOES work, so just use
it. If you want a JFrame, make it out of regular components like I did.

Other than that, we do the same thing. My example just prints the
string the user enters in the GUI to the screen, and your's does too.

Don't forget that if you need to do something beside print, you'll need
to synchronize code running on the EDT with the rest of the program.
This is the reverse of the problem we've been talking about so far.
We've been talking about the need to start in the main thread and get
over to the EDT with invokeLater. Now we're inside an ActionListener
(in my code; I think the property change listener works the same) and
we need to get off the EDT and synchronize with all the objects in the
program that are NOT GUI objects.

Try the SwingWorker class for the this:

<http://java.sun.com/docs/books/tutorial/uiswing/concurrency/worker.html>

Lew

unread,
Jul 9, 2009, 10:14:42 PM7/9/09
to
jrobinss wrote:
>> BTW, I'm aware that enums should be upper case, only here I use them
>> directly as commands, and I'd rather the "usage" command provided
>> lower-case commands to the user.

markspace wrote:
> enum Commands { START, STOP }
>
> String name = START.toString().toLowerCase();

Another standard solution is to use a private display String member - a bit
wordy but you can set up your 'enum' template in Eclipse or NetBeans to put up
the boilerplate:

public enum Command
{
START( "start" ),
STOP( "stop" );

private final String handle;

private Command( String d )
{
this.handle = d;
}

@Override public String toString()
{
return this.handle;
}
}

--
Lew

jrobinss

unread,
Jul 10, 2009, 3:24:13 AM7/10/09
to

So, I'm very sorry for wasting everyone's time. As I had hinted in my
reply to Simon, the problem was launching the program from Eclipse.

After receiving several solutions (I just tested Mark Space's, thank
you Mark), I was intrigued that they all had the same result as mine,
regarding hanging and GUI not showing up. None of them worked!

I just tested them all from command-line, and they work fine...
including mine. :-/

So I guess the question is now, why doesn't it work as well executing
from inside Eclipse? I suppose Eclipse is using the EDT too. So is the
lesson learned, never test graphical programs from Eclipse??

Is there any special way to launch programs that require EDT from
Eclipse?

As for me, I'll start cleaning up my code now and move on to my next
problem. Thanks for all the tips.

--
JRobinss

jrobinss

unread,
Jul 10, 2009, 3:25:11 AM7/10/09
to

markspace wrote:
> enum Commands { START, STOP }
>
> String name = START.toString().toLowerCase();

or this:
enum MyCommand {
START,
STOP;

@Override
public String toString() {
return super.toString().toLowerCase();
}
}

Lew wrote:
>
> Another standard solution is to use a private display String member - a
> bit wordy but you can set up your 'enum' template in Eclipse or NetBeans
> to put up the boilerplate:
>
> public enum Command
> {
> START( "start" ),
> STOP( "stop" );

That's what I usually do. Neatly separates HMI from code. In this case
its adds more boilerplate than that, because the user command input is
also not recognized, so I would have to compare the user input to
command.toString() for all commands.

So what I was doing really was a shortcut.

However, in the SSCCE I could have done like all here, and gone with
"start".equalsIgnoreCase(userInput); with no enum at all.

--
JRobinss

jrobinss

unread,
Jul 10, 2009, 3:25:58 AM7/10/09
to

markspace wrote:
> I haven't read your SSCCE yet, but I thought I'd show you my solution. I
> notice you have one extra niggle that was mentioned earlier (the
> property change listener).

Many thanks.

I just changed this:
> private static void stopGui()
> {
if (jf == null) return;


> jf.setVisible( false );
> jf.dispose();
> jf = null;
> }

to avoid a NPE.
(yes, I enter a lot of commands, which leads me to these NPEs, not to
test your solution, but to see what it takes to display a GUI)

See my other post to get to the real problem.
--
JRobinss

jrobinss

unread,
Jul 10, 2009, 3:33:49 AM7/10/09
to

markspace wrote:
> Yes. Your property change listener is just bizarre. You need help with
> Swing, not multi-threading. Read the docs on JOptionPane, since you're
> trying to use one:

In fact my property change listener is copy pasted from a sample found
on the web. The reason why is that to post an SSCCE, or approaching, I
needed something that compiles and runs, and it's been a long time
since last time I've developed GUIs. And it has no bearing on the
issue.

As I said, these comments are welcome, even though they are not linked
to the problem at hand.

> <http://java.sun.com/javase/6/docs/api/javax/swing/JOptionPane.html>
[...]


> JDialog dialog = pane.createDialog(parentComponent, title);

[minor rant]
BTW, I'm always frustrated when reading up on GUI subjects at the
number of times there are code extracts with some kind of magical
"parentComponent" or "frame" or "panel". Here you are, Java GUI
beginner, trying to understand how to create stuff, and you think you
have a code sample that works, you copy paste it, and voilà, here's a
compilation error, parentComponent not known.
Ok, I understand the logic behind it, but it's still frustrating.

--
JRobinss

RedGrittyBrick

unread,
Jul 10, 2009, 9:24:47 AM7/10/09
to

jrobinss wrote:

> So I guess the question is now, why doesn't it work as well executing
> from inside Eclipse? I suppose Eclipse is using the EDT too. So is the
> lesson learned, never test graphical programs from Eclipse??

I always test my Swing programs from within Eclipse.


> Is there any special way to launch programs that require EDT from
> Eclipse?

With the default configuration of Eclipse, Clicking the "Run" button
works for me.


If I had your problem I'd check the "Run", "Run..." Configuration. Then
the Project Build Path. I'd also use the debugger to step through a
Swing "Hello World". If that was taking too long I'd uninstall Eclipse
and reinstall the latest version.

--
RGB

Lew

unread,
Jul 10, 2009, 9:46:04 AM7/10/09
to
Lew wrote:
>> Another standard solution is to use a private display String member - a
>> bit wordy but you can set up your 'enum' template in Eclipse or NetBeans
>> to put up the boilerplate:
>>
>> public enum Command
>> {
>> START( "start" ),
>> STOP( "stop" );

jrobinss wrote:
> That's what I usually do. Neatly separates HMI from code. In this case
> its adds more boilerplate than that, because the user command input is
> also not recognized, so I would have to compare the user input to
> command.toString() for all commands.

I usually include a 'public static E fromString( String lu )' method for an
enum E that looks up and returns the E instance whose 'toString()' value
equals 'lu', or 'null' if none found.

Sometimes I use 'equalsIgnoreCase()' as the comparison for 'fromString()'.

--
Lew

Simon

unread,
Jul 10, 2009, 12:04:37 PM7/10/09
to
> BTW, to the best of my knowledge the Thread:stop() method is
> deprecated, and should be replaced with interrupt().

Did you test whether that works? The docs say that this only helps if
the thread is blocked by IO of an interruptible channel. If that applies
to System.in, then this works.

> I ran your code, and saw only the CLI, no GUI. When I typed something
> in, it obviously triggered the EDT, because I ran into an NPE, so I
> changed your line
> if (dialog.isVisible()) {
> dialog.setVisible(false);
> }
> to
> if (dialog != null && dialog.isVisible()) {
> (the dialog wasn't yet created)
>
> With this corrected, upon startup I only see the CLI, and when I type
> in some input, the program exits. (same as Daniel's code in fact)

Well, admittedly, it is not very nice that each thread assumes that the
other one has already started, but its only a demo. Wait a few seconds
and give the Dialog a chance to pop up.

The dialog is very small and has no button, it gets lost easily. You can
"confirm" only by closing it.

At least for me, it also works outside eclipse.

Let me know if you find the dialog :-)

Cheers,
Simon


markspace

unread,
Jul 10, 2009, 12:09:16 PM7/10/09
to
jrobinss wrote:

> to avoid a NPE.

Yes, if you enter "stop" twice in a row, you'll get an NPE. Also, if
you type "start" twice in a row, the previous window will be replaced
with a new one, and you can't close or dispose the old window anymore.

The example was to show starting and stopping a GUI from another thread,
not bomb proof window handling. Depending on your requirements, you
might want to do nothing if a "start" command is issued and a window
already exists. Or you might want to make a new window, and save both
references. Or you might issue an error message. It all depends.


Re your comment from the other post:

>> JDialog dialog = pane.createDialog(parentComponent, title);
>
> [minor rant]
> BTW, I'm always frustrated when reading up on GUI subjects at the
> number of times there are code extracts with some kind of magical
> "parentComponent" or "frame" or "panel". Here you are, Java GUI


If you want to know what createDialog() does, read the docs! You had a
link to the docs right in that post. This is a little bit silly,
really. "parentComponent" is a variable, the fact that it was
undeclared and used in an example should be pretty obvious if you know
any Java syntax.

JComponent parentComponent = null;
panel.createDialog( parentComponent, title );

This really seems like you just don't know Java very well.
Multi-threading can be tricky for anyone, but variables and method calls
should be one of the first things you learn. If you're new, no worries,
we all have to start somewhere, but I think you might benefit from some
actual study of the language itself. Java Passion is Sun's free web
site where you can get free online courses in Java:

http://www.javapassion.com/javaintro/

I went through this course myself. Even though much of it was remedial,
the organization and exercises helped cement my understand of the basic
language, and made it much easier to progress to more advanced Java
topics. Just a thought.


Lastly, I'd be curious to know where you got that code example from.
It's probably doing something different that you thought, but I'd like
to check it out if you don't mind posting a link.

John B. Matthews

unread,
Jul 10, 2009, 5:41:43 PM7/10/09
to
In article <h356hm$f7t$1...@news.eternal-september.org>,
markspace <nos...@nowhere.com> wrote:

[...]


> I thought I'd show you my solution.

[...]

Your excellent example prompted me to update my GUI launcher that uses
exec() to run programs in a separate JVM:

<code>
package gui;

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

/** @author John B. Matthews */
public class Launcher extends JPanel implements Runnable {

private final JButton launch = new JButton();
private final JLabel label = new JLabel();
ProcessBuilder pb = new ProcessBuilder(
"java", "-cp", "build/classes", "gui.DialogTest");
private volatile Process proc;

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
createGUI();
}
});
}

private static void createGUI() {
final JFrame frame = new JFrame();
frame.setLayout(new GridLayout(0, 1));
frame.add(new Launcher());
frame.add(new Launcher());
frame.add(new Launcher());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}

public Launcher() {
this.setPreferredSize(new Dimension(225, 50));
launch.addActionListener(new ActionListener() {
//@Override
public void actionPerformed(ActionEvent e) {
if (proc == null) {
launch.setText("Terminate");
label.setText("Status: run");
new Thread(Launcher.this).start();
} else {
proc.destroy();
reset();
}
}
});
this.add(launch);
this.add(label);
reset();
}

//@Override
public void run() {
try {
proc = pb.start();
int status = proc.waitFor();
} catch (IOException ex) {
ex.printStackTrace();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
reset();
}
});
}

private void reset() {
proc = null;
launch.setText("Launch");
label.setText("Status: idle");
}
}

class DialogTest {

public static void main(String... args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JOptionPane.showMessageDialog(null, "Running",
"Test", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
});
}
}
</code>

--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>

Daniel Pitts

unread,
Jul 11, 2009, 3:26:58 PM7/11/09
to
Yes, for me it produces an "Okay" dialog box, and waits for the user to
either type something on the console, or press the Okay box.

This was meant to demonstrate that the EDT is started separately from
the Main thread, and it happens automatically with the first call to
EventQueue.invoke[Later|AndWait]

jrobinss

unread,
Jul 20, 2009, 12:27:39 PM7/20/09
to

RedGrittyBrick answered me:

> > Is there any special way to launch programs that require EDT from
> > Eclipse?
>
> With the default configuration of Eclipse, Clicking the "Run" button
> works for me.
>
> If I had your problem I'd check the "Run", "Run..." Configuration. Then
> the Project Build Path. I'd also use the debugger to step through a
> Swing "Hello World". If that was taking too long I'd uninstall Eclipse
> and reinstall the latest version.

Many thanks for these practical suggestions. I'll jump to it ASAP.
(I'm in the midst of several things at the moment)

--
JRobinss

jrobinss

unread,
Jul 20, 2009, 12:28:49 PM7/20/09
to

Simon answered me:

> Well, admittedly, it is not very nice that each thread assumes that the
> other one has already started, but its only a demo. Wait a few seconds
> and give the Dialog a chance to pop up.
>
> The dialog is very small and has no button, it gets lost easily. You can
> "confirm" only by closing it.
>
> At least for me, it also works outside eclipse.
>
> Let me know if you find the dialog :-)

No problem, as I said elsewhere, I saw the dialog, but only when
executing outside Eclipse.

--
JRobinss

jrobinss

unread,
Jul 20, 2009, 12:47:27 PM7/20/09
to

markspace answered me:

>
> The example was to show starting and stopping a GUI from another thread,
> not bomb proof window handling.

I had already written:


> (yes, I enter a lot of commands, which leads me to these NPEs, not to
> test your solution, but to see what it takes to display a GUI)

We're basically saying the same thing. I simply thought it polite to
mention the minor modification I did to your code, I wasn't
criticizing it for being unfit for production. :-)

> Re your comment from the other post:
>
>  >>       JDialog dialog = pane.createDialog(parentComponent, title);
>  >
>  > [minor rant]
>  > BTW, I'm always frustrated when reading up on GUI subjects at the
>  > number of times there are code extracts with some kind of magical
>  > "parentComponent" or "frame" or "panel". Here you are, Java GUI
>
> If you want to know what createDialog() does, read the docs!   You had a
> link to the docs right in that post.  This is a little bit silly,
> really.  "parentComponent" is a variable, the fact that it was
> undeclared and used in an example should be pretty obvious if you know
> any Java syntax.

Of course I read the docs. Of course it's a bit silly, it's a rant. Of
course parentComponent is a variable, and declared and initialized
somewhere. Of course I know some Java syntax.

Thanks for the advice you went on to provide about learning, but
although I'm certainly no guru, I think I may be just at the level
above learning about variables and method calls. At least
syntactically.
(for the record, I once met an intern in IT who actually did not know
about variables... hard to believe, I know, but there it was)

What was the point of my rant? Same point as many postings in NGs: on
one hand you're talking to people, but on the other hand you're also
simply creating content (accessible through GG for example), and on
the third hand (!) you're generating traffic on a public billboard. It
may of some comfort to some Java beginner or lurker to know that
they're not alone in wishing for an example that would also include
declaration and initialization of stuff such as parentComponent. It
may also trigger, who knows, interesting discussions, remarks or
whatnot. Or not.

What it doesn't mean is that I, for one, stop short when I read such
extracts and freak out because the variable is missing. :-)

> Lastly, I'd be curious to know where you got that code example from.
> It's probably doing something different that you thought, but I'd like
> to check it out if you don't mind posting a link.

Sure
http://java.sun.com/docs/books/tutorial/uiswing/examples/components/DialogDemoProject/src/components/CustomDialog.java

--
JRobinss

markspace

unread,
Jul 20, 2009, 4:36:20 PM7/20/09
to
jrobinss wrote:

> We're basically saying the same thing. I simply thought it polite to
> mention the minor modification I did to your code, I wasn't
> criticizing it for being unfit for production. :-)


No worries. I wasn't offended; I was just agreeing that my code is
unfit for production. Just something I whipped up quickly as an example.


> What was the point of my rant? Same point as many postings in NGs: on
> one hand you're talking to people, but on the other hand you're also
> simply creating content (accessible through GG for example), and on


My answer to your rant was aimed at the same audience. We get a lot of
folks on cljp who are first year students, hobbyists or new to Java
after modest experience with another language.

Most of those have the same problem you did, and in fact the same
problem I did when I first tried to learn Java. Sun's tutorial is lousy
and the API docs are impenetrable.

What worked for me was the link I posted. Even though that course is
remedial (it was for me), the fact that it forces you to sit down and
write code forced me to learn the language and small parts of the API in
an orderly fashion. After that, learning the rest was much easier.
After a few small projects on my own and I could understand the API docs
and follow code examples in the tutorial.

Everyone tries to use the tutorial and dive right in and learn in great
big gulps. That didn't work for me. Carefully chewing my food in
smaller bites was the answer.


> http://java.sun.com/docs/books/tutorial/uiswing/examples/components/DialogDemoProject/src/components/CustomDialog.java

That's from this page:

<http://java.sun.com/docs/books/tutorial/uiswing/components/dialog.html>

It's a custom dialog. The prefab dialogs are much easier to use. Even
making dialogs for myself for my own projects, I didn't use anything as
fancy as that custom code. Normally I just made my own panels and
dropped them in a plain JDialog.

One of the advantages of that course I posted earlier is that we used
the simple static methods in JOptionPane a lot to display simple
messages. Once you get used to doing it that way, you look at the big
example of custom code you posted and go "Pfft, why bother?" and just do
it the easy way.

jrobinss

unread,
Jul 21, 2009, 5:51:47 AM7/21/09
to
markspace answered me:

>
> One of the advantages of that course I posted earlier is that we used
> the simple static methods in JOptionPane a lot to display simple
> messages.  Once you get used to doing it that way, you look at the big
> example of custom code you posted and go "Pfft, why bother?" and just do
> it the easy way.

I completely agree, I started off with JOptionPane's static utilities.
It's really a great relief from managing dialogs. :-)

However, there's no way in my case to use these methods and then hide
or destroy the dialog upon the command "stop". Is there?

I don't have any pointer to any object such as dialog for hiding, and
stopping or interrupting the thread in which I run the static method
doesn't work either.

So that the remaining option is to create my panel, keep a pointer to
it (instance attribute), and hide or destroy it upon "stop".

--
JRobinss

jrobinss

unread,
Jul 21, 2009, 6:02:21 AM7/21/09
to

I'm answering myself, because it's fairly easy to show/hide while
still using JOptionPane's static methods.

My new code, without any callbacks: (this is not SSCCE, it's just an
extract)
[...]
private void onInput(String input) {
System.out.println("got input=" + input);
}

private Component dialogParent_ = new JFrame();

private Runnable showDialog_ = new Runnable() {
public void run() {
String input = JOptionPane.showInputDialog(dialogParent_,
"Please enter input");
onInput(input);
}
};

private Runnable hideDialog_ = new Runnable() {
public void run() {
dialogParent_.setVisible(false);
}
};

public void processCommand(MyCommand cmd, List<String> args) {
if (cmd == MyCommand.start) {
SwingUtilities.invokeLater(showDialog_);
} else {
SwingUtilities.invokeLater(hideDialog_);
}
}
}

--
JRobinss

0 new messages