2

私は、jframe にログイン フォームを持つ Java アプリケーションに取り組んでいます。その中にテキストフィールドとボタンがあります。

ログイン ボタンには、ログイン ウィンドウを作成するクラスの内部クラスである eventlistener があります。ユーザーがログイン ボタンを押すと、リスナーはフィールドから値を取得し、バリデーターに渡します。バリデーターは mysql データベースを使用してそれを検証し、ユーザーの入力に基づいて true と false を返します。戻り値に基づいて、リスナーはif-elseステートメントを使用して UI を更新します。このすべてがうまくいっています。

問題は、検証が実行されているときに gui を使用できないことです。これは、すべてのことが単一のスレッドで行われているためです。そのため、その間guiは一種の凍結されています。マルチスレッドを使用してこの問題を回避し、検証の実行中に他の GUI コンポーネントを使用するにはどうすればよいですか。

4

5 に答える 5

3

お気づきかもしれませんが、イベント ディスパッチ スレッド内で長時間実行されるタスクを実行しないでください。これにより、プログラムがハングしたように見えます。

同様に、イベント ディスパッチ スレッドの外部で UI コンポーネントを作成/変更しないでください。

最も簡単な解決策の 1 つは、SwingWorker を使用することです。これにより、バックグラウンド スレッドでコードを実行できますが、その結果はイベント ディスパッチ スレッドに自動的に再同期されます...

public class LoginForm {

    public static void main(String[] args) {
        new LoginForm();
    }

    public LoginForm() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JDialog frame = new JDialog((JFrame) null, "Login", true);
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new LoginPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                System.exit(0);
            }
        });
    }

    public class LoginPane extends JPanel {

        private JTextField userNameField;
        private JPasswordField passwordField;
        private JButton okay;
        private JButton cancel;

        public LoginPane() {

            setLayout(new BorderLayout());

            userNameField = new JTextField(15);
            passwordField = new JPasswordField(10);

            okay = new JButton("Login");
            cancel = new JButton("Cancel");

            JPanel mainPane = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.EAST;
            gbc.insets = new Insets(2, 2, 2, 2);
            mainPane.add(new JLabel("User Name:"), gbc);
            gbc.gridy++;
            mainPane.add(new JLabel("Password:"), gbc);

            gbc.gridx++;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.WEST;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            mainPane.add(userNameField, gbc);
            gbc.gridy++;
            mainPane.add(passwordField, gbc);
            mainPane.setBorder(new EmptyBorder(8, 8, 8, 8));

            add(mainPane);

            JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT));
            buttonPane.setBorder(new EmptyBorder(8, 8, 8, 8));
            buttonPane.add(okay);
            buttonPane.add(cancel);

            add(buttonPane, BorderLayout.SOUTH);

            okay.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    userNameField.setEnabled(false);
                    passwordField.setEnabled(false);
                    okay.setEnabled(false);
                    cancel.setEnabled(false);
                    new LoginWorker(userNameField.getText(), passwordField.getPassword()).execute();
                }
            });

            cancel.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    SwingUtilities.getWindowAncestor(LoginPane.this).dispose();
                }
            });
        }

        public class LoginWorker extends SwingWorker<Boolean, Boolean> {

            private String userName;
            private char[] password;

            public LoginWorker(String userName, char[] password) {
                this.userName = userName;
                this.password = password;
            }

            @Override
            protected Boolean doInBackground() throws Exception {
                // Do you background work here, query the database, compare the values...
                Thread.sleep(2000);
                return Math.round((Math.random() * 1)) == 0 ? new Boolean(true) : new Boolean(false);
            }

            @Override
            protected void done() {
                System.out.println("Done...");
                try {
                    if (get()) {
                        JOptionPane.showMessageDialog(LoginPane.this, "Login sucessful");
                    } else {
                        JOptionPane.showMessageDialog(LoginPane.this, "Login failed");
                    }
                    userNameField.setEnabled(true);
                    passwordField.setEnabled(true);
                    okay.setEnabled(true);
                    cancel.setEnabled(true);
                } catch (Exception exp) {
                    exp.printStackTrace();
                }
            }

        }

    }
}

詳細については、 Swing の同時実行を参照してください。特に、SwingWorker

于 2013-01-08T08:28:04.233 に答える
1

スレッドを使用できます。トリッキーな点は、UIに対して行う必要のある更新がUIスレッドで行われるようにすることです。このためのSwingUtilitiesヘルパークラスがあります。

例えば。

new Thread(){
    public void run() {
        // do the background work...

        SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                 // update the UI
             }
        });
    }
}.start();

スレッドの作成方法を管理したい場合は、バックグラウンドエグゼキュータの使用を検討することもできます。

ExecutorService backgroundExector = Executors.newFixedThreadPool(1);

(したがって、複数の場所から使用されたアプリ用にこれらの1つがあります)。

于 2013-01-08T07:39:48.460 に答える
0

新しいスレッドをうまく開始するのは比較的簡単です。

Thread thread = new Thread(Runnable r);
thread.start();

rはRunnableを実装し、内のsqlライブラリでユーザー名/パスワードをチェックするためのコードを含める必要がありますrun()

new Runnable() {
@Override
public void run() {
        // your sql-code goes here.
    }
};

実際の問題は、リスナーとSQLコードの両方からアクセスする必要のある変数を同期することです。

変数の同期は簡単です。

class example {
  private synchronized Integer mySyncInteger = new Integer();
}

SQLコードの実行後、ビュー(スイング作業を行う場所)からのような関数をトリガーするだけですswingClass.pushResult(Boolean)。この関数は、与えられた結果に応じてビューを変更します。作成したスレッド内で引き続き機能するため、その関数からのビューの更新には注意してください。

于 2013-01-08T07:41:09.320 に答える
0

(ボタン リスナーから) [ログイン] を押すと、ボタンが無効になり、ログイン スレッドが開始されます。このスレッドは、データベースに接続し、self または login コンポーネント クラスにいくつかのフィールドを設定して、ログインの成功を通知する必要があります。ログイン コードをtry {} finally {}and で囲み、finally セクションで call を呼び出しますSwingUtilities.invokeLater。これで、Runnableこのメソッドがパラメーターとして受け取るようになり、ボタンを再度有効にしたり、「ok」または「ログインに失敗しました」を表示したり、他のアクションを実行したりできます。

于 2013-01-08T07:39:28.707 に答える
0

データベースと通信してユーザーとパスワードを検証するスレッドを作成できます。ただし、UI の更新は Event Dispatcher スレッドからのみ行う必要があります。SwingUtilities.invokeLater()またはSwingUtilities.invokeAndWait()メソッドを使用してこれを行うことができます。

したがって、スレッドは次のように実装できます。

public void run()
{
    // logic to validate user/password

    if(valid == true)
    {
        SwingUtilities.invokeLater(/*Runnable to update the UI*/));
    }
}
于 2013-01-08T07:48:04.683 に答える