2017-02-24 7 views
1

Javaでプログラミングするのは初めてではありませんが、私はJavaプログラムでスレッドを使うのが初めてです。私は学校に通っていて、スレッドとJavaネットワーキングの章を終えました。私はクライアントのGUIをプログラミングして、ローン情報(年間金利、年数、ローン金額)をサーバーに送信していました。サーバーには独自のGUIがあり、毎月の支払い額とローンの合計支払い額が計算され、クライアントに送り返され、ユーザーに表示され、サーバーGUIが更新されます。JavaFXの異なるクラスファイル間でスレッドを使用する方法はありますか?

本は、一例として、このコードを持っています

public class Server extends Application { 
/** Variables */ 
private TextArea textArea = new TextArea(); 
private double rate; 
private int year; 
private double loan; 

public void start(Stage serverStage) 
{ 
    // Creating server GUI 
    Scene scene = new Scene(new ScrollPane(textArea), 400, 200); 
    serverStage.setTitle("Server"); 
    serverStage.setScene(scene); 
    serverStage.show(); 

    new Thread(() ->{ 

     try 
     { 
      // create server socket 
      ServerSocket serverSocket = new ServerSocket(8000); 
      textArea.appendText("Server started at " + new Date() + "\n"); 

      while(true) 
      { 
       // listen for a connection request 
       Socket socket = serverSocket.accept(); 

       Platform.runLater(() -> { 
        InetAddress inetAddress = socket.getInetAddress(); 
        textArea.appendText("Connected to " + inetAddress.getHostAddress() + " at " + new Date() + "\n"); 
       }); 


       // create and start a new thread for every connection 
       new Thread(new HandleAClient(socket)).start(); 

      } 
     } 
     catch(IOException ex) 
     { 
      ex.printStackTrace(); 
     } 
    }).start(); 
} 

class HandleAClient implements Runnable { 

    private Socket socket; // A connected socket 
    private double rate; 
    private int year; 
    private double loan; 

    /** costruct a thread */ 
    public HandleAClient(Socket socket) 
    { 
     this.socket = socket; 
    } 

    /** run a thread */ 
    public void run(){ 
     try 
     { 
      // create data input and output streams 
      DataInputStream inputFromClient = new DataInputStream(socket.getInputStream()); 
      DataOutputStream outputToClient = new DataOutputStream(socket.getOutputStream()); 

      // continuously serve the client 
      while(true) { 
       // read data from client 

       rate = inputFromClient.readDouble(); 
       year = inputFromClient.readInt(); 
       loan = inputFromClient.readDouble(); 


       // calculate monthly payment of loan and total payment 

       outputToClient.writeDouble(calculateMonthlyPayment(rate, year, loan)); 
       outputToClient.writeDouble(calculateTotalPayment(rate, year, loan)); 

       Platform.runLater(() -> { 
        textArea.appendText("The rate is : " + rate + "\n"); 
        textArea.appendText("The number of years is: " + year + "\n"); 
        textArea.appendText("Loan amount is: " + loan + "\n\n");}); 




      } 
     } 
     catch(IOException e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

// calculateMonthlyPayment method calculates the monthly payment of a loan given 
// the required information 

public double calculateMonthlyPayment(double interestRate, int years, double loanAmt) 
{ 
    double monthlyRate; 
    int termInMonths; 
    double monthlyPayment; 

    // Convert the interest rate to a decimal 
    interestRate = interestRate/100; 

    // convert annual interest rate to monthly interest rate 
    monthlyRate = interestRate/12; 

    // calculate the term in months which is years * 12 
    termInMonths = years * 12; 

    monthlyPayment = (loanAmt*monthlyRate)/(1-Math.pow(1+monthlyRate, -termInMonths)); 

    return monthlyPayment; 
} 



// method that calculates and returns the total payment of the loan 
public double calculateTotalPayment(double rate, int year, double loan) 
{ 
    double totalPayment; 
    double monthlyPay; 

    monthlyPay = calculateMonthlyPayment(rate, year, loan); 


    totalPayment = monthlyPay * 12 * year; 

    return totalPayment; 
    } 

} 

あなたがのコード例にあるように、彼ら(本の著者は)のテキストを追加できるようにする新しいスレッドを使用しますサーバーGUI。ただし、複数のクライアントを処理できるようにするには、whileループ内に新しいスレッドを作成して、個々のクライアントを処理します。

私は独立したJavaクラスとしてHandleAClientクラスを作成する代わりに、サーバ・クラスでそれを挿入しようとしたが、これはPlatform.runLaterコード

Platform.runLater(() -> { 
        textArea.appendText("The rate is : " + rate + "\n"); 
        textArea.appendText("The number of years is: " + year + "\n"); 
        textArea.appendText("Loan amount is: " + loan + "\n\n");}); 

だから私の質問に更新されていないサーバーのGUIになりました: HandleAClientクラスがServerクラスの内側にあり、HandleAClientクラスがServerを拡張する別のJavaクラスファイルにあるときには、なぜ動作しますか私はスレッドで何かをしなければならないと思いますか? HandleAClientクラスを独自のJavaクラスファイルに含めることができるように変更するにはどうすればよいですか?

私は興味があり、スレッドの仕組みをよく理解しようとしています。前もって感謝します。

更新 これは私にとっては役に立たないスタンドアロンクラスです。私はServerクラスを拡張し、TextAreaフィールドをServerクラスで保護しました。

class HandleAClient extends Server implements Runnable { 

private Socket socket; // A connected socket 
private double rate; 
private int year; 
private double loan; 


public HandleAClient(Socket socket) 
{ 
    this.socket = socket; 
} 

/** run a thread */ 
public void run(){ 
    try 
    { 
     // create data input and output streams 
     DataInputStream inputFromClient = new DataInputStream(socket.getInputStream()); 
     DataOutputStream outputToClient = new DataOutputStream(socket.getOutputStream()); 

     // continuously serve the client 
     while(true) { 
      // read data from client 

      rate = inputFromClient.readDouble(); 
      year = inputFromClient.readInt(); 
      loan = inputFromClient.readDouble(); 


      // calculate monthly payment of loan and total payment 

      outputToClient.writeDouble(calculateMonthlyPayment(rate, year, loan)); 
      outputToClient.writeDouble(calculateTotalPayment(rate, year, loan)); 

      Platform.runLater(() -> { 
       textArea.appendText("The rate is : " + rate + "\n"); 
       textArea.appendText("The number of years is: " + year + "\n"); 
       textArea.appendText("Loan amount is: " + loan + "\n\n");}); 

     } 
    } 
    catch(IOException e) 
    { 
     e.printStackTrace(); 
    } 
    } 
} 

Platform.runLaterのコードは、クラスがServerクラスの内部にあるときのようにサーバーGUIに表示されません。なぜこれが本質的に起こるのか理解したい。

+0

私は質問を理解しているか分かりません。 'HandleAClient'クラスは、アクセスする必要がある' Server'クラスのすべてのフィールドにアクセスできる限り、スタンドアロンクラスとして正常に動作するはずです(本当に内部クラスとトップレベルクラスの唯一の違いは内部クラスがその周囲のクラスのフィールドにアクセスできること)。あなたがトップレベルのクラスとしてそれを実装したとき、どのように 'textArea'へのアクセス権を与えましたか?動作しなかったスタンドアロン(最上位)の 'HandleAClient'クラスのフルバージョンを投稿できますか? –

+0

はい元の投稿を更新して、うまくいかなかったクラスを追加しました。基本的には、ServerクラスでtextAreaフィールドをprotectedにし、ServerクラスをHandleAClientクラスに拡張しました。 – j2k1218

+0

ここで更新するテキストエリアは、UIに表示するテキストエリアとは異なります。 UIを表示している 'Server'インスタンスに属するインスタンスを更新する必要があります。 –

答えて

0

あなたはそれらを作成しServerオブジェクトに属するテキストエリア更新するために、あなたのHandleAClientのインスタンスが必要になります。そのServerインスタンスに属するtextAreaがUIに表示されているものですが。あなたが持っている設定では、各のインスタンスはそれぞれを更新します。もちろん、それらのどれも表示されていません。

HandleAClientServerに拡張することは実際にはわかりません。あなたがしなければならないことは(その継承を持っているかどうかにかかわらず)HandleAClientServerに属するテキスト領域を更新する方法を提供することです。最も簡単な(しかし、必ずしも最良の)方法はただHandleAClientインスタンスにそのテキスト領域を通過させることである。

class HandleAClient implements Runnable { 

    private Socket socket; // A connected socket 
    private double rate; 
    private int year; 
    private double loan; 

    private final TextArea textArea ; 

    public HandleAClient(Socket socket, TextArea textArea) 
    { 
     this.socket = socket; 
     this.textArea = textArea ; 
    } 

    /** run a thread */ 
    public void run(){ 
     try 
     { 
      // create data input and output streams 
      DataInputStream inputFromClient = new DataInputStream(socket.getInputStream()); 
      DataOutputStream outputToClient = new DataOutputStream(socket.getOutputStream()); 

      // continuously serve the client 
      while(true) { 
       // read data from client 

       rate = inputFromClient.readDouble(); 
       year = inputFromClient.readInt(); 
       loan = inputFromClient.readDouble(); 


       // calculate monthly payment of loan and total payment 

       outputToClient.writeDouble(calculateMonthlyPayment(rate, year, loan)); 
       outputToClient.writeDouble(calculateTotalPayment(rate, year, loan)); 

       Platform.runLater(() -> { 
        textArea.appendText("The rate is : " + rate + "\n"); 
        textArea.appendText("The number of years is: " + year + "\n"); 
        textArea.appendText("Loan amount is: " + loan + "\n\n");}); 

      } 
     } 
     catch(IOException e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

そしてもちろん、それは感じている

while(true) 
{ 
    // listen for a connection request 
    Socket socket = serverSocket.accept(); 

    Platform.runLater(() -> { 
     InetAddress inetAddress = socket.getInetAddress(); 
     textArea.appendText("Connected to " + inetAddress.getHostAddress() + " at " + new Date() + "\n"); 
    }); 


    // create and start a new thread for every connection 
    new Thread(new HandleAClient(socket, textArea)).start(); 

} 

としてあなたはそれを修正ServerHandleAClientクラス(通信を担当)がTextArea(UI固有のもの)への参照に依存するようにすることは、少し不自然です。より自然なアプローチは次のとおりです。

私はおそらく率、年、およびローン表現するために単純なクラスを定義します

public class LoanData { 

    private final double rate ; 
    private final int year ; 
    private final double loan ; 

    public LoanData(double rate, int year, double loan) { 
     this.rate = rate ; 
     this.year = year ; 
     this.loan = loan ; 
    } 

    public double getRate() { 
     return rate ; 
    } 
    public int getYear() { 
     return year ; 
    } 
    public double getLoan() { 
     return loan ; 
    } 
} 

をそして融資データを処理するためのHandleAClientクラスにConsumer<LoanData>を与える:

class HandleAClient implements Runnable { 

    private Socket socket; // A connected socket 

    private final Consumer<LoanData> dataProcessor ; 

    public HandleAClient(Socket socket, Consumer<LoanData> dataProcessor) 
    { 
     this.socket = socket; 
     this.dataProcessor = dataProcessor ; 
    } 

    /** run a thread */ 
    public void run(){ 
     try 
     { 
      // create data input and output streams 
      DataInputStream inputFromClient = new DataInputStream(socket.getInputStream()); 
      DataOutputStream outputToClient = new DataOutputStream(socket.getOutputStream()); 

      // continuously serve the client 
      while(true) { 
       // read data from client 

       double rate = inputFromClient.readDouble(); 
       double year = inputFromClient.readInt(); 
       double loan = inputFromClient.readDouble(); 


       // calculate monthly payment of loan and total payment 

       outputToClient.writeDouble(calculateMonthlyPayment(rate, year, loan)); 
       outputToClient.writeDouble(calculateTotalPayment(rate, year, loan)); 

       dataProcessor.accept(new LoanData(rate, year, loan)); 

      } 
     } 
     catch(IOException e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

今でサーバーdo

Consumer<LoanData> textAreaUpdater = 
    loanData -> Platform.runLater(() -> { 
     textArea.appendText("The rate is : " + loanData.getRate() + "\n"); 
     textArea.appendText("The number of years is: " + loanData.getYear() + "\n"); 
     textArea.appendText("Loan amount is: " + loanData.getLoan() + "\n\n"); 
    }); 

new Thread(new HandleAClient(socket, textAreaUpdater)).start(); 

UIデータ機能がUIクラスに正しく隠されています。

+0

ありがとう、これが解決しました! – j2k1218

関連する問題