7

I'm new to java coming from C# so I'm not familiar with java best practices.

I have a main class that opens a JFrame to get several input strings from a user. When the user clicks submit the GUI should close and the main class continue processing using the input.

This is the main class:
public class Main {
    FInput fInput;

    public void main(String[] args) {
        if(args.length==0)
        {
            fInput = new FInput();
            fInput.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            fInput.pack();
            fInput.setVisible(true);
        }
    else
        startProcess(args);
    }

    public void startProcess(String[] args) {
// Do stuff
}

The main class will use this frame to get input from the user:

public class FInput extends JFrame{
    private JTextField txtSourceDirectory;
    private JTextField txtTargetDirectory;
    private JTextField txtDefectNumber;
    private JTextField txtSliceTokens;
    private JButton btnStart;

    public FInput() {
        // Initialize text fields and button
        JButton.addActionListener(something);
    }
}

In all the examples I could find, the listener would be a FMain itself. However in this case I want Main to listen and use the input in method startProcess.

Would having Main implement ActionListener, and passing it to FMain constructor is the way to go?
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Yoav
  • 2,077
  • 6
  • 27
  • 48

3 Answers3

5

Yes, that is the right idea. You must do two things in order to be able to do that, though:

  1. Put this at the beginning of the FInput class:

    Main m = new Main(this);
    
  2. Then, put these lines somewhere in the Main class...

    FInput gui;
    
    public Main(FInput in) { gui = in; }
    

Now you can refer to any component in the FInput class from the Main class by doing something like this.

gui.someComponent ...

To set up listeners just write someComponent.addItemListener(m); or something of the sort.

Hope this helps!


@Yoav In response to your latest comment...

You don't have to separate the listening class from the GUI class; you can combine the two into one class...

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Main extends JFrame implements ActionListener {

    private JTextField txtSourceDirectory;
    private JTextField txtTargetDirectory;
    private JTextField txtDefectNumber;
    private JTextField txtSliceTokens;
    private JButton btnStart;

    public Main() {
        txtSourceDirectory = new JTextField(40); //change this to the amount of characters you need
        txtTargetDirectory = new JTextField(40);
        txtDefectNumber = new JTextField(40);
        txtSliceTokens = new JTextField(40);
        btnStart = new JButton("Start");
        add(txtSourceDirectory);
        add(txtTargetDirectory);
        add(txtDefectNumber);
        add(txtSliceTokens);
        add(btnStart);
        btnStart.addActionListener(this);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }

    public void actionPerformed(ActionEvent event) {
        //do stuff
    }

    static void startProcess(String[] ARGS) {
        //do stuff
    }

    public static void main(String[] args) {
        if (args.length == 0) {
            Main frame = new Main();
        } else {
            startProcess(args);
        }
    }
}
fireshadow52
  • 6,298
  • 2
  • 30
  • 46
  • This means that Main is launched from FInput. Since I don't necessarily need to show FInput (parameters may come externally through args) then this is not a good solution. – Yoav Sep 18 '11 at 14:23
  • @Yoav I'm confused. *Since I don't necessarily need to show FInput (parameters may come exterally through args) then this is not a good solution.* If you aren't showing the window, then there is no reason to have listeners at all. – fireshadow52 Sep 18 '11 at 15:34
  • The app may display the window or not. If it does then the listeners are needed. In any case my point was that I need Main to be the entry class which will invoke FInput and possibly other windows. – Yoav Sep 18 '11 at 19:40
2

First main method in java always must be public static void. Below is example how this can be done.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

/**
 * Main class is frame but also implements ActionListener interface.
 */
public class Main extends JFrame implements ActionListener {
    private JButton btnStart;
    private static Main frame;

    public Main() {
        JPanel panel = new JPanel();
        btnStart = new JButton("Press me");

        // Add action listener. Listener could be any class that implements
        // ActionListener
        btnStart.addActionListener(this);

        // This means add button btnStart to panel
        panel.add(btnStart);

        // This means add panel to frame
        this.add(panel);
    }

    // main method in java always must be public, static and void. You forgot to
    // put static.
    public static void main(String[] args) {
        if (args.length == 0) {
            frame = new Main();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setVisible(true);
        } else
            frame.startProcess(args);
    }

    public void startProcess(String[] args) {
        // TODO
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        // Here you put your code that is executed every time you press button.
        // For example you just want to show message.
        JOptionPane.showMessageDialog(this, "You pressed Button.");

    }
}

But it is much better to have special class. For example:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JOptionPane;


    public class ButtonListener implements ActionListener {
        JFrame parent;

        public ButtonListener(JFrame parent) {
            this.parent = parent;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            JOptionPane.showMessageDialog(parent, "You pressed Button");
        }

    }

And in the main class you just add action listener to button:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

/**
 * Main class is frame but also implements ActionListener interface.
 */
public class Main extends JFrame {
    private JButton btnStart;
    private static Main frame;

    public Main() {
        JPanel panel = new JPanel();
        btnStart = new JButton("Press me");


        ButtonListener listener = new ButtonListener(this);
        // Add action listener. Listener could be any class that implements
        // ActionListener
        btnStart.addActionListener(listener);

        // This means add button btnStart to panel
        panel.add(btnStart);

        // This means add panel to frame
        this.add(panel);
    }

    // main method in java always must be public, static and void. You forgot to
    // put static.
    public static void main(String[] args) {
        if (args.length == 0) {
            frame = new Main();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setVisible(true);
        } else
            frame.startProcess(args);
    }

    public void startProcess(String[] args) {
        // TODO
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
Иван Бишевац
  • 13,811
  • 21
  • 66
  • 93
  • If I understand correctly, you've made one class out of my 2 classes. You use the static methods to run the application, and open an instance to present to the user. How does this work if I need to open another different Frame from MAIN? Doesn't java support having one class opening and closing Frames as needed? – Yoav Sep 18 '11 at 13:30
  • @Yoav, yes I made one class from your 2 classes. I just told that this could be done on this way. Problem with this approach is what to do if you have more that one button that you want to attach listener to. For that purpose inside actionPerformed you must check which button is pressed and according to that do some acction. For example if you have 2 buttons each one should change background color of frame (for exmaple red and blue) then you have to do check if red button is pressed or blue. Better approach is to have two different listeners for every button as I showed in post. – Иван Бишевац Sep 18 '11 at 20:48
  • @Yoav, I've just saw comment that you want to have Main class that is entry point for your application. You confused me with JFrame class. If it is so, then just write Main class and put into this method "public static void main(String[] args)" and then put into it everything you want for your application (for example show frame). – Иван Бишевац Sep 18 '11 at 20:53
2

Also consider using JOptionPane, shown here, in your Main class. You can customize the appearance, including button text, as shown in How to Make Dialogs.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • It seems that while JOptionPane can be customized, its not 'free form'. I specifically detailed the controls on FInput to show that I need to take 4 strings from the user, 2 of them are directories which he will select through DirectoryDialog. I don't think I can customize JOptionPane to do that. – Yoav Sep 18 '11 at 13:28
  • In order to select paths interactively, I'd use [`JFileChooser`](http://download.oracle.com/javase/tutorial/uiswing/components/filechooser.html) in a `JFrame`. You might edit your question to show this new requirement. – trashgod Sep 18 '11 at 19:49