我已经看到很多类似的问题,但是我仍然无法理解我的实现到底出了什么问题。我正在尝试使用RMI构建客户端服务器应用程序以实现通信。它应该成为一种游戏,但是现在我只专注于基本的客户端界面操作,例如登录,玩家列表等。在客户端,我有一个摆动的GUI,除其他外,该GUI显示当前在服务器上注册的玩家列表。每当服务器上有新玩家注册时,服务器会将注册玩家的完整列表发送给所有注册客户端。然后,客户必须清除其播放器列表内容,并再次用接收到的值填充它。收到的列表是IPlayer的数组,它是Player类导出的远程接口。要在客户端上更新JList,请使用以下updatePlayerList()方法:class BrowseScreen extends Screen implements ActionListener, MouseListener, ListSelectionListener {private JList<String> playerList;...@Overrideprotected void init() { setLayout(new BorderLayout()); ... playerList = new JList<String>(); playerList.setModel(new DefaultListModel<String>()); JScrollPane playerScroll = new JScrollPane(playerList); playerScroll.setBorder(BorderFactory.createTitledBorder(null, "Players", TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION)); add(playerList, BorderLayout.EAST); ...}public void updatePlayerList(IPlayer[] list) { try { DefaultListModel<String> model = (DefaultListModel<String>) playerList.getModel(); model.clear(); for (IPlayer p : list) { model.addElement(p.getName()); // remote method invocation } System.out.println(model); // added to check the content of the list model } catch (RemoteException e) { // TODO auto-generated catch block e.printStackTrace(); }}...}(注意:Screen只是一个JPanel扩展名,我用来定义我的应用程序中的不同屏幕,例如登录名,房间列表等。)当我尝试打开多个客户端时,发生的情况是随机客户端上的列表完全空白,并且每次我使用其中一个客户端登录/注销时,JList s更新和其他一些(仍然是随机的)客户端最终都会一个空列表。列表模型应使用新数据正确更新,因为我在控制台上看到了正确的输出。我阅读了有关“ JList无法更新”问题的一些答案,最常见的答案是应该在EDT线程中执行模型更新。我不确定自己是否正确执行此操作,但是我有以下主要信息:public static void main(String[] args) throws RemoteException { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { Client client = new Client(); GuiClient gui = new GuiClient(client); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } });}(注意:GuiClient对象使用对Client的引用来执行涉及与服务器交互的复杂操作。所有用户界面组件(例如显示前一个JFrame的Screen)均由)我希望我能很好地解释这种情况(我是Stackoverflow的新手);我的项目现在有很多课程,在这里我无法完整介绍。任何帮助都非常感激:)编辑:使用GuiClient执行RMI调用已解决了问题。这就是我更改SwingWorker方法的方式:public void updatePlayerList(IPlayer[] list) { new ReadPlayerList(list, playerList).execute();}这是updatePlayerList()类,它扩展了ReadPlayerList:public class ReadPlayerList extends SwingWorker<Void, String> {private IPlayer[] list;private JList<String> playerList;private boolean listCleared;public ReadPlayerList(IPlayer[] list, JList<String> playerList) { this.list = list; this.playerList = playerList; listCleared = false;}@Overrideprotected Void doInBackground() throws Exception { for (IPlayer p : list) { publish(p.getName()); } return null;}@Overrideprotected void process(List<String> chunks) { DefaultListModel<String> model = (DefaultListModel<String>) playerList.getModel(); if (!listCleared) { model.clear(); listCleared = true; } for (String name : chunks) { model.addElement(name); }}}这解决了JList不显示其内容的问题。现在的挑战是确保此更新操作始终是原子的。我猜我将不得不编写某种“线程安全的JList”扩展,但这是另一回事了:) (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 您有一个复杂的系统,该系统涉及客户端与服务器之间的通信,并且您会看到随机的不可预测的错误。总而言之,您会看到线程问题的所有经典症状。是的,您可以在Swing线程上正常启动GUI,但这可能不是问题所在。很有可能(我不得不猜测),这是因为您没有通过RMI通信正确处理线程。您是否正在使用SwingWorker执行此操作?如果我是您,我会这样做,以便您可以将线程后台中的通信代码与Swing事件线程隔离开,从而可以轻松地使通信代码与EDT上的Swing代码进行通信。如果您需要更多具体的帮助,则需要显示更多内容,最好发布尽可能靠近minimal example program的程序。 (adsbygoogle = window.adsbygoogle || []).push({});
07-24 09:15