3

着信クライアントが接続を確立しようとするたびに、executor プールを使用してソケット サーバーを開く新しいスレッドを開始する Java Swing アプリケーションがあります。

アプリケーションには 2 つのボタンが必要です。1 つはサーバーを開始するため、もう 1 つはサーバーを停止するためです。私が望むのは、サーバーのステータスを表示し、ステータスが変わるまで反対のボタンを無効にすることです。

これは私が今持っているものですが、スレッドが停止したときに EDT と通信する方法がわかりません。私にできることは、isRunning()方法を確認することだけです。

SwingWorker を使用した方が良いでしょうか?

public class ServerManager implements Runnable {

    private Executor mExecutor          = Executors.newSingleThreadExecutor();
    private ServerSocket mServerSocket  = null;
    private int mDefaultPort            = 43012;    
    private volatile boolean isRunning  = false;

    public ServerManager (int port){
        mDefaultPort = port;        
    }

    @Override
    public void run() {
        try {           
            mServerSocket = new ServerSocket(mDefaultPort);
            isRunning = true;
            while (isRunning){
                mExecutor.execute(new IncomingClientThread(mServerSocket.accept()));
            }
        } catch (IOException e) {           
            e.printStackTrace();
        } finally {
            if(mServerSocket != null){
                stop();
                System.out.println("Server closed");
            }
        }
    }

    public void stop(){
        try {
            mServerSocket.close();
            isRunning = false;
        } catch (IOException e) {
            throw new RuntimeException("Error closing server", e);
        }
    }

    public synchronized boolean isRunning() {
        return isRunning;
    }

    public int getServerPort (){
        return mDefaultPort;
    }
}

そして、これが GUI スレッドにあるものです。ボタンを 1 つだけ使用し、ボタンを押すたびにテキストを変更していますが、何らかの理由でサーバーが切断された場合、ボタンは同じままです。

connectButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                if(mServer.isStopped()){
                    new Thread (mServer).start();
                    connectButton.setText("Desconectar");
                    infoLabel.setText("Servidor online en IP: " + NetworkUtils.getLocalIpAddress()
                            + " puerto: " + mServer.getServerPort());
                    System.out.println(mServer.getIpAddress());
                }else{
                    mServer.stop();
                    connectButton.setText("Conectar");
                    infoLabel.setText("Offline");
                }
            }
        });

どんな助けでも大歓迎です!ありがとう。

4

2 に答える 2

4

考えられる解決策の 1 つは、SwingWorker の機能の一部を提供することです。つまり、SwingPropertyChangeSupport オブジェクトを提供し、GUI が状態の変化をリッスンして応答できるようにします。

例えば、

public class ServerManager implements Runnable {
  public static final String IS_RUNNING = "is running"; // for the Event's name
  private SwingPropertyChangeSupport propChngSupport = new SwingPropertyChangeSupport(this);
  private volatile boolean isRunning  = false;
  // other variables

  // addPropertyChangeListener(...) {...} goes here
  // removePropertyChangeListener(...)  {...} goes here

  public void setIsRunning(boolean isRunning) {
    boolean newValue = isRunning;
    boolean oldValue = this.isRunning;
    this.isRunning = isRunning;
    propChngSupport.firePropertyChange(IS_RUNNING, oldValue, newValue);    
  }

  public void run() {
    // ....
  }

  // other methods
}

重要なのは、setter メソッドの外で isRunning プロパティを決して変更しないことです。

于 2012-10-08T22:59:56.917 に答える
0

だから、@Hovercraft Full Of Eelsが推奨したように私がしたことは次のとおりです。

スレッド化されたクラスでは:

    public class ServerManager implements Runnable {

...     
        public static final String IS_RUNNING = "IS_RUNNING";

        private SwingPropertyChangeSupport pChange = new SwingPropertyChangeSupport(this);


        public void setIsRunning (boolean isRunning){
            boolean newValue = isRunning;
            boolean oldValue = this.isRunning;
            this.isRunning = isRunning;
            pChange.firePropertyChange(IS_RUNNING, oldValue, newValue);         
        }   

        public void addPropertyChangeListener (PropertyChangeListener listener){
            pChange.addPropertyChangeListener(IS_RUNNING, listener);
        }

        public void removePropertyChangeListener(PropertyChangeListener listener){
            pChange.removePropertyChangeListener(IS_RUNNING, listener);
        }
...
    }

そしてGUIクラスでは:

public class StatusPane extends JPanel{

    private ServerManager mServer;

    public StatusPane() {       
    ...
        mServer = new ServerManager();

        mServer.addPropertyChangeListener(new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
                System.out.println(evt.getPropertyName() + " cambia su valor de " 
                        + evt.getOldValue() + " a " + evt.getNewValue());
            }
        });
    ... 
    }
}
于 2012-10-09T09:08:36.567 に答える