java - 通过不同的线程更新java UI

标签 java multithreading swing model-view-controller

我为了开发一个 swing 应用程序,我正在使用 MVC 模式的简化版本,其中 Controller 在两个方向上都介于 View 和模型之间:

  • 当用户与 swing 控件交互时,如果此交互需要访问模型,则 swing 控件引发的事件会调用 Controller 的适当方法;
  • 当模型更新后应更新 View 时, Controller 会调用 View 的一个或多个公共(public)方法。

一个复杂的应用程序可能会请求不同的线程运行:例如,如果你必须在磁盘上写一个文件,你可以启动一个后台线程,在文件写入结束时,这个线程应该发送一个通知来查看通过 Controller 。在这种情况下,可能会出现不止一个线程想要刷新 View 的情况,因此我认为应该以某种方式处理这个问题。

我的灵感来自 this answer为了编写以下 SSCCE 的方法 appendTextupdateLastText .

public class NewJFrame extends javax.swing.JFrame {

    private volatile String lastText;

    /**
     * Creates new form NewJFrame
     */
    public NewJFrame() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane1 = new JScrollPane();
        jTextArea1 = new JTextArea();

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        jTextArea1.setEditable(false);
        jTextArea1.setColumns(20);
        jTextArea1.setRows(5);
        jScrollPane1.setViewportView(jTextArea1);

        getContentPane().add(jScrollPane1, BorderLayout.CENTER);

        pack();
    }// </editor-fold>                        


    // Variables declaration - do not modify                     
    private JScrollPane jScrollPane1;
    private JTextArea jTextArea1;
    // End of variables declaration                   

    /**
     *
     * @param text
     */
    public void appendText(final String text) {
        updateLastText(text);
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                jTextArea1.append(String.format("%s\n", lastText));
            }
        });
    }

    /**
     *
     * @param text
     */
    private synchronized void updateLastText(String text) {
        lastText = text;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {

        final NewJFrame frame = new NewJFrame();

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame.setVisible(true);
            }
        });

        Thread counter = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    frame.appendText((new Date()).toString());
                }
            }
        };
        counter.start();
    }
}

上述解决方案似乎工作正常,那么我应该使用相同的技术来更新 UI 的其他 swing 组件吗?或者有更紧凑的解决方案吗?

最佳答案

如果您运行的是多线程 swing 应用程序,那么是的,您需要确保所有 UI 交互都发生在 event dispatch thread 上. Swing 类本质上不是线程安全的,它们之所以安全,是因为它们被限制在单个线程(事件调度线程)中。

关于java - 通过不同的线程更新java UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32150941/

相关文章:

java - Java 中的不可变对象(immutable对象)和访问数据

ios - 在多线程中等待返回

c# - 我可以限制 ThreadPool 中线程的创建吗?

c# - 在 Parallel.ForEach 中监控进度

Java图像不会随着鼠标点击而移动?

java - 每个客户端模型或 NIO react 器模式的旧 I/O 线程?

java - Spring 3.1 WebApplicationInitializer & Embedded Jetty 8 AnnotationConfiguration

JavaFX TableView 每行都有单独的 bean 适配器。如何?

java - 如何将 CaretEvent.getDot() 转换为直角坐标?

Java Swing 无法正确渲染