好吧,所以我在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循環內部創建了一個新線程來處理每個客戶端。
我試圖創建HandleAClient類作爲一個單獨的Java類,而不是在服務器級別將其插入的,但是這導致服務器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類,我該怎麼做?
我很好奇,並試圖很好地理解線程是如何工作的。先謝謝你。
UPDATE 這是沒有爲我工作的獨立類。我擴展了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中的代碼沒有出現在服務器GUI中,因爲它是在類位於Server類內部時出現的。我想明白爲什麼會發生這種情況。
我不確定我是否理解這個問題。 'HandleAClient'類應該可以獨立運行,只要它能夠訪問它需要訪問的所有'Server'類的字段(真正的內部類和頂級類之間的唯一區別是內部類可以訪問其周圍類的字段)。當你把它作爲一個頂級的類來實現時,你是如何讓它訪問'textArea'的?你可以發佈獨立(頂級)HandleAClient類的完整版本嗎? –
是的,我更新了我原來的帖子,包括沒有工作的班級。基本上我在Server類中保護了textArea字段,並將Server類擴展爲HandleAClient類。 – j2k1218
儘管您在此處更新的文本區域與您在UI中顯示的文本區域不同。你需要更新屬於顯示UI的'Server'實例的那個。 –