i'm a java beginner (and french:)).I make a gui with javafx to communicate via serial port to a 3d printer. In my code i can send and receive data. The received data is displayed in the java console but i'd like to display this data in a textarea. And i didn't manage. i've no code error but nothing in the textarea. here is my code:
#FXML
private TextArea rxArea = new TextArea();
in the same controller class :
public void serialEvent(SerialPortEvent event) {
if(event.isRXCHAR() &&event.getEventValue() > 0){
try {
String data = serialPort.readString(event.getEventValue());
System.out.println(data); //work
rxArea.appendText(data); // not work
}
catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
Thanks for any help
Related
I'm trying to setup a backdoor on an application which I'm working on.
I want to load a new Window when the user presses "CTRL + ALT + F12".
This is what I have tried so far though it is terribly bad.
//packages
import java.awt.EventQueue;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
//...
private void setupBackPass(){
HashMap<KeyStroke, Action> actionMap = new HashMap<KeyStroke, Action>();
KeyStroke key1 = KeyStroke.getKeyStroke(KeyEvent.ALT, KeyEvent.CTRL_DOWN_MASK);
actionMap.put(key1, new AbstractAction("action1") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Ctrl-ALT pressed: " +e);
}
});
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
kfm.addKeyEventDispatcher(new KeyEventDispatcher() {
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
if(actionMap.containsKey(keyStroke)){
final Action a = actionMap.get(keyStroke);
final ActionEvent ae = new ActionEvent(e.getSource(), e.getID(), null);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
}
});
return false;
}
});
});
}
Am not sure how to do it but I would like it that if the keys are pressed then a Super admin window should be opened.
From the code you posted, it looks like you are using Swing and not JavaFX. It also looks like you are trying to use Key Bindings. As explained in that link, you need to modify both the input map and the action map. Also, you don't create an action map, you use the existing one. Again, that is explained in the page that I provided a link to.
apologies for the length of my code. I realized last night that I was on the wrong path and now have gotten stuck on an issue that I think relates to JavaFX event handling. Initially I had the logic functioning outside a GUI in a basic loop that depended on interaction through the console. Everything was working great. I've now tried to get this to work in a GUI with interaction from the user.
I have two main problems with the code below.
The first is that the text in textArea is not updating with additional text after the startButton executes the start of my main logic sequence. The first append starts right under the first while loop. I was hoping to have this show up in the GUI as the logic executes. I'm not sure if I need to tell the GUI to update at certain intervals or if there's something else wrong.
Second, I'm not sure how to get the program to wait for the user to type in something into textField before hitting the textButton I created to continue on. I used to have a scanner created which caused the program to wait in the console for input. I realize I need some way of telling it to wait for a button press when it's running inside JavaFX.
I chose not to include the rest of the code to make things easier to read, but I can add it on if it will help resolve this issue.
Thank you everyone for your help!
public class FxApp extends Application {
//Creates FileParser object with methods that alter the incoming Array of Strings into the format we need
FileParser fileParser = new FileParser();
Configure configure = new Configure();
private String text;
private String initialState;
private ArrayList<Machine> machines = new ArrayList<Machine>();
private Map<String, String> initialStates = new HashMap<String, String>();
private Map<String, String> states = new HashMap<String, String>();
private Map<String, ArrayDeque<String>> queues = new HashMap<String, ArrayDeque<String>>();
private Map<Integer, ArrayList<String>> parsedData = new HashMap<Integer, ArrayList<String>>();
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("File Chooser");
FileChooser fileChooser = new FileChooser();
fileChooser.getExtensionFilters().addAll(new ExtensionFilter("Text Files", "*.txt"));
Button startButton = new Button("Start");
Button openButton = new Button("Click to open a file...");
openButton.setPrefSize(200, 80);
Button textButton = new Button("Enter");
TextArea textArea = new TextArea();
textArea.setWrapText(true);
TextField textField = new TextField();
Label lbl = new Label();
VBox vbox = new VBox(lbl, openButton, startButton, textArea, textField, textButton);
vbox.setSpacing(10);
vbox.setPadding(new Insets(15));
lbl.setText("This tool creates virtual automata based \ron the file.");
Scene scene = new Scene(vbox, 640, 480);
primaryStage.setScene(scene);
primaryStage.show();
openButton.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
File file = fileChooser.showOpenDialog(primaryStage);
if (file != null) {
//Execute the method to convert to string array before sending to file parser
try {
fileParser.convertFile(file);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
textButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
text = textField.getText();
}
});
startButton.setOnAction(new EventHandler <ActionEvent>()
{
public void handle(ActionEvent event)
{
machineCreation();
String exit = "no";
String nextLine = null;
ArrayList<String> listOfCurrentTransitions = new ArrayList<String>();
int nextInt = 0;
states = initialStates;
while(!(exit.toLowerCase().equals("yes"))) {
textArea.appendText("Choose a state to load");
//Print out the states possible for each machine
ArrayList<String> tempTrans = machines.get(nextInt).getTransitions();
//This loops through the list of transitions of the machine and pulls possible transitions from its current state
for(int i = 0; i < tempTrans.size(); i++) {
String pull = tempTrans.get(i);
String[] apart = pull.split(" ");
pull = apart[0];
if(states.get(Integer.toString(nextInt)).equals(pull)) {
listOfCurrentTransitions.add(tempTrans.get(i));
}
}
if(!(listOfCurrentTransitions.isEmpty())) {
textArea.appendText("The following transitions are possible. Choose one: " + listOfCurrentTransitions);
}
else {
textArea.appendText("No transitions for this machine exist from its current state");
}
//Tell GUI to wait for user input in textField and execute textButton which assigns to String text. Resume on button click.
The while loop blocks the JavaFX application thread which prevents updates of the GUI and handling of events.
You need to execute the logic of a single iteration of the loop on each "text commit" instead:
private TextArea textArea;
private void activateState(int nextInt) {
ArrayList<String> listOfCurrentTransitions = new ArrayList<String>();
textArea.appendText("Choose a state to load");
//Print out the states possible for each machine
ArrayList<String> tempTrans = machines.get(nextInt).getTransitions();
//This loops through the list of transitions of the machine and pulls possible transitions from its current state
for(int i = 0; i < tempTrans.size(); i++) {
String pull = tempTrans.get(i);
String[] apart = pull.split(" ");
pull = apart[0];
if(states.get(Integer.toString(nextInt)).equals(pull)) {
listOfCurrentTransitions.add(tempTrans.get(i));
}
}
if(listOfCurrentTransitions.isEmpty()) {
textArea.appendText("No transitions for this machine exist from its current state");
} else {
textArea.appendText("The following transitions are possible. Choose one: " + listOfCurrentTransitions);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
...
textArea = new TextArea();
...
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
machineCreation();
activateState(0);
}
});
textButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// read input and ask for more input...
int nextState = Integer.parseInt(textField.getText()); // TODO: deal with invalid input
activateState(nextState);
}
});
You probably need to fix the logic a bit to verify a transition is valid, change the values of some fields ect...
I have a small javafx application using scene builder which on a button click should read a string from COM port at regular intervals and update in a text field.
But now it only shows the last string if I use a for loop, and nothing if i put the code in infinite loop (That's my temporary requirement).
Can anyone help me so that at each read from COM port the new string is updated in the text field.
Here is the code I used for both the cases :
Note : In both cases in controller class, I'm getting perfect output on console.
public class Main extends Application
{
#Override
public void start(Stage primaryStage)
{
try
{
Parent root = FXMLLoader.load(getClass().getResource("test.fxml"));
Scene scene = new Scene(root);
//scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("test");
primaryStage.setScene(scene);
primaryStage.show();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
launch(args);
}
}
Here is the Controller class :
// In this case it shows only the last string in the text field.
public class Controller implements Initializable
{
#FXML
private Button sayHelloButton;
#FXML
private TextField helloField;
#Override
public void initialize(URL arg0, ResourceBundle arg1)
{
}
#FXML
public void printHello(ActionEvent event)
{
if(event.getSource() == sayHelloButton)
{
SerialPort serialPort = new SerialPort("COM22");
for(int i=0;i<5;i++)
{
try
{
if(!serialPort.isOpened())
{
serialPort.openPort();
serialPort.setParams(9600, 8, 1, 0);
}
String str = serialPort.readString(10,3000);
System.out.println(str);
helloField.clear();
helloField.setText(str);
}
catch(Exception e)
{
helloField.setText(e.toString());
}
}
}
}
}
Here is the method with infinite loop :
//this shows nothing in the text field
#FXML
public void printHello(ActionEvent event)
{
if(event.getSource() == sayHelloButton)
{
SerialPort serialPort = new SerialPort("COM22");
while(true)
{
try
{
if(!serialPort.isOpened())
{
serialPort.openPort();
serialPort.setParams(9600, 8, 1, 0);
}
String str = serialPort.readString(10,3000);
System.out.println(str);
helloField.clear();
helloField.setText(str);
}
catch(Exception e)
{
helloField.setText(e.toString());
}
}
}
}
There are a couple things happening here. In your first example, you state that the console output is correct but the TextField only shows the last result.
This is expected if the loop executes quickly. The TextField is being updated, but it happens so quickly that you can't see it until the loop ends and the last result is still being displayed. Even if you have a delay built into the loop, this could still block the UI from being updated until the loop is completed.
With your infinite loop, the issue is that the loop is being run on the JavaFX Application Thread (JFXAT). This blocks any updates to the GUI until the loop is finished, which is never is.
You will need to move the infinite loop to a new background thread. From there, you can update the GUI using the Platform.runLater() method.
SerialPort serialPort = new SerialPort("COM22");
new Thread(() -> {
while(true)
{
try
{
if(!serialPort.isOpened())
{
serialPort.openPort();
serialPort.setParams(9600, 8, 1, 0);
}
String str = serialPort.readString(10,3000);
System.out.println(str);
// Update the UI on the JavaFX Application Thread
Platform.runLater(() -> {
helloField.clear();
helloField.setText(str);
});
}
catch(Exception e)
{
Platform.runLater(() -> helloField.setText(e.toString()));
}
}
}).start();
This allows your UI to continually update as the background thread sends it new information.
I have partially solved the following problem: JavaFX WebView / WebEngine show on-screen-keyboard automatically for each text input
I stucked at the 6th point because I would like to use the built in JavaFX virtual keyboard but I can not find any reference how can trigger the displaying of it.
Do you know any solution for this? If it is possible I do not want to use 3rd party library.
I am going to answer my question because I found a solution.
First of all I added an event listener for all input tags on webpage, after page loaded:
private void addEventListenersToDOM() {
webview.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
#Override
public void changed(ObservableValue<? extends State> ov, State oldState, State newState) {
if (newState == State.SUCCEEDED) {
JSObject win = (JSObject) webview.getEngine().executeScript("window");
win.setMember("javaFXVirtualKeyboard", new JavaFXVirtualKeyboard());
String script =
"var inputsList = document.getElementsByTagName('input');"
+ "for (var index = 0; index < inputsList.length; ++index) { "
+ "inputsList[index].addEventListener('focus', function() { javaFXVirtualKeyboard.show() }, false); "
+ "inputsList[index].addEventListener('focusout', function() { javaFXVirtualKeyboard.hide() }, false); "
+ "}";
webview.getEngine().executeScript(script);
}
}
});
}
And the key point, how I triggering the keyboard displaying and hiding:
public class JavaFXVirtualKeyboard {
public void show() {
FXVK.init(webview);
FXVK.attach(webview);
}
public void hide() {
FXVK.detach();
}
}
One note: FXVK class is not an API so we get a warning message in all cases but it works without any bug.
Discouraged access: The type 'FXVK' is not API (restriction on required library 'C:\Program Files\Java\jre1.8.0_91\lib\ext\jfxrt.jar')
I'm working on a simple application using JavaFX with controller class and FXML and Jssc to control arduino. The arduino is connected to a sg90 servo motor and a LED.
I'm having problem with slider to control the servo motor. i want to use the slider to control the angle of the servo motor and whenever i drag the slider thumb the servo will constantly update its angle.
here is the controller class the code works but the problem is i don't have any idea how to implement the controls for the slider and servo.
public class ServoCtrl implements Initializable {
#FXML
private Button IncrBtn = new Button();
#FXML
private Button DecrBtn = new Button();
#FXML
private ToggleButton toggleConnectSerial = new ToggleButton();
#FXML
private ToggleButton lightSwitcH = new ToggleButton();
#FXML
private Slider AngleSlider = new Slider(0, 180, 90);
#FXML
private TextField tfAngle = new TextField();
#FXML
private TextField tfSteps = new TextField();
SerialPort ServoSerialPort;
private int tempstr = 0;
#Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
tfAngle.textProperty().bindBidirectional(AngleSlider.valueProperty(), NumberFormat.getIntegerInstance());
//disable all port when starting the application
AngleSlider.setDisable(true);
lightSwitcH.setDisable(true);
IncrBtn.setDisable(true);
DecrBtn.setDisable(true);
tfAngle.setDisable(true);
tfSteps.setDisable(true);
}
/*--------- increase or decrease slider value using buttons---------------------------------*/
public void IncrBtnPress(ActionEvent btnIncr) {
tempstr = Integer.parseInt(tfSteps.getText());
AngleSlider.setValue(Integer.parseInt(tfAngle.getText()) + tempstr);
tfAngle.setText(Integer.toString((int) AngleSlider.getValue()));
}
public void DecrBtnPress(ActionEvent btnDecr) {
tempstr = Integer.parseInt(tfSteps.getText());
AngleSlider.setValue(Integer.parseInt(tfAngle.getText()) - tempstr);
tfAngle.setText(Integer.toString((int) AngleSlider.getValue()));
}
/*-----------toggle Switch on light-----------------------------------*/
public void lightSwitch(ActionEvent eve) {
try {
if (lightSwitcH.isSelected() == true) {
lightSwitcH.setText("OFF");
/*
* send the following string commands 3 = led number 1 = On, 0 =
* Off / = seperator - = wait for next command
*
*/
// turn on led
ServoSerialPort.writeString("3/1-");
} else {
// turn off led
lightSwitcH.setText("ON");
ServoSerialPort.writeString("3/0-");
}
}
catch (SerialPortException e) {
e.printStackTrace();
}
}
/*-------------------- connect or disconnect port-------------------------*/
public void toggleConnect(ActionEvent tgle) {
if (toggleConnectSerial.isSelected() == true) {
// enable control when serial port is connected
AngleSlider.setDisable(false);
lightSwitcH.setDisable(false);
IncrBtn.setDisable(false);
DecrBtn.setDisable(false);
tfAngle.setDisable(false);
tfSteps.setDisable(false);
// set the port name
ServoSerialPort = new SerialPort("COM8");
try {
// set the toggle button text to disconnect
toggleConnectSerial.setText("Disconnect");
// open the serial port
ServoSerialPort.openPort();
// set the port parameters
ServoSerialPort.setParams(SerialPort.BAUDRATE_115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
} catch (SerialPortException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
// disable all control when port is disconnected
AngleSlider.setDisable(true);
lightSwitcH.setDisable(true);
IncrBtn.setDisable(true);
DecrBtn.setDisable(true);
tfAngle.setDisable(true);
tfSteps.setDisable(true);
toggleConnectSerial.setText("Connect");
try {
ServoSerialPort.closePort();
} catch (SerialPortException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
You are binding the value bidirectional:
tfAngle.textProperty().bindBidirectional(AngleSlider.valueProperty(), NumberFormat.getIntegerInstance());
which means the property gets already updated if the textfield or the slider changes - the other component gets updated automatically. therefore your methods like IncrBtnPress should not update both values, just one: either the slider OR the textField.
if you want to update the new ankle to your arduino: pick a property (e.g. the textProperty() of your textfield) and add a ChangeListener where you can implement your new ankle-Setter to your arduino.