gpt4 book ai didi

java - 有没有办法在 JavaFX 中的不同类文件中使用线程?

转载 作者:太空宇宙 更新时间:2023-11-04 11:45:06 25 4
gpt4 key购买 nike

好吧,我对 Java 编程并不陌生,但我对在 Java 程序中使用线程很陌生。我正在上学,刚刚读完关于线程和 Java 网络的章节。我正在编写一个客户端 GUI,将贷款信息(年利率、年数和贷款金额)发送到服务器。服务器有自己的 GUI,计算每月还款额和贷款总额,并将其发送回客户端并显示给用户,并更新服务器 GUI。

书中有这样的代码作为示例:

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 循环内部创建一个新线程来处理每个单独的客户端。

我尝试将 HandleAClient 类创建为单独的 Java 类,而不是将其插入到 Server 类中,但这导致服务器 GUI 未使用 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");});

所以我的问题是:为什么当 HandleAClient 类位于 Server 类内部时它可以工作,而当 HandleAClient 类位于扩展 Server 的单独 Java 类文件中时它不起作用?我认为它必须与线程做一些事情?为了能够在自己的 Java 类文件中包含 HandleAClient 类,我需要进行哪些更改?

我很好奇并试图很好地理解线程是如何工作的。预先感谢您。

更新这是独立的类(class),对我来说不起作用。我扩展了 Server 类,并在 Server 类中保护了 TextArea 字段。

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 中。我想了解为什么会发生这种情况。

最佳答案

您需要您的HandleAClient实例来更新属于 Server 的文本区域创建它们的对象:textArea属于那个Server实例是在 UI 中显示的实例。根据您的设置,每个 HandleAClient实例有自己的 textArea ,并且每个都更新自己的 textArea 。当然,这些都不会显示。

对于我来说 HandleAClient 真的没有意义延长Server 。您需要做的(无论您是否拥有该继承)是为 HandleAClient 提供一种方法。更新属于 Server 的文本区域。最简单(但不一定是最好)的方法是将文本区域传递给 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();
}
}
}

然后当然是Server您将其修改为

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();

}
<小时/>

HandleAClient 感觉有点不自然类(负责通信)依赖于对 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 A类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();
}
}
}

现在在服务器中执行

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 类中。

关于java - 有没有办法在 JavaFX 中的不同类文件中使用线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42428801/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com