1

I currently have a simple Java AWT/Swing code that creates a simple GUI that takes multiple String User-input and stores and displays it in the Intellij terminal like so:

import javax.swing.*;
import java.awt.*;        // Using AWT container and component classes
import java.awt.event.*;  // Using AWT event classes and listener interfaces
import java.util.ArrayList;
import java.util.Scanner;

// An AWT program inherits from the top-level container java.awt.Frame
public class DateTime extends JFrame implements ActionListener {
    private Label lblCount, lblsource, lbldate1, lbldate2;    // Declare a Label component
    private JTextField tfCount, date1, date2; // Declare a TextField component
    private Button btnCount;   // Declare a Button component
    private int count = 0;     // Counter's value
    static String type = null;
    private JCheckBox source1, source2;
    boolean a = false;
    boolean b= false;
    static String source, datedefined1, datedefined2;
    ArrayList<String> texts = new ArrayList<String>();
    // Constructor to setup GUI components and event handlers
    public DateTime () {
        setLayout(new FlowLayout());
        // "super" Frame, which is a Container, sets its layout to FlowLayout to arrange
        // the components from left-to-right, and flow to next row from top-to-bottom.

        lblCount = new Label("Enter the type of report you want generated; Hourly/ Daily/ Weekly/ EventComparison:");  // construct the Label component
        add(lblCount);                    // "super" Frame container adds Label component

        tfCount = new JTextField("", 20); // construct the TextField component
        tfCount.setEditable(true);       // set to read-only
                          // "super" Frame container adds TextField component

        tfCount.setBounds(10,50,200,40);
        add(tfCount);
        tfCount.addActionListener(this);

        lblsource = new Label("Now choose the source type:");
        add(lblsource);
        source1 = new JCheckBox("Drivetest", a);
        source1.setBounds(10,100,50,30);
        add(source1);
        source2 = new JCheckBox("Ookla Dump",b);
        add(source2);
        source1.addActionListener(this);
        source2.addActionListener(this);


            lbldate1 = new Label("Please enter the Start DATETIME of the chosen duration(YYYY-MM-DD HH:MM:SS) :");
            add(lbldate1);
            date1 = new JTextField("", 30); // construct the TextField component
            date1.setEditable(true);
            add(date1);
            date1.addActionListener(this);
            lbldate2 = new Label("Please enter the end DATETIME of the chosen duration(YYYY-MM-DD HH:MM:SS): ");
            add(lbldate2);
            date2 = new JTextField("",30);
            date2.setEditable(true);
            add(date2);
            date2.addActionListener(this);

            // set to read-only
            // "super" Frame container adds TextField component



        // "btnCount" is the source object that fires an ActionEvent when clicked.
        // The source add "this" instance as an ActionEvent listener, which provides
        //   an ActionEvent handler called actionPerformed().
        // Clicking "btnCount" invokes actionPerformed().

        setTitle("Report Generator");  // "super" Frame sets its title
        setSize(800, 700);        // "super" Frame sets its initial window size

        // For inspecting the Container/Components objects
        // System.out.println(this);
        // System.out.println(lblCount);
        // System.out.println(tfCount);
        // System.out.println(btnCount);

        setVisible(true);         // "super" Frame shows


        // System.out.println(this);
        // System.out.println(lblCount);
        // System.out.println(tfCount);
        // System.out.println(btnCount);
    }

    // The entry main() method
    public static void main(String[] args) {
        // Invoke the constructor to setup the GUI, by allocating an instance
        DateTime app = new DateTime();

        // or simply "new AWTCounter();" for an anonymous instance

    }

    // ActionEvent handler - Called back upon button-click.
    @Override
    public void actionPerformed(ActionEvent evt) {
        Object actionsource = evt.getSource();
        if(actionsource instanceof JTextField){
            JTextField dateget1 = (JTextField) evt.getSource();
            JTextField dateget2 = (JTextField) evt.getSource();

            if (dateget1 == date1){
            datedefined1 = date1.getText();
                System.out.println(datedefined1);}
            else if(dateget2 == date2){

            datedefined2 = date2.getText();
            System.out.println(datedefined2);}
            else{
                type = tfCount.getText();
                System.out.println(type);


            }



        }
        else if(actionsource instanceof JCheckBox){
            JCheckBox cb = (JCheckBox) evt.getSource();
            if(cb == source1){
                source = "Drivetest";
                System.out.println(source);
            }
            else if(cb == source2){
                source = "Ookla Data Dump";
                System.out.println(source);
            }

        }



    }
}

The thing is, my main program needs to take in and store multiple string variables(ie. type, source, date1 AND date2) before it should execute.

My code for a normal terminal-style running of the program would look like this:

 System.out.println("Enter the report type you would like: DailyComparison or HourlyComparison or WeeklyComparison or EventComparison; Type the exact words!");
    type = scan.next();
    System.out.println("Now enter the type of data you would like analysed: OOKLA or ManualTest: ");
    source = scan.next();
    if("DailyComparison".equals(type) || "HourlyComparison".equals(type) || "WeeklyComparison".equals(type) ){
        Scanner scan2 = new Scanner((System.in));
        System.out.println("Now enter the lower bound of the DateTime range(FORMAT YYYY-MM-DD HH:00:00):");
        date1 = scan2.nextLine();
        System.out.println("Now enter the upper bound of the DateTime range(FORMAT YYYY-MM-DD HH:00:00):");
        date2 = scan2.nextLine();
    }

Where user-input is taken through the terminal as normal.

The user input is then used to run the rest of the program, calling the methods in other classes i have defined:

Report.report(date1, date2, type, filename, source);// Creates the excel .xlsx file report

MailSender.MailSender(filename, type); // Send a email containing the attached report xlsx file

So my question is: How do i extend this GUI code's functionality so that the user-input string variables can ALL be gathered first then used to run the rest of the program?

EDIT:

Thanks for the advice guys.

I sort of got it to work, but I'm not sure if the structure is sound. What was happening previously was that since each component was handling a different variable and i wanted to store all the variables first before calling the main method classes that would process these variables.

So i created an additional button called "Generate Report" and under the actionlistener condition+action for this button, I placed the class.methods like so. Where basically I key in all my variables in the respective components(checkboxes, button etc) THEN press "generate report"

 if (evt.getActionCommand() == "Generate Report") {


                if ("DailyComparison".equals(type)) {
                    filename = "\\Users\\User\\Documents\\Reports\\" + " Daily SpeedTest Telco Comparison Report";
                    datedefined3 = null;
                    datedefined4 = null;
                    datedefined5 = null;
                    datedefined6 = null;
                } else if ("WeeklyComparison".equals(type)) {
                    filename = "\\Users\\User\\Documents\\Reports\\" + " Weekly Telco Comparison Report";
                    datedefined3 = null;
                    datedefined4 = null;
                    datedefined5 = null;
                    datedefined6 = null;
                } else if ("HourlyComparison".equals(type)) {
                    filename = "\\Users\\User\\Documents\\Reports\\" + "Hourly Telco Comparison Report";
                    datedefined3 = null;
                    datedefined4 = null;
                    datedefined5 = null;
                    datedefined6 = null;
                }
                if("HourlyComparison".equals(type)|"DailyComparison".equals(type)|"WeeklyComparison".equals(type)) {
                    Report.report(datedefined1, datedefined2, datedefined3, datedefined4, datedefined5, datedefined6, type, filename, source);// Creates the base excel .xlsx file report
                    LinechartGenerator.chartgen(0, "upload", datedefined1, datedefined2, datedefined3, datedefined4, datedefined5, datedefined6, source, type, filename);
                    LinechartGenerator.chartgen(0, "download", datedefined1, datedefined2, datedefined3, datedefined4, datedefined5, datedefined6, source, type, filename);
                    LinechartGenerator.chartgen(0, "latency", datedefined1, datedefined2, datedefined3, datedefined4, datedefined5, datedefined6, source, type, filename);
        }


    }

Although the code has its limitations where I cannot press generate report first or the program will just throw an error seeing as no variables were stored.

I also faced a roadblock where I'm trying to find the Swing-equivalent of the Flush Scanner function to allow the user to generate multiple reports in the same program instance.

JohnDoeDeer
  • 85
  • 1
  • 11

3 Answers3

1

This would invoke some basic principles:

  • Model-View-Controller - where the "data" is separated from the view and mechanisms used to collect it
  • Observer pattern - which is used to generate notifications when some state changes so interested parties can take action.

The observer pattern is used extensively in most UI frameworks, which tend to be event driven (something happens, you respond to it), rather then procedural or linear driven.

Typically, you would create a "form" which included the fields which would capture the data you need and some kind of "button", which when pressed, would initiate the next step - validating the data, building the model and generating the notification that the form has been completed.

The observer to this would then take the model and process it as required.

These are just some of the basic concepts used in UI development. Have a look at:

for some more details

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I updated my question to include my proposed solution that i think sort of fit what you were suggesting; Was it correct? – JohnDoeDeer Nov 17 '17 at 01:56
  • `evt.getActionCommand() == "Generate Report"` isn't how you compare `String` in Java, using `String#equals` instead – MadProgrammer Nov 17 '17 at 02:04
0

I noticed that you set this as the action listener for all the check boxes and textfields. What I think you really want, is to only process the user input when the user clicks the button, right?

Remove lines like these:

tfCount.addActionListener(this);

so that this only handles the click of the button.

Now, you can access all the inputs in the actionPerformed method:

dateDefined1 = date1.getText();
dateDefined2 = date2.getText();
type = tfCount.getText();
if (source1.isChecked()) {
    source = "Drivertest";
} else {
    source = "Ookla Data Dump"
}
// now you can use dateDefined1, dateDefined2, type and source!

Also, why use check boxes but not radio buttons? For this kind of "select one from the below option" usage, radio buttons are better suited.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Yeah i was actually thinking of radio buttons, I'll read on the documentation for that. Could you explain the removal of 'tfCount.addActionListener(this);'? I was following the online tutorial but it claimed that the line .addActionListener(this) is what tells the component what action to initiate upon clicking/entering right? If i delete that line how would ActionListener be activated? – JohnDoeDeer Nov 17 '17 at 01:47
  • @JohnDoeDeer you only need to handle the press of the button, right? There's no need to listen for text fields. – Sweeper Nov 17 '17 at 06:00
-1

You may break down this in two different jars:

  1. Read the input and write that in a temp file.
  2. Once the input has been read and written to the file, invoke your GUI jar application this can read contents from the temp file.

You may refer to this question on how to invoke jar from java application.

Ravik
  • 694
  • 7
  • 12