1

我编写了一个小摇摆程序来获取用户输入(一系列 0/1 字符,后跟“完成”)将字符串返回给主类 - 代码附在下面。问题是它在正常模式下运行时挂起,但在“return new String(str)”行(在函数 getData() 中)放置断点时工作正常,之后单步运行。我认为这是一个时间问题,并在 while 循环之前放入了一个“Thread.sleep(400)”(参见注释行) - 现在它工作正常。

但是这段代码看起来很愚蠢。有没有更好的方法来编写这段代码——接受用户输入并将用户给定的字符串返回给调用类?

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

class DataEntryPanel extends JPanel implements ActionListener {
    private JButton Button0, Button1, ButtonDone;
    private JLabel DataEntered;
    public char[] str = "________".toCharArray();
    int posn = 0;
    public boolean dataDone = false;
    public DataEntryPanel() {
        this.setLayout(new FlowLayout(FlowLayout.CENTER));
        Button0 = new JButton("0"); Button0.addActionListener(this); this.add(Button0);
        Button1 = new JButton("1"); Button1.addActionListener(this); this.add(Button1);
        ButtonDone = new JButton("Done"); ButtonDone.addActionListener(this); this.add(ButtonDone);
        DataEntered = new JLabel("xxxxxxxx"); this.add(DataEntered);
    }
    public void actionPerformed(ActionEvent e) {
        Object source  = e.getSource();
        if(source==Button0) DataEntered.setText(setData('0'));
        else if(source==Button1) DataEntered.setText(setData('1'));
        else if(source==ButtonDone) dataDone=true;
    }
    public String setData(char c) {
        if(posn<8) str[posn++] = c;
        return new String(str);
    }
}
class DataEntryFrame extends JFrame {
    public JPanel panel;
    private void centerWindow (Window w) {
        Toolkit tk = Toolkit.getDefaultToolkit();
        Dimension d = tk.getScreenSize();
        setLocation((d.width-w.getWidth())/2, (d.height-w.getHeight())/2);
    }
    public DataEntryFrame() {
        setTitle("Data Entry");
        setSize(267, 200);
        centerWindow(this);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        panel = new DataEntryPanel();
        this.add(panel);
    }
    public String getData() {
        DataEntryPanel p = (DataEntryPanel) panel;
        System.out.printf("waiting for data......\n");
        // try {
           while(!p.dataDone) 
                // Thread.sleep(400)
                ; // looping on data completion
        // } catch (InterruptedException e) { e.printStackTrace(); }
        return new String(p.str);
    }
}

public class FRead {
    public FRead() {
        JFrame frame  = new DataEntryFrame();
        frame.setVisible(true);
        DataEntryFrame f = (DataEntryFrame) frame;
        String s = f.getData();
        System.out.printf("string obtained=%s\n", s);
        System.exit(0);
    }

    public static void main(String[] args) throws Exception {
        new FRead();
    }
}
4

2 回答 2

2

您可能遇到了 EDT 问题,并且您的 while 循环会占用您的 CPU。

  1. 与 UI 相关的一切都应在 EDT(事件调度线程)上执行
  2. 要使框架居中,请设置其大小(使用pack()or setSize()),然后只需调用setLocationRelativeTo(null);
  3. 永远不要while(!true) ;循环,这会占用你的 CPU 并阻塞当前线程。
  4. dataDone应该声明您的变量,volatile因为您正在“主”线程中读取它,但它已被 EDT 修改。

考虑阅读有关Swing 中的并发性

这是您的代码稍作修改的版本,似乎效果更好:

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

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class GUI {

    class DataEntryPanel extends JPanel implements ActionListener {
        private JButton button0, button1, buttonDone;
        private JLabel dataEntered;
        public char[] str = "________".toCharArray();
        int posn = 0;
        public volatile boolean dataDone = false;
        private String data;

        public DataEntryPanel() {
            this.setLayout(new FlowLayout(FlowLayout.CENTER));
            button0 = new JButton("0");
            button0.addActionListener(this);
            this.add(button0);
            button1 = new JButton("1");
            button1.addActionListener(this);
            this.add(button1);
            buttonDone = new JButton("Done");
            buttonDone.addActionListener(this);
            this.add(buttonDone);
            dataEntered = new JLabel("xxxxxxxx");
            this.add(dataEntered);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            Object source = e.getSource();
            if (source == button0) {
                dataEntered.setText(setData('0'));
            } else if (source == button1) {
                dataEntered.setText(setData('1'));
            } else if (source == buttonDone) {
                JOptionPane.showMessageDialog(this, "Data entered is " + String.format("string obtained=%s\n", getData()));
                System.exit(0);
            }
        }

        public String getData() {
            return data;
        }

        public String setData(char c) {
            if (posn < 8) {
                str[posn++] = c;
            }
            return data = new String(str);
        }

    }

    protected void initUI() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("Data Entry");
        frame.setSize(267, 200);
        frame.setLocationRelativeTo(null);
        DataEntryPanel panel = new DataEntryPanel();
        frame.add(panel);
        frame.setVisible(true);
    }

    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new GUI().initUI();
            }
        });
    }

}
于 2012-10-30T09:28:54.560 回答
1

一种选择是您使用模式对话框。一旦你打开模态对话框,之后的代码只有在你关闭它之后才会执行。关闭后,您可以从外部调用对话框类的 getter 方法,以获取输入的值。

于 2012-10-30T09:14:21.593 回答