0

I am experienced programmer, but never used Java until recently. I have a class that works by copying code from the internet(huzzah), and the Jframe runs in its own thread when I run the code below as its own thread when using the main() function.

But I have a problem. I want to use this Jframe as the interactive portion of another thread (as a private member of a implements Runnable class). AND I want them to interactive. The Jframe method actionPerformed needs to call the parent thread object's functions (I type a command, it does something) AND parent needs to call the .append() method to report the result to the Jframe. I can include a reference to the parent inside my Jframe, so I can call its methods.

So my problem is about designing this properly for thread synchronization. I am not sure how thread synchronization and the eventhandler interact, so as my thread can use the not threadsafe Jframe properly.

Where and how do I initialize the Jframe properly? (Specifically, am I supposed to use the EventQueue in some way?) Or am I missing something glaring and doing this the completely wrong way?

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.ActionMapUIResource;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

public class CmdPrompt3 extends JFrame {
    private static final String progname = "CmdPrompt <Monitor Game Client>";

    private JTextField input;
    private JTextArea history;
    private JPanel mainpanel;
    private JMenuBar greenMenuBar;
    private String lastCmd;
    private boolean unusedCmd;
    //public boolean defaultConstruct = true;

    public CmdPrompt3(int x, int y, String name) { //offset coordinates
        super("CmdPrompt3 <" + name + ">");
        lastCmd = "";
        unusedCmd = false;
        //defaultConstruct = false;

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create the menu bar.  Make it have a green background.
        greenMenuBar = new JMenuBar();
        greenMenuBar.setOpaque(true);
        greenMenuBar.setBackground(new Color(154, 165, 127));
        greenMenuBar.setPreferredSize(new Dimension(200, 20));
        this.setJMenuBar(greenMenuBar);

        mainpanel = new JPanel(new BorderLayout());
        mainpanel.setBorder(new EmptyBorder(2, 3, 2, 3));

        // adjust numbers for a bigger default area
        JTextArea history = new JTextArea(25, 40); //25 lines, 40 columns
        Font font = new Font(
                Font.MONOSPACED,
                Font.PLAIN,
                16); //font size 16
        //history.getFont().getSize()+4);
        mainpanel.setFont(font);
        history.setFont(font);
        mainpanel.add(new JScrollPane(history,
                JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));
        this.add(mainpanel);

        input = new JTextField(80);
        input.setFont(font);
        this.add(input, BorderLayout.SOUTH);

        ActionMap actionMap = new ActionMapUIResource();
        actionMap.put("enter", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String cmd = input.getText();

                //String sofar = history.getText ();
                history.append("\tinput box>>\t" + cmd + "\n");

                //DO IMPORTANT STUFF HERE
                //Set flags for retrieving commands
                lastCmd = cmd;
                unusedCmd = true;

                //clear input line
                input.setText("");
            }
        });
        InputMap keyMap = new ComponentInputMap(input);
        keyMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "enter");

        SwingUtilities.replaceUIActionMap(input, actionMap);
        SwingUtilities.replaceUIInputMap(input, JComponent.WHEN_IN_FOCUSED_WINDOW, keyMap);

        setLocation(x, y);
        this.pack();
        setVisible(true);
    }

    //owner thread writes history to window
    //TODO this doesn't work when Client calls the function
    //Apparently,
    public void append(String S) {
        history.append(S);
        return;
    }

    //owner thread gets last issued command, if any
    public String getUnusedCmd() {
        if (unusedCmd) {
            unusedCmd = false;
        } else {
            lastCmd = "";
        }
        return lastCmd;
    }

    public static void main(final String args[]) {
        Runnable runner = new Runnable() {
            public void run() {
                new CmdPrompt3(100, 100, "Basic Class Test");
            }
        };
        EventQueue.invokeLater(runner);
    }
}
Marv
  • 3,517
  • 2
  • 22
  • 47
BAMF4bacon
  • 523
  • 1
  • 7
  • 21
  • I don't understand what you mean when you say that "the Jframe runs in its own thread." Your example is almost completely single-threaded. It starts with a main thread, the main thread causes an Event Dispatch Thread (EDT) to be created when it calls `EventQueue.invokeLater(...)`, and then the main() thread dies, leaving the EDT as the only thread in your application. I'm not saying that any of that is a bad thing: The methods of a JPanel, like most Swing method, should only ever be called from the EDT anyway. – Solomon Slow Mar 16 '16 at 15:59
  • The point is I don't know enough about the terminology to ask the right question. I don't know about EDT's, apparently. so I will go read up on that. To try to clarify, when I make a "implements Runnable" class, I use .start() to start that thread. Here, I am starting the thread differently for the Jframe and I don't know how to do it from within another class that is a "implements runnable" class. – BAMF4bacon Mar 16 '16 at 16:36
  • https://docs.oracle.com/javase/tutorial/uiswing/concurrency/ – Solomon Slow Mar 16 '16 at 16:53
  • http://docs.oracle.com/javase/tutorial/essential/concurrency/ – Solomon Slow Mar 16 '16 at 16:54
  • *"and the Jframe runs in its own thread when I run the code below as its own thread when using the main() function"*, no, no it doesn't, or not entirely. The frame might be created within a different thread, but it will execute the majority of it's functionality within the context of the Event Dispatching Thread, Swing is single threaded AND not thread safe. See [Concurrency in Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) for more details – MadProgrammer Mar 16 '16 at 21:09
  • First of all, drop ALL the threading, it's the wrong approach and will lead you into nothing but trouble. Start by implementing a [Observer Pattern](http://www.oodesign.com/observer-pattern.html) when your second frame can register interest with the first so it can be notified of changes – MadProgrammer Mar 16 '16 at 21:11

0 Answers0