1

ユーザー入力 (0/1 文字のシーケンスの後に "Done" が続く) を取得するための小さなスイング プログラムを作成し、文字列をメイン クラスに返します - 以下にコードを添付します。問題は、通常モードで実行するとハングすることですが、「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()またはを使用してsetSize()) 設定してから、単純に呼び出します。setLocationRelativeTo(null);
  3. 決してwhile(!true) ;ループを実行しないでください。これは CPU を使い果たし、現在のスレッドをブロックします。
  4. 「メイン」スレッド内で変数を読み取っているため、変数を宣言する必要がありますが、EDT によって変更されますdataDonevolatile

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

1 つのオプションは、モーダル ダイアログを使用することです。モーダル ダイアログを開くと、その後のコードはそれを閉じた後にのみ実行されます。閉じたら、入力された値を取得するために、外部からダイアログ クラスの getter メソッドを呼び出すことができます。

于 2012-10-30T09:14:21.593 に答える