A exceção acontece porque você está alterando uma coleção (adicionando ou removendo itens) enquanto itera usando um enhanced for
ou um Iterator
.
Posta o código completo da classe que fica fácil te mostrar como resolver o problema.
A exceção acontece porque você está alterando uma coleção (adicionando ou removendo itens) enquanto itera usando um enhanced for
ou um Iterator
.
Posta o código completo da classe que fica fácil te mostrar como resolver o problema.
Estou usando uma LinkedList
e via thread
de monitoramento vou adicionando os eventos disparados.
public class CLPMonitor {
private Protocol protocol;
private List<CLPListener> listeners = new LinkedList<CLPListener>();
private static CLPMonitor eagerInstance = null;
public static synchronized CLPMonitor getEagerInstance() {
if (eagerInstance == null) {
eagerInstance = new CLPMonitor();
}
return eagerInstance;
}
private CLPMonitor() {
}
public void start() {
clpMonitor();
}
public void addCLPListener(CLPListener listener) {
listeners.add(listener);
}
public void clpMonitor() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
if (protocol.readBoolean(4099, 2)) {
for (CLPListener listener : listeners) {
listener.machineReference(new CLPEvent(4099, 2));
}
} else {
for (CLPListener listener : listeners) {
listener.machineReferenceOff(new CLPEvent(4099, 2));
}
}
if (protocol.readBoolean(4099, 9)) {
for (CLPListener listener : listeners) {
listener.generalEmergency(new CLPEvent(4099, 9));
}
} else {
for (CLPListener listener : listeners) {
listener.generalEmergencyLiberate(new CLPEvent(4099, 9));
}
}
if (protocol.readBoolean(4140, 6)) {
for (CLPListener listener : listeners) {
listener.engineOverload(new CLPEvent(4140, 6));
}
}
if (protocol.readBoolean(4099, 8)) {
for (CLPListener listener : listeners) {
listener.failedMachine(new CLPEvent(4099, 8));
}
}
if (!protocol.readBoolean(4100, 2)) {
for (CLPListener listener : listeners) {
listener.tablePositioning(new CLPEvent(4100, 2));
}
}
if (protocol.readBoolean(4100, 7)) {
for (CLPListener listener : listeners) {
listener.positionTable(new CLPEvent(4100, 7));
}
}
if (protocol.readBoolean(4100, 4) && !protocol.readBoolean(4099, 9)) {
for (CLPListener listener : listeners) {
listener.securityCurtain(new CLPEvent(4100, 4));
}
} else {
for (CLPListener listener : listeners) {
listener.securityCurtainLiberate(new CLPEvent(4100, 4));
}
}
}
}
if (protocol.readBoolean(4099, 6)) {
for (CLPListener listener : listeners) {
listener.feedPositionOK(new CLPEvent(4099, 6));
}
}
if (protocol.readBoolean(4099, 15)) {
for (CLPListener listener : listeners) {
listener.machineStopped(new CLPEvent(4099, 15));
}
} else {
for (CLPListener listener : listeners) {
listener.machineInMotion(new CLPEvent(4099, 15));
}
}
if (protocol.readBoolean(4100, 3)) {
for (CLPListener listener : listeners) {
listener.resetFailed(new CLPEvent(4100, 3));
}
} else {
for (CLPListener listener : listeners) {
listener.resetFailedOff(new CLPEvent(4100, 3));
}
}
if (protocol.readBoolean(4099, 14)) {
for (CLPListener listener : listeners) {
listener.machineOK(new CLPEvent(4099, 14));
}
} else {
for (CLPListener listener : listeners) {
listener.machineOFF(new CLPEvent(4099, 14));
}
}
}
} catch (Exception e) {
}
}
});
thread.start();
}
}
Alguma classe está chamando o método addCLPListener
enquanto sua Thread
está processando um dos inúmeros for (CLPListener listener : listeners)
.
Quando eu implemento classes que podem receber vários listeners, eu não utilizo coleções, eu implemento o padrão de projeto Composite com a interface do listener.
O próprio Swing e AWT utilizam essa estratégia através da classe AWTEventMulticaster
.
O benefício é que a implementação fica mais limpa, pois acaba com a necessidade de iterar listas de listeners.
No seu caso, vamos criar a classe CLPEventMulticaster
, conforme abaixo:
final class CLPEventMulticaster implements CLPListener {
protected static CLPListener add(CLPListener atual, CLPListener proximo) {
if (atual == null) {
return proximo;
}
if (proximo == null) {
return atual;
}
return new CLPEventMulticaster(atual, proximo);
}
protected static CLPListener remove(CLPListener atual, CLPListener anterior) {
if (atual == anterior || atual == null) {
return null;
}
if (atual instanceof CLPEventMulticaster) {
return ((CLPEventMulticaster) atual).remove(anterior);
}
return atual;
}
private final CLPListener a;
private final CLPListener b;
private CLPEventMulticaster(CLPListener a, CLPListener b) {
this.a = a;
this.b = b;
}
@Override
public void engineOverload(CLPEvent clpEvent) {
a.engineOverload(clpEvent);
b.engineOverload(clpEvent);
}
@Override
public void failedMachine(CLPEvent clpEvent) {
a.failedMachine(clpEvent);
b.failedMachine(clpEvent);
}
@Override
public void feedPositionOK(CLPEvent clpEvent) {
a.feedPositionOK(clpEvent);
b.feedPositionOK(clpEvent);
}
@Override
public void generalEmergency(CLPEvent clpEvent) {
a.generalEmergency(clpEvent);
b.generalEmergency(clpEvent);
}
@Override
public void generalEmergencyLiberate(CLPEvent clpEvent) {
a.generalEmergencyLiberate(clpEvent);
b.generalEmergencyLiberate(clpEvent);
}
@Override
public void machineInMotion(CLPEvent clpEvent) {
a.machineInMotion(clpEvent);
b.machineInMotion(clpEvent);
}
@Override
public void machineOFF(CLPEvent clpEvent) {
a.machineOFF(clpEvent);
b.machineOFF(clpEvent);
}
@Override
public void machineOK(CLPEvent clpEvent) {
a.machineOK(clpEvent);
b.machineOK(clpEvent);
}
@Override
public void machineReference(CLPEvent clpEvent) {
a.machineReference(clpEvent);
b.machineReference(clpEvent);
}
@Override
public void machineReferenceOff(CLPEvent clpEvent) {
a.machineReferenceOff(clpEvent);
b.machineReferenceOff(clpEvent);
}
@Override
public void machineStopped(CLPEvent clpEvent) {
a.machineStopped(clpEvent);
b.machineStopped(clpEvent);
}
@Override
public void positionTable(CLPEvent clpEvent) {
a.positionTable(clpEvent);
b.positionTable(clpEvent);
}
@Override
public void resetFailed(CLPEvent clpEvent) {
a.resetFailed(clpEvent);
b.resetFailed(clpEvent);
}
@Override
public void resetFailedOff(CLPEvent clpEvent) {
a.resetFailedOff(clpEvent);
b.resetFailedOff(clpEvent);
}
@Override
public void securityCurtain(CLPEvent clpEvent) {
a.securityCurtain(clpEvent);
b.securityCurtain(clpEvent);
}
@Override
public void securityCurtainLiberate(CLPEvent clpEvent) {
a.securityCurtainLiberate(clpEvent);
b.securityCurtainLiberate(clpEvent);
}
@Override
public void tablePositioning(CLPEvent clpEvent) {
a.tablePositioning(clpEvent);
b.tablePositioning(clpEvent);
}
private CLPListener remove(CLPListener listener) {
if (listener == a) {
return b;
}
if (listener == b) {
return a;
}
CLPListener primeiro = remove(a, listener);
CLPListener segundo = remove(b, listener);
if (primeiro == a && segundo == b) {
return this;
}
return add(primeiro, segundo);
}
}
E agora vamos modificar a classe CLPMonitor
para ter somente um atributo do tipo CLPListener
:
public class CLPMonitor {
private Protocol protocol;
// mesmo quando houver mais de um listener
// para essa classe é como se fosse um só objeto
// é a magia do padrão Composite
private CLPListener listener;
private static CLPMonitor eagerInstance;
public static synchronized CLPMonitor getEagerInstance() {
if (eagerInstance == null) {
eagerInstance = new CLPMonitor();
}
return eagerInstance;
}
private CLPMonitor() {}
public void start() {
clpMonitor();
}
public void addCLPListener(CLPListener listener) {
// aqui acontece a mágica ao adicionar listeners
this.listener = CLPEventMulticaster.add(this.listener, listener);
}
public void removeCLPListener(CLPListener listener) {
// se quiser remover um listener, também pode
this.listener = CLPEventMulticaster.remove(this.listener, listener);
}
public void clpMonitor() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
if (listener == null) {
// se não há listeners
// dá uma chance pras outras Threads
// e volta pro início
Thread.yield();
continue;
}
// Veja que maravilha: não há mais loops!!!
if (protocol.readBoolean(4099, 2)) {
listener.machineReference(new CLPEvent(4099, 2));
} else {
listener.machineReferenceOff(new CLPEvent(4099, 2));
}
if (protocol.readBoolean(4099, 9)) {
listener.generalEmergency(new CLPEvent(4099, 9));
} else {
listener.generalEmergencyLiberate(new CLPEvent(4099, 9));
}
if (protocol.readBoolean(4140, 6)) {
listener.engineOverload(new CLPEvent(4140, 6));
}
if (protocol.readBoolean(4099, 8)) {
listener.failedMachine(new CLPEvent(4099, 8));
}
if (!protocol.readBoolean(4100, 2)) {
listener.tablePositioning(new CLPEvent(4100, 2));
}
if (protocol.readBoolean(4100, 7)) {
listener.positionTable(new CLPEvent(4100, 7));
}
if (protocol.readBoolean(4100, 4) && !protocol.readBoolean(4099, 9)) {
listener.securityCurtain(new CLPEvent(4100, 4));
} else {
listener.securityCurtainLiberate(new CLPEvent(4100, 4));
}
if (protocol.readBoolean(4099, 6)) {
listener.feedPositionOK(new CLPEvent(4099, 6));
}
if (protocol.readBoolean(4099, 15)) {
listener.machineStopped(new CLPEvent(4099, 15));
} else {
listener.machineInMotion(new CLPEvent(4099, 15));
}
if (protocol.readBoolean(4100, 3)) {
listener.resetFailed(new CLPEvent(4100, 3));
} else {
listener.resetFailedOff(new CLPEvent(4100, 3));
}
if (protocol.readBoolean(4099, 14)) {
listener.machineOK(new CLPEvent(4099, 14));
} else {
listener.machineOFF(new CLPEvent(4099, 14));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
Perceba que agora não há mais aqueles for (CLPListener listener : listeners)
.
Mesmo que você adicione mais de um CLPListener
, a classe CLPMonitor
manipula apenas um objeto do tipo CLPListener
.
O CLPEventMulticaster
é quem liga um CLPListener
com outro para atuar como uma lista, assim você não terá mais as java.util.ConcurrentModificationException
.
Fiz estas alterações que você sugeriu e realmente não recebi mais a exceção, obrigada!
Quanto a ideia de remover um listener
, em que casos eu deveria fazer isto?
Eu tenho uma instância única do CLPMonitor
, à qual faço o addCLPListener
em diversas telas do software, esse addCLPListener
eu faço no setVisible()
de cada tela, pois cada uma tem suas particularidades à executar em cada evento, entende? Gostaria de saber se esta é uma implementação correta ou se teria outra forma de fazer que seria mais indicada?
Quando você quiser, só pus o método para manter a ortogonalidade.
Não faz muito sentido você permitir adicionar algo à uma coleção e não permitir que remova.
Então, nesse caso, faz todo sentido você fazer o addCLPListener
quando passar true
para o setVisible
e chamar o removeCLPListener
quando passar false
para o setVisible
.
Eu até tentei isto, mas a princípio parece que ele remove “todos” e aí os eventos específicos não são mais disparados.
Outra coisa que notei é que, por exemplo, estou em uma tela e aí um dos eventos é disparado faz o que precisa, tranquilo, aí saio desta dela e entro em outra e o evento é disparado novamente e tals, mas aí pelo que parece ele ainda acessa o comportamento para aquele evento lá na outra tela que estava antes, o que será que pode ser?
Sim, porque você saiu da tela, mas o listener daquela tela continua registrado no CLPMonitor
, por isso tem que remover ao sair da tela.
Não deveria, dá uma depurada no método remove
do CLPEventMulticaster
.
Você copiou a classe conforme eu postei?
Posta os seguintes códigos:
CLPEventMulticaster
CLPMonitor
1 ou 2 telas que adicionam um CLPListener
Fiz a depuração no método e pelo que notei ele sempre cai no:
if (atual == anterior || atual == null) {
return null;
}
Segue a classe CLPEventMulticaster:
public final class CLPEventMulticaster implements CLPListener {
protected static CLPListener add(CLPListener atual, CLPListener proximo) {
if (atual == null) {
return proximo;
}
if (proximo == null) {
return atual;
}
return new CLPEventMulticaster(atual, proximo);
}
protected static CLPListener remove(CLPListener atual, CLPListener anterior) {
if (atual == anterior || atual == null) {
return null;
}
if (atual instanceof CLPEventMulticaster) {
return ((CLPEventMulticaster) atual).remove(anterior);
}
return atual;
}
private final CLPListener a;
private final CLPListener b;
private CLPEventMulticaster(CLPListener a, CLPListener b) {
this.a = a;
this.b = b;
}
@Override
public void generalEmergency(CLPEvent event) {
a.generalEmergency(event);
b.generalEmergency(event);
}
@Override
public void generalEmergencyApproved(CLPEvent event) {
a.generalEmergencyApproved(event);
b.generalEmergencyApproved(event);
}
@Override
public void securityCurtain(CLPEvent event) {
a.securityCurtain(event);
b.securityCurtain(event);
}
@Override
public void securityCurtainApproved(CLPEvent event) {
a.securityCurtainApproved(event);
b.securityCurtainApproved(event);
}
@Override
public void engineOverload(CLPEvent event) {
a.engineOverload(event);
b.engineOverload(event);
}
@Override
public void failedMachine(CLPEvent event) {
a.failedMachine(event);
b.failedMachine(event);
}
@Override
public void feedPositionOK(CLPEvent event) {
a.feedPositionOK(event);
b.feedPositionOK(event);
}
@Override
public void tablePositioning(CLPEvent event) {
a.tablePositioning(event);
b.tablePositioning(event);
}
@Override
public void positionTable(CLPEvent event) {
a.positionTable(event);
b.positionTable(event);
}
@Override
public void machineStopped(CLPEvent event) {
a.machineStopped(event);
b.machineStopped(event);
}
@Override
public void machineInMotion(CLPEvent event) {
a.machineInMotion(event);
b.machineInMotion(event);
}
@Override
public void resetFailed(CLPEvent event) {
a.resetFailed(event);
b.resetFailed(event);
}
@Override
public void resetFailedOff(CLPEvent event) {
a.resetFailedOff(event);
b.resetFailedOff(event);
}
@Override
public void machineOK(CLPEvent event) {
a.machineOK(event);
b.machineOK(event);
}
@Override
public void machineOFF(CLPEvent event) {
a.machineOFF(event);
b.machineOFF(event);
}
@Override
public void machineReference(CLPEvent event) {
a.machineReference(event);
b.machineReference(event);
}
@Override
public void machineReferenceOff(CLPEvent event) {
a.machineReferenceOff(event);
b.machineReferenceOff(event);
}
private CLPListener remove(CLPListener listener) {
if (listener == a) {
return b;
}
if (listener == b) {
return a;
}
CLPListener primeiro = remove(a, listener);
CLPListener segundo = remove(b, listener);
if (primeiro == a && segundo == b) {
return this;
}
return add(primeiro, segundo);
}
}
Segue a classe CLPMonitor:
public class CLPMonitor {
private Protocol protocol;
private CLPListener listener;
private static CLPMonitor eagerInstance = null;
public static synchronized CLPMonitor getEagerInstance() {
if (eagerInstance == null) {
eagerInstance = new CLPMonitor();
}
return eagerInstance;
}
private CLPMonitor() {
}
public void start() {
protocol = ActionMachineBuilder.getConnection();
clpMonitor();
}
public void addCLPListener(CLPListener listener) {
this.listener = CLPEventMulticaster.add(this.listener, listener);
}
public void removeCLPListener() {
this.listener = CLPEventMulticaster.remove(this.listener, listener);
}
public void clpMonitor() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
if (ProtocolConstants.isdemonstrationmode) {
sleep(100);
return;
}
protocol.connect();
while (true) {
if (protocol.readBoolean(4099, 2)) {
listener.machineReference(new CLPEvent(4099, 2));
} else {
listener.machineReferenceOff(new CLPEvent(4099, 2));
}
if (protocol.readBoolean(4099, 9)) {
listener.generalEmergency(new CLPEvent(4099, 9));
} else {
listener.generalEmergencyApproved(new CLPEvent(4099, 9));
}
if (protocol.readBoolean(4140, 6)) {
listener.engineOverload(new CLPEvent(4140, 6));
}
if (protocol.readBoolean(4099, 8)) {
listener.failedMachine(new CLPEvent(4099, 8));
}
if (!protocol.readBoolean(4100, 2)) {
listener.tablePositioning(new CLPEvent(4100, 2));
}
if (protocol.readBoolean(4100, 7)) {
listener.positionTable(new CLPEvent(4100, 7));
}
if (protocol.readBoolean(4100, 4) && !protocol.readBoolean(4099, 9)) {
listener.securityCurtain(new CLPEvent(4100, 4));
} else {
listener.securityCurtainApproved(new CLPEvent(4100, 4));
}
if (protocol.readBoolean(4100, 3) && !protocol.readBoolean(4100, 4)) {
listener.resetFailed(new CLPEvent(4100, 3));
} else {
listener.resetFailedOff(new CLPEvent(4100, 3));
}
if (protocol.readBoolean(4099, 6)) {
listener.feedPositionOK(new CLPEvent(4099, 6));
}
if (protocol.readBoolean(4099, 15)) {
listener.machineStopped(new CLPEvent(4099, 15));
} else {
listener.machineInMotion(new CLPEvent(4099, 15));
}
if (protocol.readBoolean(4099, 14)) {
listener.machineOK(new CLPEvent(4099, 14));
} else {
listener.machineOFF(new CLPEvent(4099, 14));
}
}
} catch (IOException e) {
// ignored
protocol.disconnect();
}
}
});
thread.start();
}
Segue uma tela (AppMenuPane - tela principal do sistema):
public class AppMenuPane extends JPanel {
private JPanel bottomMenu;
private Protocol modbus;
public AppMenuPane() {
setLayout(new BorderLayout());
modbus = ActionMachineBuilder.getConnection();
modbus.disconnect();
bottomMenu = new MenuPanePane(new FormLayout("0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu", "0dlu,pref,0dlu"));
add(bottomMenu, BorderLayout.SOUTH);
// neste bottomMenu tem os botões que acessam as outras telas do sistema
}
@Override
public void setVisible(boolean bln) {
super.setVisible(bln);
if (bln) {
enabledButtons();
try {
modbus.connect();
} catch (IOException ex) {
//
}
CLPMonitor.getEagerInstance().addCLPListener(new CLPListener() {
@Override
public void generalEmergency(CLPEvent event) {
disableButtons();
}
@Override
public void generalEmergencyApproved(CLPEvent event) {
enabledButtons();
}
@Override
public void securityCurtain(CLPEvent event) {
disableButtons();
}
@Override
public void securityCurtainApproved(CLPEvent event) {
try {
modbus.writeBoolean(4097, 9, false);
sleep(200);
} catch (IOException ex) {
//Logger.getLogger(AppMenuPane.class.getName()).log(Level.SEVERE, null, ex);
}
enabledButtons();
}
@Override
public void engineOverload(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void failedMachine(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void feedPositionOK(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void tablePositioning(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void positionTable(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineStopped(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineInMotion(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void resetFailed(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void resetFailedOff(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineOK(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineOFF(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineReference(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineReferenceOff(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
});
} else {
modbus.disconnect();
}
}
}
Segue outra tela (IOPane):
public class IOPane extends JPanel {
private JButton backButton;
private MenuPanePane bottomMenu;
private Protocol modbus;
public IOPane() {
setLayout(new BorderLayout());
modbus = ActionMachineBuilder.getConnection();
modbus.disconnect();
// aqui tem umas tabelas
bottomMenu = new MenuPanePane(new FormLayout("0dlu,pref,0dlu,pref,0dlu,fill:pref:grow,0dlu,pref,0dlu", "0dlu,pref,0dlu"));
add(bottomMenu, BorderLayout.SOUTH);
backButton = ButtonUtility.makeButton();
backButton.setText("Voltar");
backButton.setPreferredSize(new Dimension(bw, bh));
backButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
ModuleManager.getInstance().backToLastModule();
}
});
bottomMenu.add(backButton, new CellConstraints(8, 2));
}
@Override
public void setVisible(boolean bln) {
super.setVisible(bln);
if (bln) {
try {
modbus.connect();
} catch (IOException ex) {
//Logger.getLogger(IOPane.class.getName()).log(Level.SEVERE, null, ex);
}
CLPMonitor.getEagerInstance().addCLPListener(new CLPListener() {
@Override
public void generalEmergency(CLPEvent event) {
backButton.setEnabled(false);
}
@Override
public void generalEmergencyApproved(CLPEvent event) {
backButton.setEnabled(true);
}
@Override
public void securityCurtain(CLPEvent event) {
backButton.setEnabled(false);
}
@Override
public void securityCurtainApproved(CLPEvent event) {
try {
modbus.writeBoolean(4097, 9, false);
sleep(200);
} catch (IOException ex) {
//Logger.getLogger(IOPane.class.getName()).log(Level.SEVERE, null, ex);
}
backButton.setEnabled(true);
}
@Override
public void engineOverload(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void failedMachine(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void feedPositionOK(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void tablePositioning(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void positionTable(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineStopped(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineInMotion(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void resetFailed(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void resetFailedOff(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineOK(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineOFF(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineReference(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void machineReferenceOff(CLPEvent event) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
});
} else {
modbus.disconnect();
}
}
}
Bom, no geral as telas seguem sempre essa mesma estrutura, algumas delas ao clicar no botão de voltar irão retornar sempre para a tela principal (AppMenuPane), outras delas irão voltar para a tela aberta anteriormente (sistema de histórico de telas).
Outra coisa, tenho uma “tela” que nada verdade é um um painel de menu, que fica visível durante todo o tempo, nele eu também tenho um addCLPListener, será que isso não pode ser um problema?
É que na classe CLPMonitor você implementou errado o método removeCLPListener, veja:
public void removeCLPListener() { // está faltando o parâmetro listener
this.listener = CLPEventMulticaster.remove(this.listener, listener); // você está removendo o this.listener
}
O correto é assim:
public void removeCLPListener(CLPListener listenerParaRemover) {
this.listener = CLPEventMulticaster.remove(this.listener, listenerParaRemover);
}
Eu vi que as implementações dos seus CLPListeners
tem muitos métodos vazios, faz sentido pois em cada tela você só quer tratar alguns eventos específicos, mas fica muito feio você toda vez implementar todos os métodos vazios.
O ideal nesse caso, é ter uma classe abstrata que implementa o CLPListener
sem fazer nada, aí ao invés de implementar diretamente o CLPListener
, você estende essa classe e só sobrescreve os métodos dos eventos do seu interesse.
Vamos criar a classe CLPAdapter
, com métodos que não fazem nada:
public abstract class CLPAdapter implements CLPListener {
@Override
public void machineReference(CLPEvent clpEvent) {}
@Override
public void machineReferenceOff(CLPEvent clpEvent) {}
@Override
public void generalEmergency(CLPEvent clpEvent) {}
@Override
public void generalEmergencyLiberate(CLPEvent clpEvent) {}
@Override
public void engineOverload(CLPEvent clpEvent) {}
@Override
public void failedMachine(CLPEvent clpEvent) {}
@Override
public void tablePositioning(CLPEvent clpEvent) {}
@Override
public void positionTable(CLPEvent clpEvent) {}
@Override
public void securityCurtain(CLPEvent clpEvent) {}
@Override
public void securityCurtainLiberate(CLPEvent clpEvent) {}
@Override
public void feedPositionOK(CLPEvent clpEvent) {}
@Override
public void machineStopped(CLPEvent clpEvent) {}
@Override
public void machineInMotion(CLPEvent clpEvent) {}
@Override
public void resetFailed(CLPEvent clpEvent) {}
@Override
public void resetFailedOff(CLPEvent clpEvent) {}
@Override
public void machineOK(CLPEvent clpEvent) {}
@Override
public void machineOFF(CLPEvent clpEvent) {}
}
Agora veja como suas telas ficam com um código mais limpo:
Tela AppMenuPane
:
public class AppMenuPane extends JPanel {
// com o uso do CLPAdapter, basta sobrescrever apenas os métodos do eventos de interesse desta tela
private final CLPListener listener = new CLPAdapter() {
@Override
public void generalEmergency(CLPEvent event) {
disableButtons();
}
@Override
public void generalEmergencyApproved(CLPEvent event) {
enabledButtons();
}
@Override
public void securityCurtain(CLPEvent event) {
disableButtons();
}
@Override
public void securityCurtainApproved(CLPEvent event) {
try {
modbus.writeBoolean(4097, 9, false);
sleep(200);
} catch (IOException ex) {
// Logger.getLogger(AppMenuPane.class.getName()).log(Level.SEVERE, null, ex);
}
enabledButtons();
}
};
private JPanel bottomMenu;
private Protocol modbus;
public AppMenuPane() {
setLayout(new BorderLayout());
modbus = ActionMachineBuilder.getConnection();
modbus.disconnect();
bottomMenu = new MenuPanePane(new FormLayout("0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu,pref,0dlu","0dlu,pref,0dlu"));
add(bottomMenu, BorderLayout.SOUTH);
// neste bottomMenu tem os botões que acessam as outras telas do sistema
}
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
try {
CLPMonitor clpMonitor = CLPMonitor.getEagerInstance();
if (visible) {
enabledButtons();
modbus.connect();
clpMonitor.addCLPListener(listener);
} else {
modbus.disconnect();
clpMonitor.removeCLPListener(listener);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Tela IOPane
:
public class IOPane extends JPanel {
// com o uso do CLPAdapter, basta sobrescrever apenas os métodos do eventos de interesse desta tela
private final CLPListener listener = new CLPAdapter() {
@Override
public void generalEmergency(CLPEvent event) {
backButton.setEnabled(false);
}
@Override
public void generalEmergencyApproved(CLPEvent event) {
backButton.setEnabled(true);
}
@Override
public void securityCurtain(CLPEvent event) {
backButton.setEnabled(false);
}
@Override
public void securityCurtainApproved(CLPEvent event) {
try {
modbus.writeBoolean(4097, 9, false);
sleep(200);
} catch (IOException ex) {
// Logger.getLogger(IOPane.class.getName()).log(Level.SEVERE, null, ex);
}
backButton.setEnabled(true);
}
};
private JButton backButton;
private MenuPanePane bottomMenu;
private Protocol modbus;
public IOPane() {
setLayout(new BorderLayout());
modbus = ActionMachineBuilder.getConnection();
modbus.disconnect();
// aqui tem umas tabelas
bottomMenu = new MenuPanePane(new FormLayout("0dlu,pref,0dlu,pref,0dlu,fill:pref:grow,0dlu,pref,0dlu", "0dlu,pref,0dlu"));
add(bottomMenu, BorderLayout.SOUTH);
backButton = ButtonUtility.makeButton();
backButton.setText("Voltar");
backButton.setPreferredSize(new Dimension(bw, bh));
backButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
ModuleManager.getInstance().backToLastModule();
}
});
bottomMenu.add(backButton, new CellConstraints(8, 2));
}
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
try {
CLPMonitor clpMonitor = CLPMonitor.getEagerInstance();
if (visible) {
modbus.connect();
clpMonitor.addCLPListener(listener);
} else {
modbus.disconnect();
clpMonitor.removeCLPListener(listener);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Olá staroski,
Muito obrigada, implementei de acordo com suas orientações e está funcionando perfeitamente bem.
Agora estou com um outro “probleminha”, talvez até fuja do que vínhamos falando, mas enfim, em um deste eventos disparados eu abro um JDialog
e com a liberação deste eu abro outro JDialog
que ficará aguardando se o usuário quer prosseguir ou não, mas está acontecendo que quando abre a primeira vez (somente na primeira) ele não mostra os JLabel
somente os JButton
, aí depois nas outras vezes mostra certo, sabe me dizer o que seria? E olha que eu tenho mais dois JDialogs
que também abro no disparar de algum destes eventos, inclusive o que abre antes deste que dá o problema, mas em nenhum acontece isto …
Cria um novo tópico, explicando esse novo problema e posta os fontes.
Obrigada staroski.