我为学习目的创建了一个非常简单的计算器,我希望“播音员”在JTextArea中宣布操作的结果。该计划的目的是利用我们在大学学习的东西。我有一个自己的声明类,它实现了runnable并同步我的calc对象,它应该附加结果但没有任何反应。
该程序运行正常,因此我已将代码剥离到相关部分:
播音员类中的run方法:
public void run()
{
calc.getAnnouncementJTF().append("Announcer thread has been initialized...\n");
calc.getAnnouncementJTF().append("Hi. My name is " + this.getName() + " and my purpose is to " +
"announce the results of your operations as soon as they are ready. \r\n");
while(true){
synchronized(calc){
try
{
calc.wait();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
calc.getAnnouncementJTF().append(String.valueOf(calc.getResult() + "\n"));
}
}
以下是执行计算并通知所有等待对象的条件:
else if(e.getSource() == sumButton && Numbers.size() != 0)
{
if(!actualNumber.getText().equals("")){
Numbers.add(new Double(actualNumber.getText()));
addToResults = previousNumbers.getText() + " " + actualNumber.getText();
} else {
addToResults = previousNumbers.getText().substring(0, previousNumbers.getText().length() - 2);
}
currentResult = performCalculation(Numbers, Operators);
previousCalcs.append(addToResults + " = " + String.valueOf(currentResult) + "\r\n");
// Clear both lists and add the result to a cleared
// list for further calculation on it.
Operators.clear();
Numbers.clear();
actualNumber.setText(String.valueOf(currentResult));
previousNumbers.setText("");
resultExist = true;
synchronized(this){
notifyAll();
}
}
主要方法
public static void main(String[] args){
Announcer announcer = new Announcer();
Calculator calc = new Calculator(announcer);
calc.setTitle("Calculator");
calc.setSize(360, 900);
calc.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
calc.setLocationRelativeTo(null);
calc.setVisible(true);
calc.setResizable(false);
announcer.setCalculator(calc); announcer.setName("Sam");
announcer.setAge(28); announcer.setLength(182.5);
Thread announcerThread = new Thread(announcer);
announcerThread.start();
}
正如我前面提到的,代码运行正常。我唯一的问题是播放器类的run方法的这部分没有运行:
calc.getAnnouncementJTF().append(String.valueOf(calc.getResult() + "\n"));
答案 0 :(得分:0)
正如评论中已经指出的那样,修改UI状态的代码必须在事件派发线程中执行。但我想,你已经在EDT做了更新。在这种情况下,问题是您正在为新结果运行无限循环轮询并将它们附加到JTextField
。这是有效的,但是您使用无限循环阻止事件派发线程,因此它没有机会重新绘制受影响的UI区域。
一个简单的解决方案是让计算线程使用Runnable
计划EventQueue.invokeLater
,这只会执行单个更新并返回。另一种方法是让Swing Timer
定期执行Runnable
,它将在calc
对象上同步并询问当前结果。请注意,在后一种情况下,就像现在的代码一样,您可能会错过更新,因为notifyAll
无法保证与其他线程的wait
调用配对。
此外,仅仅同步wait
和notify
来电是不够的。修改结果的代码和检索结果的代码(calc.getResult()
调用)也必须在synchronized
块内。