How to disable the arrow button in JavaFX combo box - javafx

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();
}
}

Related

JavaFX MenuItem, handling the event

I'm developing an small application and I have a problem when creating the menu bar.
This is my start method:
public void start(#SuppressWarnings("exports") Stage prymaryStage) throws Exception {
// Stats menu
Menu statsMenu = new Menu("Stats");
// PairName menu
Menu pairNameMenu = new Menu("Choose pair");
// Stats Menu items
MenuItem gStats = new MenuItem("General stats");
// Pair list
ArrayList<String> pairNameList = DatabaseMethods.returnPairNameList();
// PairName items (probably i will have to change)
for (String item : pairNameList) {
pairNameMenu.getItems().add(new MenuItem(item));
}
statsMenu.getItems().addAll(gStats, pairNameMenu);
// Main menu bar
MenuBar menuBar = new MenuBar();
menuBar.getMenus().addAll(statsMenu);
// BorderPane settings
BorderPane borderPane = new BorderPane();
borderPane.setTop(menuBar);
Scene scene = new Scene(borderPane, 1200, 800);
prymaryStage.setTitle("English minimal pair training");
prymaryStage.setScene(scene);
prymaryStage.show();
}
The problem I have is in this part of the code:
ArrayList<String> pairNameList = DatabaseMethods.returnPairNameList();
// PairName items (probably i will have to change)
for (String item : pairNameList) {
pairNameMenu.getItems().add(new MenuItem(item));
}
I was trying to create the items of a submenu from an ArrayList. This data is fetch from a database and the data is returned in form of an ArrayList. I didn't find any other way to do the menu items than pairNameMenu.getItems().add(new MenuItem(item)); inside the for loop.
Now I want to handle the click in the items but I don't know how to do it. I've tried with .setOnAction but Eclipse says the .add(new MenuItem(item)) can't be use in that case and recomends .addAll and the same happens, Eclipse says that's an error and recomends .add
I tried to add this code after new MenuItem(item)
.addEventHandler(new EventHandler<ActionEvent>() {
public void handle(ActionEvent even) {
}
})
But it didn't work either.
I'm pretty new to Java and JavaFX, this is my first project so sorry if this is a very basic question.
Thank you for your time
You have to loop through pairNameMenu items after you have created and added all the items to pairNameMenu:
pairNameMenu.getItems().foreach((item) ->{
item.addEventHandler.....
....
....
});
or do something like below when creating the MenuItems:
for (String item : pairNameList) {
MenuItem tempMenuItem = new MenuItem(item);
tempMenuItem..addEventHandler.....
....
....
pairNameMenu.getItems().add(tempMenuItem);
}

How to Generate Message According to Values in Multiple Fields?

I am building an application using JavaFX. What I am trying to do is generate a message according to the user input values. So there are one text-field and one combo-box and one check-box per row and there are many rows like the following.
Let's say I will generate three different messages according to the user values. So I need to check whether those fields are empty or not and check each field's value to generate a specific message. Checking fields are okay for just three rows like the above. But I have 10 fields. So I have to check each and generate or append my own message. And also if the user checked the check-box need to group all checked row values. So what I am asking is there any good way (best practice) to achieve what I need or an easy one also? I have tried with HashMap and ArrayList. But those are not working for this.
Really appreciate it if anybody can help me. Thanks in advance.
I would probably recommend a custom node that you create on your own like below. This example is not supposed to have the same functionality as your application but just to show how to create and use custom nodes. I kept your idea in mind when creating this example it has your textfield combobox and checkbox and they are a little easier to manage. Give it a run and let me know if you have any questions
public class Main extends Application {
#Override
public void start(Stage stage) {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
ArrayList<String> itemList = new ArrayList<>(Arrays.asList("Dog", "Cat", "Turkey"));
ArrayList<HBoxRow> hBoxRowArrayList = new ArrayList<>();
for (int i = 0; i<3; i++) {
HBoxRow hBoxRow = new HBoxRow();
hBoxRow.setComboBoxValues(FXCollections.observableList(itemList));
hBoxRowArrayList.add(hBoxRow);
vBox.getChildren().add(hBoxRow.gethBox());
}
Button printTextfieldsButton = new Button("Print Textfields");
printTextfieldsButton.setOnAction(event -> {
for (HBoxRow hBoxRow : hBoxRowArrayList) {
System.out.println("hBoxRow.getTextFieldInput() = " + hBoxRow.getTextFieldInput());
}
});
vBox.getChildren().add(printTextfieldsButton);
stage.setScene(new Scene(vBox));
stage.show();
}
//Below is the custom Node
public class HBoxRow {
HBox hBox = new HBox();
ComboBox<String> comboBox = new ComboBox<>();
TextField textField = new TextField();
CheckBox checkBox = new CheckBox();
public HBoxRow(){
hBox.setAlignment(Pos.CENTER);
textField.setPrefWidth(150);
comboBox.setPrefWidth(150);
checkBox.setOnAction(event -> {
textField.setDisable(!textField.isDisabled());
comboBox.setDisable(!comboBox.isDisabled());
});
hBox.getChildren().addAll(checkBox, textField, comboBox);
}
public void setComboBoxValues(ObservableList observableList) {
comboBox.setItems(observableList);
}
public HBox gethBox(){
return hBox;
}
public String getTextFieldInput(){
return textField.getText();
}
}
}

reading and writing file in javafx program

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.

How to handle wrong drop location in JavaFx?

In my GUI I create some dices (ImageView) and I can drag and drop them in one specific GridPane. When I drop a dice into the specific GridPane, the dice disappears from the initial location and it moves to the right position. This works fine only if I choose the right drop location.
The problem is how can I manage the wrong drop location?
Actually if I drop a dice in a wrong location (like outside the Gridpane) the dice disappears like it was moved to the right position.
I want to restore the dice to the original location if the dice isn't placed to the GridPane.
Is there a method can help me to check if I drop into the right location? Or something can prevent to drop into the wrong location?
You can check the transferMode property of the DragEvent passed to the onDragDone event:
dragSource.setOnDragDone(evt -> {
if (evt.getTransferMode() == null) {
System.out.println("drag aborted");
} else {
System.out.println("drag successfully completed");
}
});
Note: this requires you to mark the drag gesture as completed in the onDragDropped event handler using setDropCompleted. Example:
#Override
public void start(Stage primaryStage) {
Button source = new Button("Not dragged yet");
Button target = new Button("target");
HBox root = new HBox(20, source, target);
source.setOnDragDetected(evt -> {
Dragboard db = source.startDragAndDrop(TransferMode.COPY);
ClipboardContent content = new ClipboardContent();
content.putString(source.getText());
db.setContent(content);
});
source.setOnDragDone(evt -> {
source.setText(evt.getTransferMode() == null ? "failure" : "success");
});
target.setOnDragOver(evt -> {
if (evt.getDragboard().hasString()) {
evt.acceptTransferModes(TransferMode.COPY);
evt.consume();
}
});
target.setOnDragDropped(evt -> {
String value = evt.getDragboard().getString();
target.setText(value);
evt.setDropCompleted(true);
evt.consume();
});
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

How to append multicolor text in JavaFx textArea

This is actually my first JavaFx desktop application. Within my application I want to display every event as a log in textarea. I have different log types , error,warning etc. I want to append all these logs inside a textarea with different colors. I tried like this(this is just a sample),
// Method call is like this
logText("Enter Ip address First");
// The method
public void logText(String log){
log = ">> "+ log +"\n";
Text t = new Text();
t.setStyle("-fx-background-color: #DFF2BF;-fx-text-fill: #4F8A10;-fx-font-weight:bold;");
t.setText(log);
txtConsole.appendText(t.toString());
}
With above code I did not get any error but my output is like :
Text[text=">> Enter Ip address First
", x=0.0, y=0.0, alignment=LEFT, origin=BASELINE, boundsType=LOGICAL, font=Font[name=System Regular, family=System, style=Regular, size=12.0], fontSmoothingType=GRAY, fill=0x000000ff]
How can I solve this ? I tried various methods mentioned here in stackoverflow (this is one of them).
*** Please note that this application is for corporate use so I need to be strict to the licenses.
Thanks in advance.
You need to have replace t.toString() with t.getText() in txtConsole.appendText(t.toString())
You can't have colored text in TextArea. Try using TextFlow instead.
You have colored text which you can add to the TextFlow:
public class TextFlowSample extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
TextFlow flow = new TextFlow();
String log = ">> Sample passed \n";
Text t1 = new Text();
t1.setStyle("-fx-fill: #4F8A10;-fx-font-weight:bold;");
t1.setText(log);
Text t2 = new Text();
t2.setStyle("-fx-fill: RED;-fx-font-weight:normal;");
t2.setText(log);
flow.getChildren().addAll(t1, t2);
stage.setScene(new Scene(new StackPane(flow), 300, 250));
stage.show();
}
}
If you have the flexibility to use external library, have a look at RichTextFX

Resources