我为了开发一个 swing 应用程序,我正在使用 MVC 模式的简化版本,其中 Controller 在两个方向上都介于 View 和模型之间:
- 当用户与 swing 控件交互时,如果此交互需要访问模型,则 swing 控件引发的事件会调用 Controller 的适当方法;
- 当模型更新后应更新 View 时, Controller 会调用 View 的一个或多个公共(public)方法。
一个复杂的应用程序可能会请求不同的线程运行:例如,如果你必须在磁盘上写一个文件,你可以启动一个后台线程,在文件写入结束时,这个线程应该发送一个通知来查看通过 Controller 。在这种情况下,可能会出现不止一个线程想要刷新 View 的情况,因此我认为应该以某种方式处理这个问题。
我的灵感来自 this answer为了编写以下 SSCCE 的方法 appendText
和 updateLastText
.
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/