英文:
JavaFx set Label text from another controller
问题
我想要在声明控制器的类中更改标签的文本,而不是从类中更改文本。
我想要在主文件的ClientAccept类中进行更改,但是当我尝试从ClientAccept获取控制器类并从控制器类运行函数时,我会得到NullPointerException,因为"this.sStatus"为空。我无法解决这个问题。
Main.java:
package sample;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
public class Main extends Application {
ServerSocket ss;
HashMap clientColl = new HashMap();
@Override
public void start(Stage stage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Controller controller = new Controller();
loader.setController(controller);
Parent parent = loader.load();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
try{
ss = new ServerSocket(8989);
}catch (IOException ioe){
System.out.println(ioe.getMessage());
}
ClientAccept cla = new ClientAccept();
cla.isWorking();
}
public static void main(String[] args) {
launch(args);
}
class ClientAccept extends Thread{
public void isWorking() throws IOException {
Controller controller = new Controller();
controller.setsStatus("test");
}
public void run(){
while(true){
try {
Socket s = ss.accept();
String i = new DataInputStream(s.getInputStream()).readUTF();
if(clientColl.containsKey(i)){
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF("Już jesteś Zarejestrowany");
}else {
clientColl.put(i, s);
Platform.runLater(() -> {
controller.setsStatus("TextToLabel");
});
}
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
}
}
Controller.java:
package sample;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
public class Controller {
@FXML
Label sStatus;
@FXML
TextArea msgBox;
void setsStatus(String text){
sStatus.setText(text);
System.out.println(text);
}
}
sample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TextArea fx:id="msgBox" layoutX="53.0" layoutY="67.0" prefHeight="278.0" prefWidth="512.0" />
<Label layoutX="67.0" layoutY="28.0" text="Server Status: " />
<Label fx:id="sStatus" layoutX="142.0" layoutY="28.0" text=".............." />
</children>
</AnchorPane>
我只是得到了NullPointerException。
英文:
I want to change text for label not from class where i declare controller to fxml file.
I want to change it in ClientAccept class in Main file, but when i tried get Controller class and run function in Controller class from ClientAccept i get NullPointerException 'because "this.sStatus" is null'. I cant resolve it.
Main.java:
package sample;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Control;
import javafx.stage.Stage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
public class Main extends Application {
ServerSocket ss;
HashMap clientColl = new HashMap();
@Override
public void start(Stage stage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Controller controller = new Controller();
loader.setController(controller);
Parent parent = loader.load();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
try{
ss = new ServerSocket(8989);
}catch (IOException ioe){
System.out.println(ioe.getMessage());
}
ClientAccept cla = new ClientAccept();
cla.isWorking();
}
public static void main(String[] args) {
launch(args);
}
class ClientAccept extends Thread{
public void isWorking() throws IOException {
Controller controller = new Controller();
controller.setsStatus("test");
}
public void run(){
while(true){
try {
Socket s = ss.accept();
String i = new DataInputStream(s.getInputStream()).readUTF();
if(clientColl.containsKey(i)){
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF("Już jesteś Zarejestrowany");
}else {
clientColl.put(i, s);
Platform.runLater(()->{
controller.setsStatus("TextToLabel");
});
}
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
}
}
Controller.java:
package sample;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
public class Controller {
@FXML
Label sStatus;
@FXML
TextArea msgBox;
void setsStatus(String text){
sStatus.setText(text);
System.out.println(text);
}
}
sample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TextArea fx:id="msgBox" layoutX="53.0" layoutY="67.0" prefHeight="278.0" prefWidth="512.0" />
<Label layoutX="67.0" layoutY="28.0" text="Server Status: " />
<Label fx:id="sStatus" layoutX="142.0" layoutY="28.0" text=".............." />
</children>
</AnchorPane>
I just get NullPointerException.
答案1
得分: 2
@FXML
注解的字段只会在 FXMLLoader
使用的 Controller
实例中初始化。它们不会在其他实例中初始化,比如你在 ClientAccept
类中创建的实例。
一个简单粗暴的方法是让 ClientAccept
类引用正确的 Controller
实例。例如:
public void start(Stage stage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Controller controller = new Controller();
loader.setController(controller);
Parent parent = loader.load();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
try{
ss = new ServerSocket(8989);
}catch (IOException ioe){
System.out.println(ioe.getMessage());
}
ClientAccept cla = new ClientAccept(controller);
cla.isWorking();
}
class ClientAccept extends Thread{
private final Controller controller ;
public ClientAccept(Controller controller) {
this.controller = controller ;
}
public void isWorking() throws IOException {
controller.setsStatus("test");
}
public void run(){
while(true){
try {
Socket s = ss.accept();
String i = new DataInputStream(s.getInputStream()).readUTF();
if(clientColl.containsKey(i)){
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF("Już jesteś Zarejestrowany");
}else {
clientColl.put(i, s);
Platform.runLater(()->{
controller.setsStatus("TextToLabel");
});
}
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
}
通常不推荐像这样共享控制器实例。更好的方法是使用 MVC 设计并共享模型。例如,你可以这样做:
public class DataModel {
private final StringProperty status = new SimpleStringProperty();
public StringProperty statusProperty() {
return status ;
}
public final String getStatus() {
return statusProperty().get();
}
public final void setStatus(String status) {
statusProperty().set(status);
}
// 同样地,对于应用程序共享的其他数据也可以这样做...
}
然后
```java
public class Controller {
@FXML
Label sStatus;
@FXML
TextArea msgBox;
private final DataModel model ;
public Controller(DataModel model) {
this.model = model ;
}
@FXML
public void initialize() {
sStatus.textProperty().bind(model.statusProperty());
}
}
和
```java
class ClientAccept extends Thread{
private final DataModel model ;
public ClientAccept(DataModel model) {
this.model = model ;
}
public void isWorking() throws IOException {
model.setStatus("test");
}
public void run(){
while(true){
try {
Socket s = ss.accept();
String i = new DataInputStream(s.getInputStream()).readUTF();
if(clientColl.containsKey(i)){
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF("Już jesteś Zarejestrowany");
}else {
clientColl.put(i, s);
Platform.runLater(()->{
model.setStatus("TextToLabel");
});
}
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
}
然后将它们统统联系在一起:
```java
public void start(Stage stage) throws Exception{
DataModel model = new DataModel();
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Controller controller = new Controller(model);
loader.setController(controller);
Parent parent = loader.load();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
try{
ss = new ServerSocket(8989);
}catch (IOException ioe){
System.out.println(ioe.getMessage());
}
ClientAccept cla = new ClientAccept(model);
cla.isWorking();
}
英文:
The @FXML
-annotated fields are only initialized in the Controller
instance used by the FXMLLoader
. They won't be initialized in other instances, such as the one you create in your ClientAccept
class.
A quick-and-dirty approach is just to arrange for the ClientAccept
to have a reference to the correct Controller
instance. E.g.
public void start(Stage stage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Controller controller = new Controller();
loader.setController(controller);
Parent parent = loader.load();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
try{
ss = new ServerSocket(8989);
}catch (IOException ioe){
System.out.println(ioe.getMessage());
}
ClientAccept cla = new ClientAccept(controller);
cla.isWorking();
}
class ClientAccept extends Thread{
private final Controller controller ;
public ClientAccept(Controller controller) {
this.controller = controller ;
}
public void isWorking() throws IOException {
controller.setsStatus("test");
}
public void run(){
while(true){
try {
Socket s = ss.accept();
String i = new DataInputStream(s.getInputStream()).readUTF();
if(clientColl.containsKey(i)){
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF("Już jesteś Zarejestrowany");
}else {
clientColl.put(i, s);
Platform.runLater(()->{
controller.setsStatus("TextToLabel");
});
}
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
}
It's generally not very good practice to share controller instances around like this. A better approach is to use a MVC design and share the model. E.g. you could do
public class DataModel {
private final StringProperty status = new SimpleStringProperty();
public StringProperty statusProperty() {
return status ;
}
public final String getStatus() {
return statusProperty().get();
}
public final void setStatus(String status) {
statusProperty().set(status);
}
// Similarly for other data shared by the app....
}
Then
public class Controller {
@FXML
Label sStatus;
@FXML
TextArea msgBox;
private final DataModel model ;
public Controller(DataModel model) {
this.model = model ;
}
@FXML
public void initialize() {
sStatus.textProperty().bind(model.statusProperty());
}
}
and
class ClientAccept extends Thread{
private final DataModel model ;
public ClientAccept(DataModel model) {
this.model = model ;
}
public void isWorking() throws IOException {
model.setStatus("test");
}
public void run(){
while(true){
try {
Socket s = ss.accept();
String i = new DataInputStream(s.getInputStream()).readUTF();
if(clientColl.containsKey(i)){
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF("Już jesteś Zarejestrowany");
}else {
clientColl.put(i, s);
Platform.runLater(()->{
model.setStatus("TextToLabel");
});
}
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
}
and then just tie it all together:
public void start(Stage stage) throws Exception{
DataModel model = new DataModel();
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Controller controller = new Controller(model);
loader.setController(controller);
Parent parent = loader.load();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
try{
ss = new ServerSocket(8989);
}catch (IOException ioe){
System.out.println(ioe.getMessage());
}
ClientAccept cla = new ClientAccept(model);
cla.isWorking();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论