Building Multi-Agent Systems with JADE
8. Building agent with integrated GUI
In the Java programming language, a GUI runs on its own thread (the event-dispatching thread) that allows it to handle and react promptly to events that are generated whenever the user interacts with the GUI via a component such as pressing a button or resizing the window.. On the other hand, an agent program runs on its own execution thread which allows it to handle its behaviours. Because it is not efficient to let one thread call directly the methods of the other thread, JADE has provided an appropriate mechanism to manage interactions between the two threads when integrating a GUI with an agent.
The mechanism is simply based on event passing. Let's see how this mechanism works by considering the two directions of the interaction beween a GUI and an agent.
Let's view now how this works trough the version 3 of our bank example. Under the directory Bank-3-Gui, you have the two files BankClientAgent that contains the agent program and the BankAgentGui that contains the program of the integrated GUI. Note that the BankServerAgent has no GUI integrated. Here are the key points you must know when writing your GUI program. We have marked in bold in the following fragment of code took from the BankAgentGui class, these important aspects:
class BankAgentGui extends JFrame implements ActionListener, BankVocabulary {
Object[] actions = {"","New Account","Deposit","Withdrawal", "Balance","Operations"};
...
private JButton ok, cancel, quit;
private BankClientAgent myAgent; // Reference to the agent class
public BankAgentGui(BankClientAgent a) {myAgent = a; // provide the value of the reference of BankClientAgent class here
...
}public void actionPerformed(ActionEvent ae) {
//Process the event according to it's source
if (ae.getSource() == quit) {
shutDown();
}
else if (ae.getSource() == ok) {if (menu.getSelectedItem().equals(actions[0])) {
alert("Select an action in the menu");
}
else if (menu.getSelectedItem().equals(actions[1])) {
GuiEvent ge = new GuiEvent(this, NEW_ACCOUNT);
myAgent.postGuiEvent(ge);
}
else if (menu.getSelectedItem().equals(actions[2]) ||
menu.getSelectedItem().equals(actions[3])) {
...
try {
float amount = Float.parseFloat(input.getText());
int type = menu.getSelectedItem().equals(actions[2])?
DEPOSIT : WITHDRAWAL;
GuiEvent ge = new GuiEvent(this, type);
ge.addParameter(accounts.get(acList.getSelectedIndex()));
ge.addParameter(new Float(amount));
myAgent.postGuiEvent(ge);
}
catch (Exception ex) { alert("Invalid input. Operation aborted!"); }
}
else if (menu.getSelectedItem().equals(actions[4]) ||
menu.getSelectedItem().equals(actions[5]) &&
status != IN_LINE) {
...
if (status == WAIT_CONFIRM) {
status = IN_LINE;
cancel.setEnabled(false);
GuiEvent ge = new GuiEvent(this, type);
ge.addParameter(accounts.get(acList.getSelectedIndex()));
myAgent.postGuiEvent(ge);
}
}
}
else if (ae.getSource() == cancel && status != IN_LINE) {
status = IN_PROCESS;
cancel.setEnabled(false);
msg.setText("Operation canceled!");
}
}
}// class BankAgentGui
The BankAgentGui class implements the ActionListener interface. It has a private attribute myAgent that is a reference to the owner agent class. This reference is obtained via the constructor of the class which takes as parameter a BankClientAgent object. This way, in the BankClientAgent class within the setup() method, the agent just calls the constructor of the BankAgentGui class, passing itself in parameter to it as follows:
public class BankClientAgent extends GuiAgent implements BankVocabulary {
...
transient protected BankAgentGui myGui; // Reference to the gui
protected void setup() {
....
// Instanciate the gui
myGui = new BankAgentGui(this);
myGui.setVisible(true);
}...
protected void onGuiEvent(GuiEvent ev) {
// Process the event according to it's type
command = ev.getType();
if (command == QUIT) {
...
}
if (command == NEW_ACCOUNT) {
createAccount();
}
else if (command == DEPOSIT || command == WITHDRAWAL) {
Account acc = (Account)ev.getParameter(0);
float amount = ((Float)ev.getParameter(1)).floatValue();
requestOperation(acc, amount);
}
...
}}
When the agent receives an event posted by the agent, it tests the type of the event by calling the method getType() on the GuiEvent object and processes the event by calling the appropriate handler. This requires you to define the types of the events that the agent is supposed to receive from the GUI. The events must be integer constants. In the above example, we defined the events QUIT, NEW_ACOOUNT, DEPOSIT AND WITHDRAWAL that are all integer constants. They are defined within the BankVocabulary interface which both the BankAgentGui and BankClientAgent classes implement. Notice that instead of defining them in an interface, you may also define them directly within the agent class and access them from the GUI via the unique reference to the agent class. Once the agent has identified the appropriate event with the GuiEvent object it can then retreive all the parameters that it contains by calling it'sgetParameter() method, assuming that these parameters had been added to the GuiEvent object before it was posted by the GUI.
- Top
- Previous
- Next