如何存储变量以供 Java Swing Gui 中的用户输入进一步使用?

Posted

技术标签:

【中文标题】如何存储变量以供 Java Swing Gui 中的用户输入进一步使用?【英文标题】:How to store variables for further use from User-input in Java Swing Gui? 【发布时间】:2018-04-29 13:38:12 【问题描述】:

我目前有一个简单的 Java AWT/Swing 代码,它创建了一个简单的 GUI,它接受多个字符串用户输入并将其存储并显示在 Intellij 终端中,如下所示:

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);
            

        



    

问题是,我的主程序在执行之前需要接收并存储多个字符串变量(即类型、来源、日期 1 和日期 2)。

我的程序正常终端样式运行的代码如下所示:

 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();
    

正常情况下通过终端进行用户输入。

然后使用用户输入来运行程序的其余部分,调用我定义的其他类中的方法:

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

所以我的问题是:我如何扩展此 GUI 代码的功能,以便可以首先收集用户输入的字符串变量,然后用于运行程序的其余部分?

编辑:

感谢各位的建议。

我有点让它工作,但我不确定结构是否合理。之前发生的事情是,由于每个组件都在处理不同的变量,并且我想在调用将处理这些变量的主方法类之前先存储所有变量。

所以我创建了一个名为“生成报告”的附加按钮,并在此按钮的操作侦听器条件+操作下,我像这样放置了 class.methods。基本上我在各个组件(复选框,按钮等)中键入所有变量,然后按“生成报告”

 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);
        


    

虽然代码有其局限性,我不能先按生成报告,否则程序会抛出错误,因为没有存储任何变量。

我还遇到了一个障碍,我试图找到 Flush Scanner 功能的 Swing 等效项,以允许用户在同一个程序实例中生成多个报告。

【问题讨论】:

【参考方案1】:

这将调用一些基本原则:

模型-视图-控制器 - “数据”与视图和用于收集数据的机制分开 观察者模式 - 用于在某些状态发生变化时生成通知,以便相关方可以采取行动。

观察者模式在大多数 UI 框架中得到了广泛使用,它们往往是事件驱动的(发生某事,你做出响应),而不是过程或线性驱动。

通常,您会创建一个“表单”,其中包括将捕获您需要的数据的字段和某种“按钮”,当按下该按钮时,将启动下一步 - 验证数据、构建模型和生成表格已完成的通知。

对此的观察者然后将获取模型并根据需要对其进行处理。

这些只是 UI 开发中使用的一些基本概念。看看:

Creating a GUI With JFC/Swing How to use buttons How to write Action Listeners

了解更多详情

【讨论】:

我更新了我的问题以包含我认为符合您建议的我提出的解决方案;对吗? evt.getActionCommand() == "Generate Report" 不是你在 Java 中比较 String 的方式,而是使用 String#equals【参考方案2】:

我注意到您将this 设置为所有复选框和文本字段的操作侦听器。我认为您真正想要的是仅在用户单击按钮时处理用户输入,对吗?

删除这样的行:

tfCount.addActionListener(this);

这样this 只处理按钮的点击。

现在,您可以访问actionPerformed 方法中的所有输入:

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!

另外,为什么要使用复选框而不是单选按钮?对于这种“从以下选项中选择一个”的用法,单选按钮更适合。

【讨论】:

是的,我实际上是在考虑单选按钮,我会阅读相关文档。你能解释一下'tfCount.addActionListener(this);'的删除吗?我正在关注在线教程,但它声称 .addActionListener(this) 行告诉组件在单击/输入时要启动什么操作?如果我删除该行将如何激活 ActionListener? @JohnDoeDeer 您只需要处理按钮的按下,对吗?无需监听文本字段。【参考方案3】:

你可以把它分解成两个不同的罐子:

    读取输入并将其写入临时文件。 在读取输入并将其写入文件后,调用您的 GUI jar 应用程序,它可以从临时文件中读取内容。

你可以参考这个question如何从java应用程序调用jar。

【讨论】:

以上是关于如何存储变量以供 Java Swing Gui 中的用户输入进一步使用?的主要内容,如果未能解决你的问题,请参考以下文章

浏览图像文件并使用 Java Swing 显示它

如何在 Java 中使用 Button Group Swing 控件?

使用 Java 在 GUI 编程中混合 awt 和 swing

强制 Java 刷新 Java Swing GUI

Swing:关于Java界面编程的第一课,如何正确的处理界面中的线程

JAVA GUI问题。如何触动按钮后弹出文件浏览器和文件名选择框,选择保存目录?