-1

I am working on this application in swing .It is actually a voice controlled thingy...I give voice commands and some action is performed.But the thing is that once it is deployed, it is on an infinite while loop, it continuously searches for voice( which it should..imagine the jarvis of iron man movie) .. but this while loop freezes up my gui.I can not update it.can not hide panels , can not play sound.

swing worker and swing utilities shouldn;t help me because they check for the code after certain period of time while i need real time voice recognition..

So what can be done ? Can i make my gui interact with another java program? Like the java prog will do the voice recognition and pass on the reply to the gui?

Here is the code sketch

class{
    main(){
    new class()
}

class(){
    frames + content pane initialized
    mousePresssed()
    {
        ///the while loop starts here and looks for voice commands..any gui update code doesnt work here..while it detects the voice fine..continuously.

    }
}
aaaaaaa
  • 13
  • 1
  • 3
  • while (portId == null && portEnum.hasMoreElements())...you mean while portId != null? – ha9u63a7 Nov 22 '14 at 12:47
  • 1
    1) Words typed in all lower case are hard to read, like trying to listen to someone who is mumbling. Please use an upper case letter at the start of sentences, for the word I, and proper names like `ArrayList` or Oracle. 2) For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete Verifiable Example) or [SSCCE](http://www.sscce.org/) (Short, Self Contained, Correct Example). 3) One way to get images for an example, is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). – Andrew Thompson Nov 22 '14 at 12:53
  • umm.no..this part of the code is correct..it is the while loop that is giving me issues @hagubear – aaaaaaa Nov 22 '14 at 12:54
  • 1
    .. 4) Don't block the EDT (Event Dispatch Thread). The GUI will 'freeze' when that happens. See [Concurrency in Swing](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/) for details and the fix. – Andrew Thompson Nov 22 '14 at 12:54
  • Tip: Add @hagubear (or whoever, the `@` is important) to notify the person of a new comment. – Andrew Thompson Nov 22 '14 at 12:54
  • 3
    *"swing worker and swing utilities shouldn;t help me because they check for the code after certain period of time.."* The 'non-real time' might be only a handful of milliseconds, which would not even be noticed by the user. – Andrew Thompson Nov 22 '14 at 12:56

1 Answers1

2

Basically, you need to have your infinite loop run in another Thread than the EDT. And whenever you want to update your GUI, do it on the EDT, using a SwingUtilities.invokeLater call. The delay for calling the update of the GUI in invokeLater will be barely noticeable. SwingUtilities.invokeLater is not based on a polling mechanism. The only thing it does is transform a Runnable into an event which is then posted on the EDT. The EDT will then execute your Runnable as soon as possible, so most of the time, instantly.

Now for the pattern on how to communicate between your Thread and your GUI, you can simply use the "Observer" pattern. Your voice recognition thread is somehow a model and your UI simply listens for changes on that model. Whenever the model changes, the UI updates itself.

I made a dummy example of such thing. For the "Observer" pattern, I used the PropertyChangeSupport for it. For the model, I created a dummy thread which generates random "command" every once in a while and the UI updates itself accordingly:

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class TestThreadingAndGUI implements PropertyChangeListener {

    private JFrame frame;

    private JLabel label;

    private DummyRunnable runnable;

    public static class DummyRunnable implements Runnable {

        private PropertyChangeSupport pcs = new PropertyChangeSupport(this);

        private String command;

        public void addPropertyChangeListener(PropertyChangeListener listener) {
            pcs.addPropertyChangeListener(listener);
        }

        @Override
        public void run() {
            Random random = new Random();
            while (true) {
                try {
                    Thread.sleep(((random.nextInt(3)) + 1) * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < 15; i++) {
                    sb.append((char) ('a' + random.nextInt(26)));
                }
                setCommand(sb.toString());
            }
        }

        public String getCommand() {
            return command;
        }

        private void setCommand(String command) {
            String old = this.command;
            this.command = command;
            pcs.firePropertyChange("command", old, command);
        }
    }

    protected void initUI(DummyRunnable runnable) {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        label = new JLabel();
        label.setHorizontalAlignment(JLabel.CENTER);
        frame.add(label);
        frame.setSize(600, 600);
        frame.setVisible(true);
        this.runnable = runnable;
        runnable.addPropertyChangeListener(this);
    }

    private void executeCommand() {
        label.setText(runnable.getCommand());
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals("command")) {
            // Received new command (outside EDT)
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    // Updating GUI inside EDT
                    executeCommand();
                }
            });
        }
    }

    public static void main(String[] args) {
        final DummyRunnable runnable = new DummyRunnable();
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                TestThreadingAndGUI testThreadingAndGUI = new TestThreadingAndGUI();
                testThreadingAndGUI.initUI(runnable);

            }
        });
        new Thread(runnable).start();
    }

}
Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
  • I see the basic workflow.But i am about to use the `observer` interface for the first time.And my head is throbbing too much to go into its detailed explanation..So if were to replace my voice receiving code inside that while loop and my gui code inside that `initUI`..and leave everything like it is..exactly like it is..it will run? – aaaaaaa Nov 22 '14 at 14:09
  • @aaaaaaa No reason for it not to work. The only "trick" is when you receive a notification from your voice recognition to your UI, you need to put the code that updates the UI in an `invokeLater` call (to ensure the UI is updated on the EDT) – Guillaume Polet Nov 22 '14 at 17:17