您的位置:首页 > 编程语言 > Java开发

为JAVA添加信号/槽支持(一)

2012-09-01 21:50 441 查看
QT语言以信号/槽方式取代callback机制,为编程提供了灵活性,而备受赞誉。本文将介绍如何为JAVA添加信号/槽机制的支持,并给出一个有趣的使用信号/槽机制的例子。

在QT中以connect函数注册信号/槽,使用emit函数发送信号,在我们的程序中也使用这两个函数进行信号/槽注册和信号的发送。创建类SignalSlotHandle类,内容如下:

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package cn.org.liuf.framework.signalmash;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
*
* @author liuf
*/
public class SignalSlotHandle {

/**
* 同步列表,保存注册的信号/槽信息
*/
static List<ConnectInfo> conns = Collections.synchronizedList(new ArrayList<ConnectInfo>());

/**
* 同步函数,注册信号/槽
* @param o 信号发送对象
* @param signal 信号
* @param ot 信号接收对象
* @param slot 信号处理函数,使用字符串表示的函数名
* @param c_param  信号传递的参数类数组,必须是信号处理函数实际参数类型,且顺序必须一致
*/
public static synchronized void connect(Object o, String signal, Object ot, String slot, Class<?>... c_param) {
ConnectInfo ci = new ConnectInfo();
ci.setSignalObject(o);
ci.setSlotObject(ot);
ci.setSignal(signal);
ci.setSlot(slot);
ci.setParams(c_param);
conns.add(ci);
}

/**
* 同步函数,发送信号和参数
* @param o 发送信号对象
* @param signal 信号
* @param args  参数对象数组,允许参数个数大于注册时的参数个数,但参数类型必须与注册时保持一致,且个数不能小于注册时个数
*/
public static synchronized void emit(Object o, String signal, Object... args) {

final Object[] argst = args;
for (ConnectInfo ci : conns) {
if (ci.getSignalObject() == o) {
if (ci.getSignal().compareTo(signal) == 0) {
final ConnectInfo cit = ci;
new Thread() {      // 为使用所有处理信号的函数能够同时执行,使用线程方式调用
@Override
public void run() {
// 使用反射调用信号处理函数
try {
Method method;
method = cit.getSlotObject().getClass().getMethod(cit.getSlot(), cit.getParams());
int alen = argst.length;
int plen = cit.getParams().length;
Object[] t;
if (alen > plen) { // 用于支持信号传递的参数个数大于实际参数个数,要求相应参数类型必须相同
t = Arrays.copyOf(argst, plen);
} else {
t = argst;
}
method.invoke(cit.getSlotObject(), t);
} catch (IllegalAccessException ex) {
Logger.getLogger(SignalSlotHandle.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalArgumentException ex) {
Logger.getLogger(SignalSlotHandle.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(SignalSlotHandle.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchMethodException ex) {
Logger.getLogger(SignalSlotHandle.class.getName()).log(Level.SEVERE, null, ex);
}
}
}.start();

}
}
}
}
}

class ConnectInfo {

Object signalObject;        // 发送信号对象
Object slotObject;          // 接受信号对象
String signal;              // 信号
String slot;                // 信号处理函数
Class<?>[] params;          // 传递的参数类型数组

public Object getSignalObject() {
return signalObject;
}

public void setSignalObject(Object signalObject) {
this.signalObject = signalObject;
}

public Object getSlotObject() {
return slotObject;
}

public void setSlotObject(Object slotObject) {
this.slotObject = slotObject;
}

public String getSignal() {
return signal;
}

public void setSignal(String signal) {
this.signal = signal;
}

public String getSlot() {
return slot;
}

public void setSlot(String slots) {
this.slot = slots;
}

public Class<?>[] getParams() {
return params;
}

public void setParams(Class<?>[] params) {
this.params = params;
}
}

在信号/槽处理类中,使用辅助类ConnectInfo,一个ConnectInfo类对象表示一个信号/槽注册信息。connect信号/槽注册函数的实现很简单,其功能就是向同步列表中添加ConnectInfo对象。emit信号发送函数,在外部调用时可以认为是信号发送,但其内部实现却是执行信号相应处理函数。就是这个100行左右代码的类便可以在你的工程中添加信号/槽机制支持。下面是使用这个类实现的一个有趣的例子,先来看看运行情况。











在这个例子中,模拟了一出舞台场景,场景中有4个演员A(饰演皇帝)、B(饰演忠臣1)、C(饰演忠臣2)、D(饰演奸臣)。场景的启动是由导演的一声Action开始(在程序由点击Action按钮实现),皇帝首先发出命令要求忠臣2自刎,忠臣2在2秒钟后显示出手足无措,忠臣1在4秒钟后对皇帝进行劝说,奸臣在8秒钟后对皇帝进行火上浇油的劝说,而后皇帝大怒要求他们闭嘴,然后在沉默10秒钟后皇帝发出新的命令让忠臣2继续做他的宰相。在此期间,忠臣2根据忠臣1、奸臣和皇帝的态度作出不同的反应。测试类如下:

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package test.ui;

import cn.org.liuf.framework.signalmash.SignalSlotHandle;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
*
* @author liuf
*/
public class TestJFrame extends javax.swing.JFrame {

private int sayed = 0;
private boolean worried = true;

/**
* Creates new form TestJFrame
*/
public TestJFrame() {
initComponents();
buttonGroup1.add(this.cExplainRadioButton);
buttonGroup1.add(this.cKillRadioButton);
SignalSlotHandle.connect(this, "action", this, "aAct", new Class[]{});                             // 导演说开始
SignalSlotHandle.connect(this, "action", this, "bAct", new Class[]{});                             // 导演说开始
SignalSlotHandle.connect(this, "action", this, "cAct", new Class[]{});                              // 导演说开始
SignalSlotHandle.connect(this, "action", this, "dAct", new Class[]{});                              // 导演说开始
SignalSlotHandle.connect(this, "action", this, "directAct", new Class[]{});

SignalSlotHandle.connect(this, "bdShutup", this, "bInRole", String.class);        // 皇帝演员让忠臣1闭嘴, 将信号通过参数String传递,以便槽函数根据信号作出处理
SignalSlotHandle.connect(this, "bdShutup", this, "dInRole", String.class);         // 皇帝演员让奸臣1闭嘴,String参数同上
SignalSlotHandle.connect(this, "bdShutup", this, "cInRole", String.class, Boolean.class); // 皇帝发火了,忠臣2忐忑中,String参数同上,boolean用于设置忐忑状态, ·始终是true(表示进入忐忑状态)
SignalSlotHandle.connect(this.bjLabel, "sayed", this, "cInRole", String.class, Boolean.class);        //  忠臣1演员劝说完, 忠臣2演员选择辨解,boolean类型变量用于标识忠臣1(true)和奸臣1(false),String参数同上
SignalSlotHandle.connect(this.djLabel, "sayed", this, "cInRole", String.class, Boolean.class);        //  奸臣1演员火上浇油完,忠臣2选择遵从命令(自杀),String参数同上
SignalSlotHandle.connect(this, "bdsayed", this, "aInRole", String.class);                  // 忠臣1和奸臣1说完话后,皇帝大怒,发送“bdShutup"信号,String参数同上

SignalSlotHandle.connect(this, "newcommond", this, "bInRole", String.class);        // 皇帝发布新的命令,不杀忠臣2
SignalSlotHandle.connect(this, "newcommond", this, "cInRole", String.class, Boolean.class); // boolean类型始终为false
SignalSlotHandle.connect(this, "newcommond", this, "dInRole", String.class);
}

public void aInRole(String signal) {
if (signal != null) {
if (signal.compareTo("bdsayed") == 0) {
this.aTextField.setText("你们闭嘴");
SignalSlotHandle.emit(this, "bdShutup", "bdShutup", true);
this.directjTextArea.setText("皇帝发火了!!大家沉默中,\n10秒后皇帝发布新的命令");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException ex) {
Logger.getLogger(TestJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
this.aTextField.setText("忠臣2,你继续做你的宰相吧");
SignalSlotHandle.emit(this, "newcommond", "newcommond", false);
this.directjTextArea.setText("场景剧本结束");
}
}
}

public void bInRole(String signal) {
if (signal != null) {
if (signal.compareTo("bdShutup") == 0) {
this.bTextField.setText("我沉默中...");
}else if(signal.compareTo("newcommond") == 0){
this.bTextField.setText("高兴中...");
}
}
}

public void cInRole(String signal, Boolean isGood) {
worried = isGood;
if (signal == null) {
this.cTextField.setText("不知道接收的是什么信号");
return;
}
if (signal.compareTo("sayed") == 0 && isGood) {
this.cTextField.setText("我要为自己辨解");
this.cExplainRadioButton.setSelected(true);
} else if (signal.compareTo("sayed") == 0 && !isGood) {
this.cTextField.setText("皇帝下命令了,我就要死了");
this.cKillRadioButton.setSelected(true);
} else if (signal.compareTo("bdShutup") == 0) {
this.cTextField.setText("我十分的忐忑啊");

while (this.worried) {
this.cExplainRadioButton.doClick();
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(TestJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
this.cKillRadioButton.doClick();
}
}else if(signal.compareTo("newcommond") == 0){
this.cTextField.setText("好险啊,还好皇帝放过了我");
this.cExplainRadioButton.setSelected(false);
}
}

public void dInRole(String signal) {
if (signal != null) {
if (signal.compareTo("bdShutup") == 0) {
this.dTextField.setText("我沉默中...");
}else if(signal.compareTo("newcommond") == 0){
this.dTextField.setText("郁闷中...");
}
}
}

public void directAct() {
this.directjTextArea.setText("皇帝发布命令,忠臣1 4秒\n后动作,忠臣2 2秒后动\n作,奸臣1 8秒后动作 ");
}

public void aAct() {
this.aTextField.setText("忠臣2,你自刎吧");
}

public void bAct() {
this.bTextField.setText("开演了,进入角色");
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException ex) {
Logger.getLogger(TestJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
this.bTextField.setText("劝说皇帝,不杀忠臣2");
SignalSlotHandle.emit(this.bjLabel, "sayed", "sayed", true);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException ex) {
Logger.getLogger(TestJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
sayed++;
if (sayed == 2) {
SignalSlotHandle.emit(this, "bdsayed", "bdsayed");
sayed = 0;
}
}

public void cAct() {
this.cTextField.setText("开演了,进入角色");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException ex) {
Logger.getLogger(TestJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
this.cTextField.setText("心理独白:我该怎么办");
}

public void dAct() {
this.dTextField.setText("开演了,进入角色");
try {
TimeUnit.SECONDS.sleep(8);
} catch (InterruptedException ex) {
Logger.getLogger(TestJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
this.dTextField.setText("火上浇油,杀了忠臣2");
SignalSlotHandle.emit(this.djLabel, "sayed", "sayed", false);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException ex) {
Logger.getLogger(TestJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
sayed++;
if (sayed == 2) {
SignalSlotHandle.emit(this, "bdsayed", "bdsayed");
sayed = 0;
}
}

/**
* 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() {

buttonGroup1 = new javax.swing.ButtonGroup();
actionButton = new javax.swing.JButton();
aTextField = new javax.swing.JTextField();
jLabel1 = new javax.swing.JLabel();
ajLabel = new javax.swing.JLabel();
bTextField = new javax.swing.JTextField();
bjLabel = new javax.swing.JLabel();
cjLabel = new javax.swing.JLabel();
cExplainRadioButton = new javax.swing.JRadioButton();
cKillRadioButton = new javax.swing.JRadioButton();
dTextField = new javax.swing.JTextField();
djLabel = new javax.swing.JLabel();
cTextField = new javax.swing.JTextField();
jScrollPane1 = new javax.swing.JScrollPane();
directjTextArea = new javax.swing.JTextArea();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

actionButton.setText("Action");
actionButton.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
actionButtonMouseClicked(evt);
}
});

aTextField.setText("我要开演");

jLabel1.setText("导演");

ajLabel.setText("演员A(皇帝)");

bjLabel.setText("演员B(忠臣1)");

cjLabel.setText("演员C(忠臣2)");

cExplainRadioButton.setText("辩解");

cKillRadioButton.setText("遵从命令");

djLabel.setText("演员D(奸臣)");

directjTextArea.setEditable(false);
directjTextArea.setColumns(20);
directjTextArea.setRows(5);
directjTextArea.setText("由我安排");
directjTextArea.setAutoscrolls(false);
directjTextArea.setName(""); // NOI18N
jScrollPane1.setViewportView(directjTextArea);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(39, 39, 39)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(actionButton)
.addComponent(jLabel1)))
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(djLabel)
.addComponent(dTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 146, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 12, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 185, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(cKillRadioButton)
.addComponent(cExplainRadioButton)
.addComponent(cjLabel)
.addComponent(aTextField)
.addComponent(ajLabel)
.addComponent(bTextField)
.addComponent(bjLabel)
.addComponent(cTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 173, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(30, 30, 30))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(actionButton)
.addGap(10, 10, 10)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(ajLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(aTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(bjLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(bTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(cjLabel)
.addGap(2, 2, 2)
.addComponent(cTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cExplainRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cKillRadioButton)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(djLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(78, 78, 78))))
);

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

private void actionButtonMouseClicked(java.awt.event.MouseEvent evt) {
SignalSlotHandle.emit(this, "action", new Object[]{});
}

/**
* @param args the command line arguments
*/
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(TestJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(TestJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(TestJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(TestJFrame.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 TestJFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JTextField aTextField;
private javax.swing.JButton actionButton;
private javax.swing.JLabel ajLabel;
private javax.swing.JTextField bTextField;
private javax.swing.JLabel bjLabel;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JRadioButton cExplainRadioButton;
private javax.swing.JRadioButton cKillRadioButton;
private javax.swing.JTextField cTextField;
private javax.swing.JLabel cjLabel;
private javax.swing.JTextField dTextField;
private javax.swing.JTextArea directjTextArea;
private javax.swing.JLabel djLabel;
private javax.swing.JLabel jLabel1;
private javax.swing.JScrollPane jScrollPane1;
// End of variables declaration
}

只需要关注这个类上部分,此类界面由Netbeans自动生成。使用信号/槽机制,首先是注册信号/槽对,在构造函数完成。

SignalSlotHandle.connect(this, "action", this, "aAct", new Class[]{});                             // 导演说开始
SignalSlotHandle.connect(this, "action", this, "bAct", new Class[]{});                             // 导演说开始
SignalSlotHandle.connect(this, "action", this, "cAct", new Class[]{});                              // 导演说开始
SignalSlotHandle.connect(this, "action", this, "dAct", new Class[]{});                              // 导演说开始
SignalSlotHandle.connect(this, "action", this, "directAct", new Class[]{});

SignalSlotHandle.connect(this, "bdShutup", this, "bInRole", String.class);        // 皇帝演员让忠臣1闭嘴, 将信号通过参数String传递,以便槽函数根据信号作出处理
SignalSlotHandle.connect(this, "bdShutup", this, "dInRole", String.class);         // 皇帝演员让奸臣1闭嘴,String参数同上
SignalSlotHandle.connect(this, "bdShutup", this, "cInRole", String.class, Boolean.class); // 皇帝发火了,忠臣2忐忑中,String参数同上,boolean用于设置忐忑状态, ·始终是true(表示进入忐忑状态)
SignalSlotHandle.connect(this.bjLabel, "sayed", this, "cInRole", String.class, Boolean.class);        //  忠臣1演员劝说完, 忠臣2演员选择辨解,boolean类型变量用于标识忠臣1(true)和奸臣1(false),String参数同上
SignalSlotHandle.connect(this.djLabel, "sayed", this, "cInRole", String.class, Boolean.class);        //  奸臣1演员火上浇油完,忠臣2选择遵从命令(自杀),String参数同上
SignalSlotHandle.connect(this, "bdsayed", this, "aInRole", String.class);                  // 忠臣1和奸臣1说完话后,皇帝大怒,发送“bdShutup"信号,String参数同上

SignalSlotHandle.connect(this, "newcommond", this, "bInRole", String.class);        // 皇帝发布新的命令,不杀忠臣2
SignalSlotHandle.connect(this, "newcommond", this, "cInRole", String.class, Boolean.class); // boolean类型始终为false
SignalSlotHandle.connect(this, "newcommond", this, "dInRole", String.class);

当点击Action按钮时,当前类发出"action"信号,调用相应槽函数aAct、bAct、cAct、dAct。首先皇帝角色发出忠臣2自刎的命令(aAct),其他角色分别等待设定时间。之后忠臣2角色表现无助(cAct);忠臣1角色进行劝说(bAct),发出"sayed"信号,忠臣2角色接收后决定进行辩解(cInRole);奸臣角色进行火上浇油的劝说(dAct),发出"sayed"信号,忠臣2角色接收后决定遵从命令自杀(cInRole)。在bAct、dAct槽函数有个计数,用于当忠臣1和奸臣都在说时,发出"bdsayed"信号给皇帝,皇帝角色命令他们闭嘴(发出信号"bdShutup"),忠臣1和奸臣收到信号后保持沉默(bInRole和dInRole),忠臣2收到信号后表现出忐忑不安(cInRole)。皇帝角色在大家沉默10秒后,发布新命令(信号"newcommond")赦免忠臣2。忠臣1、忠臣2、奸臣分别表现不同的反应(bInRole、cInRole、dInRole)。

在程序中有个boolean类型变量worried,用于控制忠臣2角色是否表现出忐忑不安,当worried为true时,界面上“辩解”和“遵从命令”单选按钮不停交替选中,以表现忐忑不安的状态。设置这个变量是因为每次函数调用都是在独立的线程中执行,第二次调用并不影响第一次调用,所以使用一个“全局”量控制忐忑不安状态时调用函数的结束。

问题:

1、 由于信号/槽处理类为静态类,从包加载起对象就已经存在,直到JVM销毁。所以同步列表需要实时维护,当注册的对象不存在时应该及时的清理列表,以减少资源占用。

2、 在emit函数中使用Thread类进行线程创建,存在与Swing图形组件的兼容性问题。

3、 例子程序在反复点击Action按钮时,会抛出InvocationTargetException异常和ClassCastException异常(java.lang.Character cannot be cast to javax.swing.Painter)。异常的发生通常在cInRole函数中的这个循环中。当减小此循环的持续时间时,异常出现的概率明显减小。

while (this.worried) {
this.cExplainRadioButton.doClick();
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(TestJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
this.cKillRadioButton.doClick();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: