0

This thread is updated for a reprex (minimal reproducible code) as per requested.

I'm building a multi-agent application with JADE for the first time, and I'm using NetBeans GUI Builder (Java Swing) for that.

In short there are three classes (MainContainer.java, ClientContainer.java and ClientAgent.java) and one library (jade.jar).

After launch, I seem to send data from the Agent to the Container normally (I can print the values in the console, Container side), however, I cannot:

statusArea.append(message)
statusArea.setText(message)

on the JTextArea (statusArea) when I invoke the method viewMessage(String message) from the Agent Class for some reason, I even tried using a SwingWorker.

can print on console, but not on the GUI

Here's a minimal reproducible code of what I'm trying to achieve:

ClientAgent.java:

    public class ClientAgent {

    public ClientAgent() {
        // Instance of the client container
        ClientContainer gui = new ClientContainer();

        // Setting this agent to it's container
        gui.setClientAgent(this);

        // Sending data to GUI container through viewMessage(String str) method
        gui.viewMessage("-- Client init");
        gui.viewMessage("Scope: " + "AID");

    }

    public static void main(String[] args) throws InterruptedException {

        ClientAgent obj = new ClientAgent();

    }}

ClientContainer.java:

    import javax.swing.SwingWorker;

    public class ClientContainer extends javax.swing.JFrame {

    ClientAgent clientAgent;

    public ClientContainer() {

        initComponents();
    }

    public ClientAgent getClientAgent() {
        return clientAgent;
    }

    // Setter to set this container as the UI for the agent
    public void setClientAgent(ClientAgent clientAgent) {
        this.clientAgent = clientAgent;
    }

    // Method that displays data on statusArea from ClientAgent.java class
    public void viewMessage(String message) {

        SwingWorker<Void, String> Worker = new SwingWorker<Void, String>() {
            @Override
            protected Void doInBackground() throws Exception {
                Thread.sleep(550);
                System.out.println(message);
                statusArea.append(message + "\n");
                return null;
            }
        };
        Worker.execute();
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane2 = new javax.swing.JScrollPane();
        statusArea = new javax.swing.JTextArea();

        setTitle("Client");

        statusArea.setEditable(false);
        statusArea.setColumns(20);
        statusArea.setRows(5);
        jScrollPane2.setViewportView(statusArea);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 451, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 350, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

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

    public static void main(String args[]) {

        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Flat Light".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(ClientContainer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }

        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                // Starting the client container
                new ClientContainer().setVisible(true);
            }
        });

    }

    // Variables declaration - do not modify                     
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JTextArea statusArea;
    // End of variables declaration }

In hopes that no body that compiles this code will face any trouble, I compiled it on my machine beforehand.

Thanks again.

[EDIT]: After applying Abra's suggestion I added this to my SwingWorker inside the viewMessage method in the ClientContainer

    public void viewMessage(String message) {

        SwingWorker<Void, String> Worker = new SwingWorker<Void, String>() {
            @Override
            protected Void doInBackground() throws Exception {
                return null;
            }

            @Override
            protected void done() {

                System.out.println("Inside done function");
                System.out.println(message);
                statusArea.setText(message + "\n");
            }

        };
        Worker.execute();
    }

Then I started an instance of ClientAgent in a jButton like this:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         

        clientAgent = new ClientAgent();

    }  

Started the ClientContainer then the ClientAgent to see what happens, still prints on the console and not on the JTextArea.

quaksil
  • 1
  • 1
  • You're likely running afoul of Swing threading rules. Swing GUI's are single-threaded, and so any long-running task must run in a background thread. The details of the problem and the solution can be found here: [Lesson: Concurrency in Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/). – Hovercraft Full Of Eels Feb 08 '22 at 21:07
  • Ah, I see that you *are* using a SwingWorker, but you're using it wrong. You should not update the Swing GUI directly from the doInBackground method. That goes totally against what this is for since you're trying to update the GUI off the event thread. Use the publish and process method pair for this. – Hovercraft Full Of Eels Feb 08 '22 at 21:10
  • @HovercraftFullOfEels I tried a StringWorker (Maybe not conveniently I suppose) but I also forgot to mention that I also tried to repaint, revalidate and validate, that didn't work. Furthermore, the same application works perfectly fine when it is not using a .form structure to accompany the Java class, as in the GUI is coded in a single java class and so the data is correctly displayed on the JTextArea from another class, it is only when I create a new JFrame from and use the Palette and inject my code that this doesn't work. – quaksil Feb 08 '22 at 21:15
  • For best help, consider creating and posting a [mre], a very small program that compiles and runs and shows us your problem. It should be a simplified extraction of your current program, should not require any resources that we don't have (images, database,...) again should be as simple as possible and yet be runnable for us without our having to alter it. Yes, this is asking work from you, but if you do this then we will easily and quickly be able to understand your problem and thus be able to help you. – Hovercraft Full Of Eels Feb 08 '22 at 21:15
  • You've got a problem in code, likely in code not shown. There *are* definite threading problems with your SwingWorker attempt (as noted above), but who knows what else might be wrong, such as updating the wrong reference. Again, the [mre] is your best bet at getting an answer. – Hovercraft Full Of Eels Feb 08 '22 at 21:16
  • @HovercraftFullOfEels Alright, I'm on it, thanks for the reply! – quaksil Feb 08 '22 at 21:20
  • Shall I update this thread, or make a new one and post it? – quaksil Feb 08 '22 at 21:21
  • Definitely update this question. – Hovercraft Full Of Eels Feb 08 '22 at 21:31
  • *"In hopes that no body that compiles this code will face any trouble"* -- nobody can, in fact, compile the code. It requires classes that we don't have, such as GuiAgent (whatever that is): `ClientAgent extends GuiAgent`. Please read or re-read the [mre] link and re-try. It should all be in one file in fact which can hold several classes, the main class holding the main method. – Hovercraft Full Of Eels Feb 08 '22 at 23:27
  • And what is `new ExtendedProperties();`? Is this even needed? – Hovercraft Full Of Eels Feb 08 '22 at 23:28
  • You also never call key methods in the code posted.... – Hovercraft Full Of Eels Feb 08 '22 at 23:35
  • @HovercraftFullOfEels Thanks for replying again, well as I said above, I believe all that's needed is add the jade.jar library in order for this code to compile and also do the necessary imports (which I thought I should get rid of). I am using the Jade Framework which can be found here: https://jade.tilab.com/ GuiAgent is a class in this framework, and so do everything else in order to launch a new container inside of Jade. – quaksil Feb 08 '22 at 23:55
  • Your MRE should not require external libraries, not just for us, but it is best to create code that can be mocked and tested without libraries for your own debugging defforts. – Hovercraft Full Of Eels Feb 08 '22 at 23:58
  • I appreciate you guiding me here, I updated the post again, in hopes that this is what's required. It's frustrating as this is the first time I'm working with all of this. – quaksil Feb 09 '22 at 01:06
  • Add method `done` to your `SwingWorker`. Remove the line `statusArea.append(message + "\n");` from method `doInBackground` and put it in method `done` and you are "done". – Abra Feb 09 '22 at 03:22
  • @Abra Thanks for your suggestion, however, I've tried that and it did not work. (I also tried making a new button and on action, create an instance of the ClientAgent class, still didn't work). – quaksil Feb 09 '22 at 08:05
  • It worked for me on the code you posted in your question. Of course you didn't explain how you test your code so I assume that your way of testing is different to mine and hence it doesn't work for you. Both classes in your question have a `main` method. So [edit] your question and explain how you test the [mcve] that you posted. – Abra Feb 09 '22 at 08:53
  • Alright, I updated the thread. – quaksil Feb 09 '22 at 10:51

0 Answers0