我使用Arduino和一些组件创建了一个电路,并在JavaFX中创建了一个小型测试应用程序(显示的代码)。问题是我无法得到 COM端口(使用Windows 10)显示在组合框中,但是我可以在输出控制台中看到它们(COM5上的Arduino)。当我运行代码检查 在intellij我得到 “问题简介 - 未经检查的调用'addListener(ChangeListener?super T>)'作为原始类型'javafx.beans.value.ObservableValue'的成员(在第92行)” 这看起来很有用。我认为这意味着听众不再听,但老实说我不知道。
fxml文件的代码:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="538.0" prefWidth="734.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="labrat.Controller">
<top>
<VBox prefHeight="148.0" prefWidth="723.0" style="-fx-background-color: #1f3641;" BorderPane.alignment="CENTER">
<children>
<HBox prefHeight="25.0" prefWidth="723.0" style="-fx-background-color: #d2d4df;">
<children>
<Label text="LabRat Version R" textFill="#5b5b5b">
<font>
<Font size="14.0" />
</font>
<HBox.margin>
<Insets bottom="5.0" left="3.0" right="3.0" top="3.0" />
</HBox.margin>
</Label>
</children>
</HBox>
<HBox>
<children>
<Button fx:id="changeText" mnemonicParsing="false" onAction="#setChangeText" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: #ffffff;" text="Change text" textFill="#4a4a4a">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<font>
<Font size="16.0" />
</font>
</Button>
<Label fx:id="dynamicText" text="Default Text" textFill="WHITE">
<font>
<Font size="24.0" />
</font>
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</Label>
</children>
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</HBox>
<HBox layoutX="10.0" layoutY="10.0">
<children>
<Button fx:id="addElement" mnemonicParsing="false" onAction="#setAddElement" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: #ffffff;" text="Add element" textFill="#4a4a4a">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<font>
<Font size="16.0" />
</font>
</Button>
<TextField fx:id="typeToAdd" prefHeight="25.0" prefWidth="231.0" promptText="type to add to combobox">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</TextField>
<ComboBox fx:id="element" prefHeight="25.0" prefWidth="238.0" promptText="select element" style="-fx-background-color: #ffcc99;">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</ComboBox>
</children>
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</HBox>
</children>
</VBox>
</top>
<center>
<VBox prefHeight="200.0" prefWidth="100.0" style="-fx-background-color: #1f3641;" BorderPane.alignment="CENTER">
<children>
<HBox VBox.vgrow="ALWAYS">
<children>
<ImageView fx:id="imgVw" fitHeight="319.0" fitWidth="421.0" pickOnBounds="true" preserveRatio="true" />
<VBox prefHeight="200.0" prefWidth="100.0" style="-fx-background-color: #cc0000;" HBox.hgrow="ALWAYS">
<children>
<Label fx:id="labelValue" text="Label Value" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
<VBox.margin>
<Insets bottom="20.0" />
</VBox.margin>
</Label>
<ComboBox fx:id="comboBoxPorts" prefHeight="25.0" prefWidth="277.0" promptText="COM PORTS" style="-fx-background-color: #bdc3c7;" styleClass="comboBox" stylesheets="@testSS.css" />
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</VBox>
</children>
</HBox>
</children>
</VBox>
</center>
<bottom>
<HBox prefHeight="66.0" prefWidth="723.0" style="-fx-background-color: #222222;" BorderPane.alignment="CENTER">
<children>
<Button fx:id="nextScene" mnemonicParsing="false" onAction="#setNextScene" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #d2d4df;" text="Next Scene">
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</HBox.margin>
<font>
<Font size="16.0" />
</font>
</Button>
<Button fx:id="exit" mnemonicParsing="false" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #ff0000;" text="Exit Lab" textFill="WHITE">
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</HBox.margin>
<font>
<Font size="16.0" />
</font>
</Button>
<Button fx:id="version" layoutX="190.0" layoutY="20.0" mnemonicParsing="false" onAction="#setVersion" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #ffffff;" text="Alert Version">
<font>
<Font size="16.0" />
</font>
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</HBox.margin>
</Button>
<Button fx:id="showTheCar" layoutX="360.0" layoutY="20.0" mnemonicParsing="false" onAction="#setShowTheCar" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #ffffff;" text="Show the car!">
<font>
<Font size="16.0" />
</font>
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</bottom>
</BorderPane>
JavaFX类代码:
package labrat;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortException;
import jssc.SerialPortList;
import java.io.IOException;
public class Controller extends Application
{
@FXML
Button changeText;
@FXML
Button showTheCar;
@FXML
Label dynamicText;
@FXML
Button addElement;
@FXML
TextField typeToAdd;
@FXML
ComboBox<String> element;
@FXML
Button nextScene;
@FXML
Button exit;
@FXML
Button version;
@FXML
ImageView imgVw;
@FXML
private Image img;
// for serial com
SerialPort arduinoPort = null;
ObservableList<String> portList;
@FXML
private Label labelValue;
@FXML
ComboBox comboBoxPorts;
@Override
public void start(Stage primaryStage)
{
Parent rootParent = null;
try
{
rootParent = FXMLLoader.load(getClass().getResource("firstScene.fxml"));
primaryStage.setTitle("Test Lab version 3200");
primaryStage.setScene(new Scene(rootParent, 1100, 600));
primaryStage.show();
System.out.println("First Stage now showing");
}
catch (IOException e)
{
e.printStackTrace();
}
labelValue = new Label();
detectPort();
comboBoxPorts = new ComboBox(portList);
comboBoxPorts.valueProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
System.out.println("\nJust making sure this was executed!");
disconnectArduino();
connectArduino(newValue);
}
});
/*
comboBoxPorts.getItems().addAll(portList);
if(comboBoxPorts.getItems().addAll(portList))
{
System.out.println("\nAdded port-list(from observable list) to the CB!");
}
if(!(comboBoxPorts.getItems().addAll(portList)))
{
System.out.println("\nPort-list not added to CB!");
}
*/
}
@Override
public void stop() throws Exception
{
disconnectArduino();
super.stop();
}
// port detector method
private void detectPort(){
System.out.println("\n1/3 Now detecting port...");
portList = FXCollections.observableArrayList();
String[] serialPortNames = SerialPortList.getPortNames();
for(String name: serialPortNames){
System.out.println("\nDetected Port: ");
System.out.println(name);
portList.add(name);
}
}
// connect the Arduino
public boolean connectArduino(String port)
{
System.out.println("\n2/3 Connect Arduino now running...");
boolean success = false;
SerialPort serialPort = new SerialPort(port);
try {
serialPort.openPort();
serialPort.setParams(
SerialPort.BAUDRATE_9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.setEventsMask(SerialPort.MASK_RXCHAR);
serialPort.addEventListener((SerialPortEvent serialPortEvent) -> {
if(serialPortEvent.isRXCHAR()){
try {
String st = serialPort.readString(serialPortEvent
.getEventValue());
System.out.println("\nSPE Listener: ");
System.out.println(st);
//Update label in ui thread
Platform.runLater(() -> {
System.out.println("\nAttempted to update label in ui thread");
labelValue.setText(st);
});
} catch (SerialPortException ex) {
ex.printStackTrace();
}
}
});
arduinoPort = serialPort;
success = true;
} catch (SerialPortException ex) {
ex.printStackTrace();
System.out.println("SerialPortException: " + ex.toString());
}
return success;
}
// disconnect the Arduino
public void disconnectArduino()
{
System.out.println("\n3/3 Now disconnecting Arduino...");
if(arduinoPort != null)
{
try
{
arduinoPort.removeEventListener();
if(arduinoPort.isOpened())
{
arduinoPort.closePort();
}
}
catch (SerialPortException e)
{
e.printStackTrace();
}
}
}
@FXML
public void setChangeText()
{
dynamicText.setText("Text changed successfully!");
}
@FXML
public void setShowTheCar()
{
img = new Image("labrat/images/megane.jpg");
imgVw.setImage(img);
imgVw.isPreserveRatio();
}
@FXML
public void setVersion()
{
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("LabRat Version");
alert.setContentText("Version after the previous one! v0.001");
alert.showAndWait();
}
@FXML
public void setNextScene(ActionEvent ev)
{
try
{
Parent secondParent = FXMLLoader.load(getClass().getResource("secondScene.fxml"));
Scene secondScene = new Scene(secondParent);
Stage ourStage = (Stage) ((Node) ev.getSource()).getScene().getWindow();
ourStage.setTitle("Test Lab Page II");
ourStage.setScene(secondScene);
ourStage.show();
}
catch (IOException e)
{
e.printStackTrace();
}
}
@FXML
public void setAddElement()
{
String bufferText = typeToAdd.getText();
element.getItems().addAll(bufferText);
}
}
控制台输出到显示场景时:
"C:\Program Files\Java\jdk1.8.0_73\bin\java" (cut this short to minimize length)
First Stage now showing
1/3 Now detecting port...
Detected Port:
COM5
如何让ComboBox显示端口?编辑 - 我正在使用jSSc插件版本2.8.0
编辑 - 在@RubioRic和@Jose Pereda的建议之后对Controller进行的纠正更改 - 现在显示端口(最终代码):
package labrat;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortException;
import jssc.SerialPortList;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable
{
@FXML
Button changeText;
@FXML
Button showTheCar;
@FXML
Label dynamicText;
@FXML
Button addElement;
@FXML
TextField typeToAdd;
@FXML
ComboBox<String> element;
@FXML
Button nextScene;
@FXML
Button exit;
@FXML
Button version;
@FXML
ImageView imgVw;
@FXML
private Image img;
// for serial com
SerialPort arduinoPort = null;
ObservableList<String> portList;
@FXML
private Label labelValue;
@FXML
ComboBox comboBoxPorts;
@Override
public void initialize(URL location, ResourceBundle resources)
{
detectPort();
}
// port detector method
private void detectPort(){
System.out.println("\n1/3 Now detecting port...");
portList = FXCollections.observableArrayList();
String[] serialPortNames = SerialPortList.getPortNames();
for(String name: serialPortNames){
System.out.println("\nDetected Port: ");
System.out.println(name);
portList.add(name);
}
// No need to create a new combo instance
// No need to add a change listener to refresh ports
comboBoxPorts.setItems(portList);
comboBoxPorts.valueProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
{
System.out.println("\nChangeListener executed!");
disconnectArduino();
connectArduino(newValue);
System.out.println("\nOld Value was: " + oldValue);
System.out.println("\nNew Value is: " + newValue);
labelValue.setText(newValue);
}
});
}
// connect the Arduino
public boolean connectArduino(String port)
{
System.out.println("\n2/3 Connect Arduino now running...");
boolean success = false;
SerialPort serialPort = new SerialPort(port);
try {
serialPort.openPort();
serialPort.setParams(
SerialPort.BAUDRATE_9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.setEventsMask(SerialPort.MASK_RXCHAR);
serialPort.addEventListener((SerialPortEvent serialPortEvent) -> {
if(serialPortEvent.isRXCHAR()){
try {
String st = serialPort.readString(serialPortEvent
.getEventValue());
System.out.println("\nSPE Listener: ");
System.out.println(st);
//Update label in ui thread
Platform.runLater(() -> {
System.out.println("\nAttempted to update label in ui thread");
labelValue.setText(st);
});
} catch (SerialPortException ex) {
ex.printStackTrace();
}
}
});
arduinoPort = serialPort;
success = true;
} catch (SerialPortException ex) {
ex.printStackTrace();
System.out.println("SerialPortException: " + ex.toString());
}
return success;
}
// disconnect the Arduino
public void disconnectArduino()
{
System.out.println("\n3/3 Now disconnecting Arduino...");
if(arduinoPort != null)
{
try
{
arduinoPort.removeEventListener();
if(arduinoPort.isOpened())
{
arduinoPort.closePort();
}
}
catch (SerialPortException e)
{
e.printStackTrace();
}
}
}
@FXML
public void setChangeText()
{
dynamicText.setText("Text changed successfully!");
}
@FXML
public void setShowTheCar()
{
img = new Image("labrat/images/megane.jpg");
imgVw.setImage(img);
imgVw.isPreserveRatio();
}
@FXML
public void setVersion()
{
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("LabRat Version");
alert.setContentText("Version after the previous one! v0.001");
alert.showAndWait();
}
@FXML
public void setNextScene(ActionEvent ev)
{
try
{
Parent secondParent = FXMLLoader.load(getClass().getResource("secondScene.fxml"));
Scene secondScene = new Scene(secondParent);
Stage ourStage = (Stage) ((Node) ev.getSource()).getScene().getWindow();
ourStage.setTitle("Test Lab Page II");
ourStage.setScene(secondScene);
ourStage.show();
}
catch (IOException e)
{
e.printStackTrace();
}
}
@FXML
public void setAddElement()
{
String bufferText = typeToAdd.getText();
element.getItems().addAll(bufferText);
}
}
答案 0 :(得分:1)
根据您的代码:
@FXML
ComboBox comboBoxPorts;
@Override
public void start(Stage primaryStage)
{
...
comboBoxPorts = new ComboBox(portList);
}
在start()
方法中,您正在创建comboBoxPorts
的第二个实例。这是获取端口列表的那个,但是这没有添加到场景图中。
相反,由于FXMLLoader
注释,您不会向@FXML
创建的第一个实例(场景图中的实例)添加任何内容。
您只需要添加列表:
@FXML
ComboBox comboBoxPorts;
@Override
public void start(Stage primaryStage)
{
...
comboBoxPorts.setItems(portList);
}
修改强>
正如@RubioRic在他的回答中所述,虽然可以像你一样合并Application
和Controller
类内容,但它不允许你从{{{ 1}}方法,任何调用start()
的尝试都将抛出一个NPE,因为你将处理该类的两个非相关实例(一个由启动器创建,另一个由FXMLLoader创建)。
通常的方法是使用comboBoxPorts
方法创建一个合适的Controller
类,同时从initialize
方法加载fxml。
控制器类
Application.start()
编辑2
如果您仍想使用原始的单一类方法,这将有效:
从fxml文件中删除@FXML
ComboBox comboBoxPorts;
public void initialize() {
...
comboBoxPorts.setItems(portList);
}
标记,并在fx:controller
方法上设置控制器,参考start()
,这样您就只有一个实例:
this
答案 1 :(得分:1)
我不是JavaFx专家,但我认为你混合了两个概念Application和Controller。如果控制器未正确初始化,JoséPereda建议的更改可能会导致NullPointerException。
我使用你的fxml文件成功启动了一个小的演示,并将你的控制器更改为不调用arduino。但我已经使用了额外的课程来启动场景。这样就可以正确注入@FMX元素,并且组合框显示端口。
主要
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class ComboMain extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("combo.fxml"));
primaryStage.setTitle("Combo");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
控制器
public class ComboController implements Initializable {
// @FXML elements here
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
detectPort(); // Include all the code that you need for initializing elements here
}
// port detector method
// Dummy method - Include arduino calls here
private void detectPort(){
System.out.println("\n1/3 Now detecting port...");
portList = FXCollections.observableArrayList();
String[] serialPortNames = {"COM1", "COM2", "COM3"}; // SerialPortList.getPortNames();
for(String name: serialPortNames){
System.out.println("\nDetected Port: ");
System.out.println(name);
portList.add(name);
}
// No need to create a new combo instance
// No need to add a change listener to refresh ports
comboBoxPorts.setItems(portList);
}
// Arduino methods here
}
正如我所说,我不是javafx专家,但也许您可以将一些更改应用到您的代码中。