AlphaUserGuru
AlphaUserGuru

Reputation: 21

I have a issue with java threads and KeyEvents?

I need a bit of help with my program here. I have a blocking function waiting in my main thread for the user to click "Enter". Then, when the user hits enter, the keypressed event should fire, which will unblock the blocking function. However, when the program hits the blocking function, it simply freezes up and doesn't register the key pressed event.

So, my question is, is a event a runnable, which is added to a thread whenever the user clicks enter? If so, my code should have worked, right? If this is not the case, and each event is not a separate thread, could anyone enlighten me on how I should fix my problem here? my blocking function:

public String getInput() {
    synchronized(waitObject) {
        try {
            System.out.println("waiting");
            waitObject.wait(); // throws exception, cba to add it here
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    return(myString);
}

my keylistener code:

public void keyPressed(KeyEvent e) {
    System.out.println("key pressed");
    char c = e.getKeyChar();
    if (c == e.VK_ENTER) {
        System.out.println("Enter pressed");
        synchronized(waitObject) {
            waitObject.notifyAll();
        }
    }
}

and the function getting the input:

private String getCommand() {
    System.out.println("getting command");
    CommandField command = new CommandField((JFrame)(this));
    command.setPreferredSize(new Dimension(getWidth(), 30));
    m_panel.add(command, BorderLayout.NORTH);
    validate();
    command.requestFocus();
    System.out.println(command.getInput());

    return null;
}

And this function is called from another keylistener:

public class Listener implements KeyListener {
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_F2) {
            System.out.println(getCommand());
        }

    }
    public void keyReleased(KeyEvent e) {

    }
    public void keyTyped(KeyEvent e) {

    }
}

Upvotes: 2

Views: 681

Answers (2)

trashgod
trashgod

Reputation: 205875

Starting with ImageApp, I added the following key binding in the constructor. It will show() the popup menu when pressing the Enter key. You can change the arbitrary location to suit your usage.

this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "showPopup");
this.getActionMap().put("showPopup", new AbstractAction("showPopup") {

    @Override
    public void actionPerformed(ActionEvent e) {
        popup.show(ImageApp.this, 42, 42);
    }
});

Addendum: To bring up a modal input dialog, so something like this:

this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "dialog");
this.getActionMap().put("dialog", new AbstractAction("dialog") {

    @Override
    public void actionPerformed(ActionEvent e) {
        String value = JOptionPane.showInputDialog("What?");
        System.out.println(value);
    }
});

Upvotes: 2

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

OK, getCommand() is called on the event thread which then calls getInput() on the same thread, which then calls Object#wait() on the event thread, so yes you are tying up the event thread and effectively freezing your program.

None of this is needed, and a much easier fix is possible if you code using the concepts of event-driven programming. You don't want to call wait() in a Swing GUI and in your situation don't need to call it, but rather you want to change how your program responds to input based on its state. If you tell us more on the exact behavior you're trying to elicit, we can probably help you find a much better solution.

Edit
Consider using a JOptionPane or a modal JDialog for displaying a "blocking" window that stops the main program until the dialog has been dealt with.

Upvotes: 2

Related Questions