我找到了许多关于我的问题的答案,但我仍然不明白为什么我的申请不会引起任何例外。 我在NetBeans 8中创建了一个新的Java表单应用程序。 我的表单在主方法中创建并显示如下:
public static void main(String args[])
{
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try
{
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
{
if ("Nimbus".equals(info.getName()))
{
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
}
catch (ClassNotFoundException ex)
{
java.util.logging.Logger.getLogger(MainForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (InstantiationException ex)
{
java.util.logging.Logger.getLogger(MainForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (IllegalAccessException ex)
{
java.util.logging.Logger.getLogger(MainForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (javax.swing.UnsupportedLookAndFeelException ex)
{
java.util.logging.Logger.getLogger(MainForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
new MainForm().setVisible(true);
}
});
}
因此,这个新的Runnable创建了新的MainForm并将其设置为可见。
然后,在我的代码中,我启动了新的线程来更新一些jButtons和jTextFields。代码如下:
private void updateUI() {
updateUIThread = new Thread(() ->
{
while (true) {
try {
jtfIP.setEnabled(!Start && !autoRec);
jtfPort.setEnabled(!Start && !autoRec);
jtfSlaveID.setEnabled(!Start && !autoRec);
jtfTimeout.setEnabled(!Start && !autoRec);
jtfReqInterval.setEnabled(!Start && !autoRec);
jCheckBox1.setEnabled(!Start && !autoRec);
jCBReconnect.setEnabled(!Start && !autoRec);
if (db != null) {
if (!db.getIsOpen()) {
jPBD.setBackground(Color.RED);
jPBD.setForeground(Color.WHITE);
jPBD.setText("ER");
} else {
jPBD.setBackground(Color.GREEN);
jPBD.setForeground(Color.BLACK);
jPBD.setText("OK ");
}
} else {
jPBD.setBackground(Color.RED);
jPBD.setForeground(Color.WHITE);
jPBD.setText(" ER ");
}
if (autoRec){
jbtnConnect.setText("Auto");
if (Start && Connected) {
jbtnConnect.setForeground(Color.BLACK);
jbtnConnect.setBackground(Color.GREEN);
} else {
jbtnConnect.setForeground(Color.WHITE);
jbtnConnect.setBackground(Color.RED);
}
} else {
if (Start) {
jbtnConnect.setText("Disconnect");
jbtnConnect.setForeground(Color.BLACK);
jbtnConnect.setBackground(Color.GREEN);
} else {
jbtnConnect.setText("Connect");
jbtnConnect.setForeground(Color.WHITE);
jbtnConnect.setBackground(Color.RED);
}
}
jtfErroriCitire.setText(String.valueOf(totalErrors));
try
{
Thread.sleep(300);
jPanel4.repaint(1);
}
catch (InterruptedException ex)
{
Logger.getLogger(MainForm.class.getName()).log(Level.SEVERE, null, ex);
}
}
catch (Exception ex) {
Logger.getLogger(MainForm.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
updateUIThread.start();
}
还有其他线程像上面这样开始,我得到的值不同,在上面的帖子中有更新。
我的问题是为什么我的代码不会抛出有关从另一个线程更新的UI元素的任何异常?我没有使用SwingUtilities.invokeLater(new Runnable() { //code here });
我的代码执行得很完美......
谢谢!
答案 0 :(得分:4)
Swing不是线程安全的并且是单线程的。您永远不应该从事件调度线程外部更新UI组件,同样,您不应该在EDT中运行长时间运行的进程或阻止代码,因为这会阻止它处理事件队列中的新事件,从而导致您的应用看起来像它挂...因为它有......
请查看Concurrency in Swing了解详情。
在我搔了一会儿之后,我意识到,简单的解决方案就是使用javax.swing.Timer
您希望以固定间隔(300毫秒)重复更新并更新UI,完美,Swing Timer
能够定期更新更新并在EDT上下文中执行回调!
它还具有合并重复呼叫的能力。这意味着,如果事件队列中已经存在“计时器”操作,则计时器将不会生成新的计时器,从而防止充斥EDT并导致可能的性能问题......
javax.swing.Timer timer = new Timer(300, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jtfIP.setEnabled(!Start && !autoRec);
jtfPort.setEnabled(!Start && !autoRec);
jtfSlaveID.setEnabled(!Start && !autoRec);
jtfTimeout.setEnabled(!Start && !autoRec);
jtfReqInterval.setEnabled(!Start && !autoRec);
jCheckBox1.setEnabled(!Start && !autoRec);
jCBReconnect.setEnabled(!Start && !autoRec);
if (db != null) {
if (!db.getIsOpen()) {
jPBD.setBackground(Color.RED);
jPBD.setForeground(Color.WHITE);
jPBD.setText("ER");
} else {
jPBD.setBackground(Color.GREEN);
jPBD.setForeground(Color.BLACK);
jPBD.setText("OK ");
}
} else {
jPBD.setBackground(Color.RED);
jPBD.setForeground(Color.WHITE);
jPBD.setText(" ER ");
}
if (autoRec){
jbtnConnect.setText("Auto");
if (Start && Connected) {
jbtnConnect.setForeground(Color.BLACK);
jbtnConnect.setBackground(Color.GREEN);
} else {
jbtnConnect.setForeground(Color.WHITE);
jbtnConnect.setBackground(Color.RED);
}
} else {
if (Start) {
jbtnConnect.setText("Disconnect");
jbtnConnect.setForeground(Color.BLACK);
jbtnConnect.setBackground(Color.GREEN);
} else {
jbtnConnect.setText("Connect");
jbtnConnect.setForeground(Color.WHITE);
jbtnConnect.setBackground(Color.RED);
}
}
jtfErroriCitire.setText(String.valueOf(totalErrors));
}
});
timer.start();
有关详细信息,请参阅How to use Swing Timers
答案 1 :(得分:1)
Swing说你不应该从Swing Event Dispatch Thread外面更新组件,但它并没有强制执行。检查每个呼叫来自哪个线程都是不切实际的。
此外,由于线程问题(通常只是)通常会导致问题的性质,因此当您遇到多线程代码中的错误时,不应该总是抛出异常。这是因为线程问题经常导致deadlock或memory consistency errors,这在大多数情况下是不可恢复的(通常整个JVM都会崩溃)。
答案 2 :(得分:0)
我这样做了。
private void updateUI() {
updateUIThread = new Thread(() ->
{
while (true) {
try {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jtfIP.setEnabled(!Start && !autoRec);
jtfPort.setEnabled(!Start && !autoRec);
jtfSlaveID.setEnabled(!Start && !autoRec);
jtfTimeout.setEnabled(!Start && !autoRec);
jtfReqInterval.setEnabled(!Start && !autoRec);
jCheckBox1.setEnabled(!Start && !autoRec);
jCBReconnect.setEnabled(!Start && !autoRec);
if (db != null) {
if (!db.getIsOpen()) {
jPBD.setBackground(Color.RED);
jPBD.setForeground(Color.WHITE);
jPBD.setText("ER");
} else {
jPBD.setBackground(Color.GREEN);
jPBD.setForeground(Color.BLACK);
jPBD.setText("OK ");
}
} else {
jPBD.setBackground(Color.RED);
jPBD.setForeground(Color.WHITE);
jPBD.setText(" ER ");
}
if (autoRec){
jbtnConnect.setText("Auto");
if (Start && Connected) {
jbtnConnect.setForeground(Color.BLACK);
jbtnConnect.setBackground(Color.GREEN);
} else {
jbtnConnect.setForeground(Color.WHITE);
jbtnConnect.setBackground(Color.RED);
}
} else {
if (Start) {
jbtnConnect.setText("Disconnect");
jbtnConnect.setForeground(Color.BLACK);
jbtnConnect.setBackground(Color.GREEN);
} else {
jbtnConnect.setText("Connect");
jbtnConnect.setForeground(Color.WHITE);
jbtnConnect.setBackground(Color.RED);
}
}
jtfErroriCitire.setText(String.valueOf(totalErrors));
}
});
try
{
Thread.sleep(300);
jPanel4.repaint(1);
}
catch (InterruptedException ex)
{
Logger.getLogger(MainForm.class.getName()).log(Level.SEVERE, null, ex);
}
}
catch (Exception ex) {
Logger.getLogger(MainForm.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
updateUIThread.start();
}
我将更新的UI代码放在invokeLater的run方法中。 updateUI()在应用程序启动时调用它。