JavaFX ComboBox不显示COM端口

时间:2016-04-15 09:51:04

标签: java intellij-idea javafx arduino fxml

我使用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);
        }

    }

2 个答案:

答案 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在他的回答中所述,虽然可以像你一样合并ApplicationController类内容,但它不允许你从{{{ 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专家,但也许您可以将一些更改应用到您的代码中。