Swing GUI客户端侦听器未响应远程RMI属性的更新

时间:2011-12-01 15:06:30

标签: swing callback listener rmi jtree

当我对其模型进行显式调用时(在我向其添加了一些新节点后进行的调用),让JTree重绘时遇到了一些麻烦。

最初工作正常的代码现在因应用程序导出到RMI而失败。

我将DefaultTreeModel对象存储在Controller类中,该类是一个远程对象。

我使用tree.addModel(controller.getModel())将DefaultTreeModel对象添加到客户端的JTree中;

我使用订阅客户端GUI上的按钮的ActionListener来调用Controller中执行“添加新节点”操作的方法。

我使用TreeModelListener将消息打印到屏幕以证明模型侦听器已经触发。

客户端Swing侦听器是否无法通过RMI工作

我设法重现了这个问题。我提供了完整性代码,但预计有人可以根据经验给出答案。

服务器驱动程序类:

package server;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import client.controller.TestTreeControllerService;

import server.controller.TestTreeControllerImpl;


public class TestTreeServerStart {

    /**
     * @param args
     */
    public static void main(String[] args) {
        new TestTreeServerStart();

    }

    public TestTreeServerStart() {

        try {

            LocateRegistry.createRegistry(1099);

            TestTreeControllerService c = new TestTreeControllerImpl();

             Registry registry = LocateRegistry.getRegistry();
             registry.rebind("TestTreeControllerService", c);

            System.out.println("Started the RMI Server");
        }
        catch (RemoteException e) {
            System.out.println(e.getMessage());
        }
    }

}

服务器控制器实施类:

package server.controller;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import client.controller.TestTreeControllerService;



@SuppressWarnings("serial")
public class TestTreeControllerImpl extends UnicastRemoteObject implements TestTreeControllerService {

    /**
     * 
     */
    //private static final long serialVersionUID = -8137864611400855504L;
    private DefaultTreeModel m ;


    public DefaultTreeModel getModel() {

        return m;
    }


    public TestTreeControllerImpl() throws RemoteException {

        super();
        m = new DefaultTreeModel(new DefaultMutableTreeNode("Root"));

    }

    public void addNodeAction() throws RemoteException {
        DefaultTreeModel m = (DefaultTreeModel) getModel();
        DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("New Node");
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) m.getRoot();
        root.add(newNode);
        //m.insertNodeInto(newNode, (DefaultMutableTreeNode) m.getRoot(), m.getChildCount(m.getRoot()));
        m.nodeStructureChanged(root);

    }

}

客户端驱动程序类:

package client;
import java.rmi.Naming;
import java.rmi.RemoteException;

import client.controller.TestTreeControllerService;
import client.view.TreeTestClient;



public class TreeTestClientStart {

    /**
     * @param args
     */
    public static void main(String[] args) {


            try {
                TestTreeControllerService c = (TestTreeControllerService) Naming.lookup("rmi://localhost:1099/TestTreeControllerService");
                 new TreeTestClient(c);
            }
            catch(RemoteException e) {
                System.out.println("Remote service not found: " + e.getLocalizedMessage());
            }
            catch (Exception e) {
                System.out.println("Splat");
            }
    }

}

客户端控制器界面:

package client.controller;
import javax.swing.tree.DefaultTreeModel;


public interface TestTreeControllerService extends java.rmi.Remote {


    public DefaultTreeModel getModel() throws java.rmi.RemoteException;

    public void addNodeAction() throws java.rmi.RemoteException;
}

客户端用户界面:

package client.view;
import java.awt.Dimension;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;

import client.controller.TestTreeControllerService;
import client.view.action.AddNodeAction;
import client.view.action.RefreshTreeAction;



public class TreeTestClient {

    private JTree t;
    private TestTreeControllerService c;

    public JTree getTree() {
        return t;
    }

    public TestTreeControllerService getController() {
        return c;
    }

    public void setTree(JTree tIn) {
        t = tIn;
    }

    public TreeTestClient(TestTreeControllerService cIn) {

        //Add controller
        try {
            c = cIn;

            //Draw Frame & Panel  - set dimensions
            JFrame f = new JFrame();
            f.setSize(new Dimension(800,600));
            JPanel p = new JPanel();
            p.setSize(new Dimension(800,600));

            //Create a tree and add the Model from the Controller to it
            t = new JTree();
            t.setModel(c.getModel());


            //Try a Tree Model Listener
            t.getModel().addTreeModelListener(new RefreshTreeAction(this));

            //Add listener to a button which adds nodes to the tree when clicked
            JButton addNode = new JButton("Add node");
            addNode.addActionListener(new AddNodeAction(this));

            JScrollPane s = new JScrollPane(t);


            p.add(s);
            p.add(addNode);

            p.setVisible(true);
            f.add(p);
            f.setVisible(true);
    }
    catch(Exception e) {
        System.out.println("Splat");
    }
    }

}

* 客户端“添加节点”操作侦听器(在控制器中调用添加操作)*

package client.view.action;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.RemoteException;

import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import client.view.TreeTestClient;


public class AddNodeAction implements ActionListener {

    private TreeTestClient treeTest;

public AddNodeAction(TreeTestClient treeTestIn) {
    treeTest=treeTestIn;
}
@Override
public void actionPerformed(ActionEvent arg0) {

    try {
        treeTest.getController().addNodeAction();
    } catch (RemoteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

}

客户端“刷新操作”树监听器(打印到屏幕以证明监听器已解雇)

package client.view.action;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;

import client.view.TreeTestClient;


public class RefreshTreeAction implements PropertyChangeListener, TreeModelListener {

    private TreeTestClient treeTest;

    public RefreshTreeAction(TreeTestClient treeTestIn) {
        treeTest = treeTestIn;
    }
    private void refreshTree() {
        System.out.println("Refresh tree fired");

    }
    @Override
    public void treeNodesChanged(TreeModelEvent arg0) {
        refreshTree();

    }

    @Override
    public void treeNodesInserted(TreeModelEvent arg0) {
        refreshTree();
    }

    @Override
    public void treeNodesRemoved(TreeModelEvent arg0) {
        refreshTree();

    }

    @Override
    public void treeStructureChanged(TreeModelEvent arg0) {
            refreshTree();

    }
    @Override
    public void propertyChange(PropertyChangeEvent arg0) {
        refreshTree();

    }

}

2 个答案:

答案 0 :(得分:2)

服务器导出的TreeModel作为客户端自己的副本序列化到客户端。服务器不知道客户端副本发生了什么,客户端也不知道服务器副本发生了什么。它们不是同一个对象。

答案 1 :(得分:1)

通过将以下代码添加到订阅GUI上的新按钮的ActionListener,我可以通过单击按钮检查模型的内容:

                //Loop contents of model attached to Client Tree
                for (int i=0; i<t.getModel().getChildCount(t.getModel().getRoot()); i++) {
                        System.out.println("From Tree: Row #" + i + ": " + t.getModel().getChild(t.getModel().getRoot(), i));
                }

                //Loop contents of model object stored in Controller
                try {
                    for (int i=0; i<c.getModel().getChildCount(c.getModel().getRoot()); i++) {
                        System.out.println("From Controller: Row #" + i + ": " + c.getModel().getChild(c.getModel().getRoot(), i));
                    }
                } catch (RemoteException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

我发现对客户模型的引用与Controller的模型对象中维护的状态不同。客户端循环中没有输出,但Controller的循环给出了正确的状态。

我随后在GUI中添加了一个Swing Timer来刷新树的模型以匹配Constructor的模型。随后是更新的GUI类和GUI刷新操作,其中包括:

更新了用户界面:

package client.view;
import java.awt.Dimension;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.Timer;

import client.controller.TestTreeControllerService;
import client.view.action.AddNodeAction;
import client.view.action.GUIRefreshAction;
import client.view.action.RefreshTreeAction;



public class TreeTestClient {

    private JTree t;
    private TestTreeControllerService c;

    public JTree getTree() {
        return t;
    }

    public TestTreeControllerService getController() {
        return c;
    }

    public void setTree(JTree tIn) {
        t = tIn;
    }

    public TreeTestClient(TestTreeControllerService cIn) {

        //Add controller
        try {
            c = cIn;

            //Draw Frame & Panel  - set dimensions
            JFrame f = new JFrame();
            f.setSize(new Dimension(800,600));
            JPanel p = new JPanel();
            p.setSize(new Dimension(800,600));

            //Create a tree and add the Model from the Controller to it
            t = new JTree();
            t.setModel(c.getModel());

            //Try a listener that doesn't use the Remote object
            t.addTreeSelectionListener(new RefreshTreeAction(this));

            //Try a property change listener on the TreeModel   
            t.addPropertyChangeListener("treeModel", new RefreshTreeAction(this));

            //Try a Tree Model Listener
            t.getModel().addTreeModelListener(new RefreshTreeAction(this));

            //Add listener to a button which adds nodes to the tree when clicked
            JButton addNode = new JButton("Add node");
            addNode.addActionListener(new AddNodeAction(this));

            JScrollPane s = new JScrollPane(t);

            //Add a GUI redraw timer
            Timer timer = new Timer(1000, new GUIRefreshAction(this));
            timer.setInitialDelay(1);
            timer.start();

            p.add(s);
            p.add(addNode);

            p.setVisible(true);
            f.add(p);
            f.setVisible(true);
    }
    catch(Exception e) {
        System.out.println("Splat");
    }
    }

}

GUI刷新侦听器类

package client.view.action;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.RemoteException;

import client.view.TreeTestClient;

public class GUIRefreshAction implements ActionListener {

    private TreeTestClient client;

    public GUIRefreshAction(TreeTestClient clientIn) {
        client = clientIn;
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        //Update the Tree's Model to match latest on Server
        try {
            client.getTree().setModel(client.getController().getModel());
        } catch (RemoteException e1) {
            e1.printStackTrace();
        }

    }

}

我希望这可以帮助对RMI客户端Swing GUI有相同要求的人根据服务器上的更改进行更新。