有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

swing Java:在等待另一个线程完成时更新UI

我有一些Java Swing登录面板。当用户单击“登录”按钮时,会发生广泛的数据库通信。我有一个想法,把db通信放到另一个线程中(db通信用于填充一些散列映射和单例)。在将该通信放入单独的线程后,当用户键入其uname和密码时,数据库将发生重载。当用户单击“登录”按钮时,代码将等待“重载”线程加入,然后继续

问题是,当我的代码等待db线程加入时,似乎无法进行UI更新。我不认为我可以使用SwingWorker进行db通信,因为用户可以随时单击“登录”按钮,即使在软件完成之前,我也无法加入SwingWorker(db通信必须在实际登录之前进行)

在等待另一个线程加入时,是否有办法启用Swing ui更新?我错过什么了吗


共 (5) 个答案

  1. # 1 楼答案

    1. 最简单的解决方案之一是在初始DB通信完成之前禁用登录按钮。但这将需要一些额外的进度条或消息,以确保初始化不会混淆用户。在这种情况下,您可以使用SwingWorker,它在完成时启用登录按钮

    2. 另一个解决方案是,当用户按下登录按钮时,处理应该再次委托给(另一个)后台线程,该线程等待初始DB通信线程加入。这样EDT(和GUI)就不会被阻止。实际上,连接到DB也是一个漫长的操作,因此无论如何,它都应该在后台线程中完成,即使在禁用1中所述的登录按钮时也是如此

    3. 另一个解决方案是创建一个固定大小为1(例如java.util.concurrent.Executors.newSingleThreadExecutor())的线程池,并将所有后台任务传递给该线程池。对于单线程,执行器任务将按顺序执行。第一个任务是初始数据库通信,另一个任务是登录任务

  2. # 2 楼答案

    只需放置两个标志,在两个操作(DB通信和用户单击)结束时,调用相同的方法并在那里验证两个标志的状态。如果要阻止用户输入,可能会在模式对话框中显示进度条:

    import java.awt.BorderLayout;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    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.JPanel;
    import javax.swing.JPasswordField;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    import javax.swing.SwingWorker;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class TestThreadJoin {
    
        private boolean dbWorkDone = false;
        private boolean credentialsProvided = false;
        private JTextField loginTF;
        private JTextField passwordTF;
    
        protected void initUI() {
            final JFrame frame = new JFrame(TestThreadJoin.class.getSimpleName());
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JPanel panel = new JPanel(new GridBagLayout());
            JLabel login = new JLabel("Login: ");
            JLabel password = new JLabel("Password: ");
            loginTF = new JTextField(20);
            passwordTF = new JPasswordField(20);
            GridBagConstraints gbc = new GridBagConstraints();
            panel.add(login, gbc);
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            panel.add(loginTF, gbc);
            gbc.gridwidth = 1;
            panel.add(password, gbc);
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            panel.add(passwordTF, gbc);
            JButton loginButton = new JButton("Login");
            loginButton.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    credentialsProvided = true;
                    proceed();
                }
            });
            frame.add(panel);
            frame.add(loginButton, BorderLayout.SOUTH);
            frame.pack();
            frame.setVisible(true);
            SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
    
                @Override
                protected Void doInBackground() throws Exception {
                    Thread.sleep(10000);
                    return null;
                }
    
                @Override
                protected void done() {
                    super.done();
                    dbWorkDone = true;
                    proceed();
                }
            };
            worker.execute();
        }
    
        protected void proceed() {
            if (credentialsProvided && dbWorkDone) {
                System.err.println("Continuing ");
            }
        }
    
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
                UnsupportedLookAndFeelException {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    new TestThreadJoin().initUI();
                }
            });
        }
    }
    
  3. # 3 楼答案

    使用执行器服务。调用executorService.submit(runnable),其中“runnable”执行数据库工作。submit方法将返回一个Future。然后在登录之后,您可以调用future.get(),它将等待完成(或者如果runnable已经完成,则立即返回)

  4. # 4 楼答案

    我真的认为你应该尝试一下SwingWorker,比如:

    • 当用户单击“登录”时,启动swing worker(新Swingworker<。执行();)
    • doInBackground()中,首先调用pusblih()来调用process()来禁用按钮
    • 然后等待doInBackground()中的后台线程
    • done()中更新用户界面

    这样你就不会冻结EDT

    另一个选择是运行您自己的“迷你swingworker”:

    loginButton.setEnabled(false);  // assuming this runs in the EDT
    new Thread(new Runnable() {
      public void run() {
        myOtherBgThread.join();  // here we wait for the BG thread
        SwingUtilities.invokeLater(new Runnable() {
          // go back into the EDT
          // update the UI here...
        }
      }
    }.start();
    

    希望对你有帮助,谢谢

  5. # 5 楼答案

    这可以使用SwingWorker完成。 将此ActionListener添加到JButton。还为“标签”提供JLabel字段&;“progressbar”的JProgressBar字段

    java.awt.event.ActionListener al = new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            SwingWorker swingWorker = new SwingWorker() {
    
                @Override
                protected Object doInBackground() throws Exception {
    
                    // SIMULATE DB WORK
                    for (int i = 0; i < 10; i++) {
                        synchronized (this) {
                            this.wait(300);
                        }
                        publish(10 * i);
                    }
                    publish(100);
    
                    return 0;
                }
    
                @Override
                protected void done() {
                    label.setText("Work complete");
                    button.setEnable(true);
                }
    
                @Override
                protected void process(List chunks) {
                    for (Object object : chunks) {
                        Integer progress = (Integer) object;
                        progressBar.setValue(progress);
                    }
                }
    
            };
    
            button.setEnable(false);
            swingWorker.execute();
        }
    }
    

    由于数据库工作可能无法量化(可测量),请进行以下更改:

    • 插入“进度条”。在“swingWorker”上方设置不确定(true)。execute()'行
    • 插入“进度条”。设置不确定(false)‘高于’标签。setText()行
    • 删除“发布(int)”调用