How can I make changes to a JFrame GUI outside of the runnable in main?

I'm currently learning Java GUI, and I'm making a Java program where you can edit shapes with text within a GUI. I've created a JFrame which contains a custom MyCanvas object and a text field. The idea is that the MyCanvas object has a MouseListener and will contain shapes, these shapes when clicked will enable the text field in the GUI so that the user can enter a new message to be displayed in the shape. However, I'm running the GUI with a Runnable inside the GUI class's main method, and I can't enable the text box from the MyCanvas class since it's outside of the Runnable. Could anyone help me how to make this possible?

Here's the basic structure of my code (pseudocode):

// GUI class
public class GUI extends JFrame implements ActionListener {
    private static MyCanvas c = new MyCanvas(); // canvas
    private static TextField editor = new TextField(); // text field

    public static void init() {
        // initialize GUI elements and disable text box
    }

    public static void enableTextBox() {
        // enables the text field
    }

    public static void disableTextBox() {
        // disables the text field
    }

    public void actionPerformed(ActionEvent e) {
        // get message from text box
    }

    public static void main(String[] args) {
        // Run the GUI frame
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                init();
                /* Add a RectTextBox (a Rectangle object with text inside,
                 * class defined elsewhere)
                 */
                c.addShape(new RectTextBox("Hello World");
            }
        }
    }
}

// Canvas class
class MyCanvas extends JPanel implements MouseListener {
    // ArrayList of blocks on the canvas
    ArrayList<RectTextBox> blocks = new ArrayList<RectTextBox>();

    // Ctor
    public MyCanvas() {
        // Initialize canvas and add MouseListener to this canvas
    }

    public void paintComponent(Graphics g) {
        // Paints all blocks on canvas
    }

    public void addShape(RectTextBox b) {
        // Adds the text box b to the blocks ArrayList
    }

    public void mouseClicked(MouseEvent e) {
        // check if any blocks from the ArrayList is clicked

        /* enables the text field from GUI to enter messages, then set the
         * message entered to the block
         */
    }
}

1 answer

  • answered 2018-07-12 00:36 MadProgrammer

    So, you're off to a good start. MyCanvas has functionality which can be called by other classes, for example, addShape...

    // Canvas class
    class MyCanvas extends JPanel implements MouseListener {
        // ArrayList of blocks on the canvas
    
        ArrayList<RectTextBox> blocks = new ArrayList<RectTextBox>();
    
        // Ctor
        public MyCanvas() {
            // Initialize canvas and add MouseListener to this canvas
        }
    
        public void paintComponent(Graphics g) {
            // Paints all blocks on canvas
        }
    
        public void addShape(RectTextBox b) {
            // Adds the text box b to the blocks ArrayList
        }
    
        public void mouseClicked(MouseEvent e) {
            // check if any blocks from the ArrayList is clicked
    
            /* enables the text field from GUI to enter messages, then set the
         * message entered to the block
             */
        }
    }
    

    Next, you need to pass a reference of MyCanvas to those classes which want to perform some operation on it, as a "really" basic example...

    public class EditorPane extends JPanel {
        private MyCanvas canvas;
    
        public EditorPane(MyCanvas canvas) {
            this.canvas = canvas;
            // Build UI as required
        }
    }
    

    Then when EditorPane wants to make a change, it can use canvas to call the methods it needs to.

    Then, we you build your UI, you would make an instance of MyCanvas, pass that reference to both the EditorPane and add it to the UI, for example...

    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            MyCanvas canvas = new MyCanvas();
            EditorPane editor = new EditorPane(canvas);
    
            JFrame frame = new JFrame();
            frame.add(canvas);
            frame.add(editor, BorderLayout.SOUTH);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
    

    Now, personally, I'd fold much of this up into interface to prevent EditorPane from doing more to MyCanvas then it should, but that's a topic for another day ;)