reading and writing file in javafx program - javafx

I'm writing a program writes and read the file. it has 50 numbers and if users enter number more than 50 it should ask the users to enter it again. my question is for the error it should show the message box but again return to the text field for input. Also one more question, for example, user1 is entering 1 and user2 is also entering 1, it should tell the user2 "please enter another number it's already entered." how can I do it in writing and reading files.
this is my code:
public class JavaFXApplication24 extends Application {
private int seatInput;
#Override
public void start(Stage primaryStage) {
StackPane pane = new StackPane();
HBox hbox = new HBox();
Label num = new Label("Please enter the number from 1 to 50: ");
TextField numInput = new TextField();
File file = new File("NumberBook.txt");
Button ok = new Button("ok");
ok.setOnAction((new EventHandler<ActionEvent>(){
public void handle(final ActionEvent event ){
try{
if ((numInput.getText().equals(1)&& numInput.getText().equals(50))){
}else{
String input = JOptionPane.showInputDialog("Please enter again");
}
}
catch (HeadlessException | NumberFormatException e) {
}
try {
PrintWriter output = new PrintWriter(file);
} catch (IOException ex) {
System.out.printf("error", ex);
}
try {
Scanner input1 = new Scanner(file);
System.out.printf("Entered: %s", seatInput);
} catch (FileNotFoundException ex) {
System.out.printf("error", ex);
}
}
}));
hbox.getChildren().addAll(num,numInput,ok);
pane.getChildren().addAll(hbox);
Scene secondScene = new Scene(pane, 600, 400);
// New window (Stage)
Stage newWindow = new Stage();
newWindow.setTitle("Booking and Timing");
newWindow.setScene(secondScene);
newWindow.show();
}
}

From a quick glance here are some problems with your code:
1) if ((numInput.getText().equals(1)&& numInput.getText().equals(50))). There are 2 problems here. Firstly, as fabian pointed out, this statement will always evaluate to false. Secondly, from your question I think you want the user to enter a number from 1 to 50, but here you're checking if they enter 1 and 50 (which also means it's always false).
2) JOptionPane.showInputDialog("Please enter again") Because your application is JavaFX, you should use the built in Dialog instead.
Now to answer your questions, you can call requestFocus on the text field right after the error message is displayed. Your second question seems like you want some networking functionality in the application, which adds a whole lot of complexity to it. You might need to do some research on how to do it in Java.

Related

How to disable the arrow button in JavaFX combo box

I have a project I am working on. I am trying to make a dictionary. For that, I have a .csv file with about 55000 words.I am using the trie data structure which has a startsWith() method which checks whether there is a word in the .csv file which matches the given prefix. I had managed to get it to work to find all words that match the given prefix and display them. Now, I have to develop this into a JavaFX app.
So, I thought of using a ComboBox which has its editable attribute set to true so that I could type into it and then the handler associated with the textProperty() of its editor would display all the words starting with given prefix in the listview of the combobox.
Now, the problem I have is that whenever I click the arrow button of the combobox the application stops responding (I think it's because the list view tries to resize itself to fit the items which are 55000).
So, what I want to know is how to disable the arrow button entirely. I have tried to set its background-color to transparent but even then it can still be clicked I want to make it so that it is disabled and transparent basically the combobox ends up looking like a text field.
If there are better, more efficient ways of implementing a dictionary I would appreciate it if you could guide me.
The ListView is a virtual control that only shows a certain number of cells at a time, it doesn't need to "resize itself to the number of items" in any way that would lock up your GUI.
Does this demo program do what you want?
public class Main extends Application {
public static void main(String[] args) throws IOException, URISyntaxException {
launch(args);
}
#Override
public void start(Stage stage) {
List<String> rawWords = Collections.emptyList();
try {
URI wordURI = new URI("https://www-cs-faculty.stanford.edu/~knuth/sgb-words.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(wordURI.toURL().openStream(), StandardCharsets.UTF_8));
rawWords = reader.lines().collect(Collectors.toCollection(() -> new ArrayList<>(6000)));
} catch (IOException | URISyntaxException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
// make the list at least as big as in the question
while(rawWords.size() < 55000) {
ArrayList<String> nextWords = new ArrayList<>(rawWords.size() * 2);
nextWords.addAll(rawWords);
nextWords.addAll(rawWords);
rawWords = nextWords;
}
Collections.sort(rawWords);
ObservableList<String> wordList = FXCollections.observableArrayList(rawWords);
FilteredList<String> filteredList = new FilteredList<>(wordList);
ComboBox<String> combo = new ComboBox<>(filteredList);
combo.setEditable(true);
combo.getEditor().textProperty().addListener((obs, oldVal, newVal) -> {
filteredList.setPredicate(s -> newVal == null || newVal.isEmpty() || s.startsWith(newVal));
});
VBox vbox = new VBox(8,new Label("Dictionary ComboBox"),
combo,
new Label("\n\n\n\nThis space intentionally left blank.\n\n\n\n"));
vbox.setPadding(new Insets(8));
Scene scene = new Scene(vbox, 400, 300);
stage.setTitle("Demo - Filtered Combobox List");
stage.setScene(scene);
stage.show();
}
}

JavaFx TableView - update items from another controller

I have a TableView that I am populating with 2 columns (Key and Value) from a database. When I click on a table row, I open a new scene which has a text area that shows the Value column and allows one to edit it. I choose to go with a separate UI for editing the contents of value column as it contains a prettyfied JSON document and having an in place edit in the table would have been cumbersome.
dataTable.setRowFactory(tv -> {
TableRow<Map.Entry<String, String>> row = new TableRow<>();
row.setOnMouseClicked(event -> {
showDataPopup(dataValue.getKey(), dataValue.getValue());
});
return row;
});
private void showDataPopup(String key, String value) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("tableDataPopup.fxml"));
Parent dataRoot = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setTitle("Data Viewer");
stage.setScene(new Scene(dataRoot, 800, 500));
DataPopupController dataPopupController = fxmlLoader.getController();
dataPopupController.loadDataTextArea(key, value, this);
stage.show();
} catch (Exception e) {
logger.error("Error loading tableDataPopup.fxml", e);
}
}
Now, in the tableDataPopup scene, I allow the value to be edited. I have a save button which should save the edited document back to the table and close the scene. Here's my save method
public void saveEditedDocument(ActionEvent event) {
//code to save document to db
mainController.refreshTable(docIdLabel.getText(), dataTextArea.getText());
Stage stage = (Stage) editCancelButton.getScene().getWindow();
stage.close();
}
...
I have a refreshTable method in my main controller. Main controller has all the TableView components and logic.
public void refreshTable(String docId, String docVal) {
logger.info(": {}", dataTable.getItems());
}
I need help figuring out how to update the cell value that was changed in the popup dialog. I'd rather avoid having to stream the whole table and look for the key column and update the value. I am looking for a way to pass the cell index to the data popup and have it pass it back to the refreshTable method. Then use it to directly update the cell and then call dataTable.refresh() method to refresh the data table.
I am struggling with where to even start on this. Any pointers would really help...
I guess i figured it out. May not be an elegant solution, but this works for me.
I am passing the index of the row that was clicked on to my dataPopupController
dataTable.setRowFactory(tv -> {
TableRow<Map.Entry<String, String>> row = new TableRow<>();
row.setOnMouseClicked(event -> {
showDataPopup(dataValue.getKey(), dataValue.getValue(),row.getIndex());
});
return row;
});
private void showDataPopup(String key, String value, int index) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("tableDataPopup.fxml"));
Parent dataRoot = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setTitle("Data Viewer");
stage.setScene(new Scene(dataRoot, 800, 500));
DataPopupController dataPopupController = fxmlLoader.getController();
dataPopupController.loadDataTextArea(key, value, this, **index**);
stage.show();
} catch (Exception e) {
logger.error("Error loading tableDataPopup.fxml", e);
}
}
And I updated the refreshTable method in main controller to update the item based on the index
public void refreshTable(String docVal, int tableIndex) {
logger.info(": {}", dataTable.getItems());
logger.info("Table value is: {}", dataTable.getItems().get(tableIndex).setValue(docVal));
dataTable.refresh();
}
And in my popup controller, I just pass back the index when I call refreshTable method
public void saveEditedDocument(ActionEvent event) {
// Todo - refresh table after save
try {
mainController.refreshTable(minifyData(dataTextArea.getText()), tableIndex);
Stage stage = (Stage) editCancelButton.getScene().getWindow();
stage.close();
} catch (JsonSyntaxException exception) {
saveStatusLabel.setText("Malformed JSON, please correct");
logger.error("Malformed JSON - {}", exception.getMessage());
}
}
May not be the most elegant way to do this, but in a pinch, it works for me.

Issue relating to JavaFX GUI event handling and updating

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...

Add level in JavaFX during loading operation

I have the following UI
So , you insert a keyword and then press "Cerca" (it's like Search in Italian) , then the Google Custom Search Api show the first 10 pictures. During the Custom search API are processing the results (the pictures) I want to show an other picture like this
(I know it's big but the dimension is not the main point now). My idea is simple, I want to put the picture one "level"(don't know exactly how to call ) over the UI, then the picture will be not visible in 3 case: 1) When the API will end their job 2)If I don't have results 3) If I get an exception. My question is, which is the best approach to do this ? And then, Should I use Threads?
I hope I was clear
UPDATE:
This is the code of "cerca" button
cerca.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
// Task<Boolean> task = new Task <Boolean>(){
//
// #Override
// protected Boolean call() throws Exception {
// // TODO Auto-generated method stub
// return null;
// }
//
//
// };
String searchKeyWord = userTextField.getText();
result = getSearchResult(searchKeyWord);
for ( i=0; i<result.size(); i++)
{
System.out.println("" +result.get(i));
ImageView resultview;
resultview = new ImageView(result.get(i));
resultview.setFitWidth(130);
resultview.setFitHeight(130);
// resultview.setStyle("-fx-border:6; -fx-border-color: green;");
if(j==4)
{
j=0;
k++;
}
resultgrid.add(resultview, j,k );
j++;
VBox vbox = new VBox();
resultgrid.setHgap(50);
resultgrid.setVgap(50);
// resultgrid.setStyle("-fx-border:1; -fx-border-color: red;");
vbox.getChildren().add(resultgrid);
vbox.setSpacing(10);
vbox.setPadding(new Insets(90, 0, 10, 220)); //TOP RIGHT BOTTOM LEFT
// content.setAlignment(resultgrid, Pos.TOP_RIGHT);
getChildren().add(vbox);
final int ind = i;
resultview.setOnMouseClicked((ev) ->{
if (ev.getClickCount()==2)
{
image = SwingFXUtils.fromFXImage(resultview.getImage(), null);
parent.setCrop(image);
}
});
}
}
});
Have a look at Task. It has setOnSucceeded() and setOnFailed() which will come handy in your case.
You can basically create a new Task when the search takes place. The search will run in background and you can show the loading UI in the screen.
If the task completes successfully, you can load the new screen with the results.
If the task fails, you can show an error message near the search TextField.
In case of exception, you can catch it and write the necessary code.

JavaFX disable button

I'm writing a program in netbeans with javaFX
The view has several buttons in it with some bad buttons(like bombs is minesweeper), I'm trying to freeze the program when a bad button is pushed but i don't find how to do it
thanks!
There are various solutions to your problem. 2 among them are simply ignoring the action event or disabling the buttons like this:
public class ButtonAction extends Application {
final BooleanProperty buttonActionProperty = new SimpleBooleanProperty();
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
FlowPane root = new FlowPane();
CheckBox checkBox = new CheckBox( "Enabled");
checkBox.setSelected(true);
// solution 1: check if action is allowed and process it or not
buttonActionProperty.bind( checkBox.selectedProperty());
Button button = new Button( "Click Me");
button.setOnAction(e -> {
if( buttonActionProperty.get()) {
System.out.println( "Allowed, processing action");
} else {
System.out.println( "Not allowed, no action");
}
});
// solution 2: remove comments to activate the code
// button.disableProperty().bind(buttonActionProperty.not());
root.getChildren().addAll(checkBox, button);
primaryStage.setScene(new Scene(root, 600, 200));
primaryStage.show();
}
}
Add a ROOT typed event filter that consumes all kind of events (mouse, keyboard etc.)
btnThatHasHiddenMine.setOnAction(( ActionEvent event ) ->
{
System.out.println("Ohh no! You just stepped over the mine!");
getGameboardPane().addEventFilter( EventType.ROOT, Event::consume );
});
Add the filter to your GameboardPane only, since we don't want to freeze other part of the app.

Resources