I am using ControlFx Textfields binding which works find. The thing is that the Suggestion popup values that Contains the inputed value. Like if i type in "M" values will be "Emma", "max", "rosemary", "Mathew". So my main Question is how to make the Suggestion to only bring out values Starting with "M" like "max",""Mathew"
This is my code. It select name from database and add them to an ArrayList
PreparedStatement ps=db.DataBase.getCon().prepareStatement("select name from STUDENTINFO");
ResultSet res=ps.executeQuery();
List list=new ArrayList();
while(res.next()){
list.add(res.getString("name"));
}
TextFields.bindAutoCompletion(textfieldSearch,list);
Here is a sample app that demos your question.
This snippet searches the original list for a substring and returns every item in the list that starts with the substring.
this snippet should work with your code.
Key code:
TextFields.bindAutoCompletion(textFieldSearch, t -> {
return list.stream().filter(elem ->
{
return elem.toLowerCase().startsWith(t.getUserText().toLowerCase());
}).collect(Collectors.toList());
});
Full app:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import org.controlsfx.control.textfield.TextFields;
/**
*
* #author blj0011
*/
public class JavaFXApplication193 extends Application
{
#Override
public void start(Stage primaryStage)
{
List<String> list = new ArrayList();
list.add("Max");
list.add("moon");
list.add("am");
list.add("two");
TextField textFieldSearch = new TextField();
TextFields.bindAutoCompletion(textFieldSearch, t -> {
return list.stream().filter(elem
-> {
return elem.toLowerCase().startsWith(t.getUserText().toLowerCase());
}).collect(Collectors.toList());
});
StackPane root = new StackPane(textFieldSearch);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
Related
I implemented a small chart with a button to rotate the slice inside the chart, in order to do this, I implemented the following steps:
Copy the actual data of the chart into a new ObservableList "ActualData"
Create a new ObservableList "NewList" empty
Add to NewList the last value of ActualData, and then add the remaing values ( ind: 0,1,2,3 )
Clear the data of the chart
Enter using a loop all the data of the new list "NewList"
My questions are:
Is there a better way to implement such action?
Is a way to delete the ugly spaces between each slice?
Thanks
package application;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.PieChart.Data;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
PieChart pieChart = new PieChart();
int counter = 0;
EnterValues(pieChart);
pieChart.setLegendVisible(false);
pieChart.setClockwise(true);
pieChart.setStartAngle(90);
StackPane.setAlignment(pieChart, Pos.TOP_CENTER);
Button button = new Button("Change Values");
StackPane.setAlignment(button, Pos.BOTTOM_CENTER);
StackPane stackPane = new StackPane();
stackPane.setPrefSize(500, 500);
stackPane.getChildren().add(pieChart);
stackPane.getChildren().add(button);
Scene scene = new Scene(stackPane);
primaryStage.setTitle("Test");
primaryStage.setMinHeight(500);
primaryStage.setMinWidth(500);
primaryStage.setScene(scene);
primaryStage.show();
button.setOnAction((EventHandler<ActionEvent>) new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
// GET DATA FROM CURRENT LIST
ObservableList<Data> ActualData = pieChart.getData();
// CREATE NEW EMPTY LIST
ObservableList<Data> NewList = FXCollections.observableArrayList();;
// ADD ITEMS TO NEW LIST ( LAST BECOMES THE FIRST ONE )
NewList.add(ActualData.get(4));
NewList.add(ActualData.get(0));
NewList.add(ActualData.get(1));
NewList.add(ActualData.get(2));
NewList.add(ActualData.get(3));
// CLEAR DATA FROM CURRENT CHART
pieChart.getData().clear();
// ENTER NEW DATA TO CHART
for(int i = 0;i<NewList.size();i++)
{
PieChart.Data slice = new PieChart.Data(NewList.get(i).getName(),NewList.get(i).getPieValue());
pieChart.getData().add(slice);
}
}
});
}
public void EnterValues(PieChart chart) {
PieChart.Data slice1 = new PieChart.Data("USA", 30);
PieChart.Data slice2 = new PieChart.Data("EU", 20);
PieChart.Data slice3 = new PieChart.Data("China", 100);
PieChart.Data slice4 = new PieChart.Data("Japan", 50);
PieChart.Data slice5 = new PieChart.Data("Others", 10);
chart.getData().add(slice1);
chart.getData().add(slice2);
chart.getData().add(slice3);
chart.getData().add(slice4);
chart.getData().add(slice5);
}
public static void main(String[] args) {
Application.launch(args);
}
}
In theory, you should just be able to rotate the pie chart data. However, because the chart API has the Node that represents the data as a part of the data class (which represents a major design flaw in my opinion, and renders the Chart API as not suitable for production code), this results in a "duplicate children added" error.
So it seems the only way around this is to create a deep copy of the data, and rotate that list, which is essentially what you do. Note there's no real need to create an ObservableList for the data copy; a plain old List (which has less overhead) will do. So your code can be reduced a little:
button.setOnAction(e -> {
List<Data> dataCopy = new ArrayList<>();
for (Data d : pieChart.getData())
dataCopy.add(new Data(d.getName(), d.getPieValue()));
Collections.rotate(dataCopy, 1);
pieChart.getData().setAll(dataCopy);
});
so I'm writing a javafx app and I need to be able to select the cells from the list view (for copy paste purposes) but I don't want to make it editable, I mean, the content cannot be changed unless I want to (allowing it through a button, for example).
So I have the following code:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
List<String> contacts = new ArrayList<>(Arrays.asList("968787522","3424234234","2343234324"));
ListView<String> contactsList = new ListView();
contactsList.setItems(FXCollections.observableArrayList(contacts));
//this gives me the ability to edit the row as text field but I want this text field to not be editable
contactsList.setCellFactory(TextFieldListCell.forListView());
StackPane pane = new StackPane();
pane.getChildren().add(contactsList);
primaryStage.setScene(new Scene(pane, 300, 275));
primaryStage.show(); }
public static void main(String[] args) {
launch(args);
}
}
and if I set 'contactsList' as not editable, I'm not able to edit, neither select.
As you can see (image bellow),I'm editing the cell, but I want to be able to select the text(not the item), but I don't want to be able to delete characters (text selectable but not editable).
so after breaking my head off, lots of research and API reading, I came up with a solution. This does EXACTLY what I wanted to do. Here is the demo if someone needs it ;)
So the idea is, each time we want to select the content of a row we need to select the row, get the textField and set the editing to true or false, (every time).
So in the demo that I made, I placed a button so you can toggle the editing to true or false to be sure that's is working, and how is working.
Cheers.
I commented some of the code for better understanding, if you have any questions about this just let me know.
package sample;
import com.sun.javafx.scene.control.skin.VirtualFlow;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main extends Application {
private boolean editable = false;
public static IndexedCell getCell(final Control control, final int index) {
return getVirtualFlow(control).getCell(index);
}
public static VirtualFlow<?> getVirtualFlow(Control control) {
Group group = new Group();
Scene scene = new Scene(group);
Stage stage = new Stage();
if(control.getScene() == null) {
group.getChildren().setAll(control);
stage.setScene(scene);
stage.show();
}
VirtualFlow<?>flow = (VirtualFlow<?>) control.lookup("#virtual-flow");
return flow;
}
public void setEditable(ListView contactsList){
//this needs to be done since we need to run our code after the text field was rendered
//so we need to invoke our code after this happens, if not it will throw a null pointer...
Platform.runLater(() -> {
//this is one of the most important guys because javafx api says that
//TextFieldListCell.forListView() allows editing of the cell content when the cell is double-clicked,
// or when {#link ListView#edit(int)} is called.
int rowIndex = contactsList.getSelectionModel().getSelectedIndex();
contactsList.edit(rowIndex);
ListCell rootCell = (ListCell) getCell(contactsList, rowIndex);
TextField textField = (TextField) rootCell.getGraphic();
textField.setEditable(editable);
});
}
#Override
public void start(Stage primaryStage) throws Exception{
List<String> contacts = new ArrayList<>(Arrays.asList("968787522","3424234234","2343234324"));
ListView<String> contactsList = new ListView();
contactsList.setItems(FXCollections.observableArrayList(contacts));
contactsList.setEditable(true);
//this gives me the ability to edit the row as text field but I want this text field to not be editable
contactsList.setCellFactory(TextFieldListCell.forListView());
contactsList.setOnEditStart(e -> {
setEditable(contactsList);
});
StackPane pane = new StackPane();
Button editBtn = new Button("Toggle edit");
editBtn.setOnAction(event -> {
editable = !editable;
editBtn.setText("Editing = " + editable);
//to cancel any editing that might be occuring
contactsList.getSelectionModel().clearSelection();
});
pane.getChildren().addAll(contactsList,editBtn);
primaryStage.setScene(new Scene(pane, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If I understand you correctly, it is not necessary to set the listview to 'not editable', as the default behaviour should suffice for your purpose. Take a look at this code, for example:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class NewFXMain extends Application {
#Override
public void start(Stage primaryStage) {
ListView listView = new ListView();
listView.getItems().addAll("one","two","three","four");
listView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println(listView.getSelectionModel().getSelectedItem());
}
});
StackPane root = new StackPane();
root.getChildren().add(listView);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("ListView Example");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I changed nothing about the editable-property of the ListView, but I can select every item, without being able to edit it (in the sense of changing its value). You can easily add an EventHandler to the ListView to perform whatever operation you want to perform. You could also add an EventHandler to every cell of the ListView by manipulating the CellFactory, as shown in this answer: How to handle ListView item clicked action?
Here's what works for me:
TableView<DataBean> table = new TableView<>();
table.setItems(...); // list of some DataBean objects with dataBeanField proprty
table.setEditable(true);
TableColumn<DataBean, String> column = new TableColumn<>("SomeData");
column.setCellValueFactory(new PropertyValueFactory<DataBean, String>("dataBeanField"));
column.setCellFactory(new Callback<TableColumn<DataBean, String>, TableCell<DataBean, String>>() {
#Override
public TableCell<DataBean, String> call(TableColumn<DataBean, String> param) {
return new TextFieldTableCell<>(new DefaultStringConverter() {
private String defaultValue = "";
#Override
public String fromString(String newValue) {
return super.fromString(defaultValue);
}
#Override
public String toString(String value) {
return defaultValue = super.toString(value);
}
});
}
});
Basically my code is like this:
fileOpener.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(final ActionEvent e) {
myFileList.add(openMusicTracks.showOpenDialog(window));
System.out.println(myFileList.getName(0)); //prints file name so I know this works
}
});
I want the add method (that's inside of the EventHandler) to actually edit the arraylist for everywhere else so that later when I reference it in
ObservableList<String> playList = FXCollections.observableArrayList ();
for(int i = 0; i < myFileList.size(); i++) {
playList.add(i, myFileList.get(i).getName());
System.out.println(myFileList.getName(0)); //doesn't print the file name, so I know this doesn't work.
}
the arraylist won't be empty. How do I do this? I'm sorry if there's a more elegant way to word this, but I have honestly no idea how to research this, I've tried. Thanks.
A simple example which shows how can an ArrayList be shared between methods.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
public class Main extends Application {
private List<String> list = new ArrayList<>();
#Override
public void start(Stage primaryStage) {
Button add = new Button("Add");
Button display = new Button("Show");
// Add Items
add.setOnAction(event -> list.add("Item"));
// Display Items
display.setOnAction(e -> {
printAndClear();
});
VBox root = new VBox(10, add, display);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 200, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
private void printAndClear() {
list.forEach(System.out::println);
list.clear();
}
public static void main(String[] args) {
launch(args);
}
}
Basically, I have managed to create a comboBoxTableCell within my tableView. The only problem is that I cannot type in any user input and without this function, the comboBoxTableCell is no different from a Choice box table cell to me.
Now from looking at this, if I can set setComboBoxEditable(true)for comboBoxTableCell, then I think my problem will be sorted. Question is how do I do this in the following line of code?
public TableColumn<Trade,String> tableColumnX;
tableColumnX.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
tableColumnX.setCellFactory(ComboBoxTableCell.forTableColumn(obsList));
I have taken a second attempt on this using what I saw on this post,
tableColumnX.setCellFactory(new Callback<TableColumn<Product, String>,ComboBoxTableCell<Product,String>>() {
#Override
public ComboBoxTableCell<Product, String> call(TableColumn<Product, String> param) {
ComboBoxTableCell ct= new ComboBoxTableCell<>();
ct.setComboBoxEditable(true);
return ct;
}});
This time I am getting an error:
The method setCellFactory(Callback<TableColumn<Product,String>,TableCell<Product,String>>) in the type TableColumn<Product,String> is not applicable for the arguments (new Callback<TableColumn<Product,String>,ComboBoxTableCell<Product,String>>(){})
If I am not clear on any parts of the question, please let me know. I can add in more details for clarification.
Use Callback<TableColumn<Product, String>,TableCell<Product,String>>() instead of Callback<TableColumn<Product, String>,ComboBoxTableCell<Product,String>>()
Try this :
tableColumnX.setCellFactory(new Callback<TableColumn<Product, String>,TableCell<Product,String>>() {
#Override
public TableCell<Product, String> call(TableColumn<Product, String> param) {
ComboBoxTableCell<Product, String> ct= new ComboBoxTableCell<>();
ct.setComboBoxEditable(true);
return ct;
}});
Here is an Example
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.ComboBoxTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
/**
*
* #author
*/
public class Javafx_test extends Application {
#Override
public void start(Stage stage) {
TableColumn<String, String> tableColumn = new TableColumn<>("Column");
tableColumn.setCellValueFactory(cellData
-> {
return new SimpleStringProperty(cellData.getValue());
}
);
tableColumn.setCellFactory(tableCol -> {
ComboBoxTableCell<String, String> ct = new ComboBoxTableCell<>();
ct.getItems().addAll("1", "2");
ct.setComboBoxEditable(true);
return ct;
});
TableView<String> tableView = new TableView<>();
tableView.setEditable(true);
tableView.getColumns().add(tableColumn);
tableView.getItems().addAll("4", "5");
BorderPane root = new BorderPane(tableView);
Scene scene = new Scene(root, 200, 100);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I'd like to have a ComboBox with following options:
(combobox employment:)
- Education
- Automotive
- (...)
- OTHER <-- editable
If user selects "other", he could edit the item in the ComboBox but all the other options would be non-editable.
Is that possible or should I just display additional TextField when user selects "other"?
There is the option to make a ComboBox editable:
combobox.setEditable(true);
You can only make all entries editable with this function though.
Read more at: http://docs.oracle.com/javafx/2/ui_controls/combo-box.htm
As far as I know you can only add Strings to the ObservableList which contains the content of your Combobox. Therefore you can not add a Node (in this case a Textfield).
Same goes for the ChoiceBox, if you add a TextField there (which is technically possible) but you will only get the .toString displayed when you actually use it.
Therefore you are probably best of creating a seperate field.
Just as an idea: You can quickly make a popup window when the user clicks "Other", in which whatever other is entered. Then, when you close the window or click enter or whatever, this value is added to the ObservableList. Would make it look nicer I guess...
Use this example:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package comboboxeditable;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author reegan
*/
public class ComboBoxEditable extends Application {
Node sub;
#Override
public void start(Stage primaryStage) {
ComboBox mainCombo = new ComboBox(listofCombo());
Button save = new Button("Save");
sub = new ComboBox(listofCombo());
HBox root = new HBox(20);
root.getChildren().addAll(mainCombo, sub,save);
mainCombo.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
if (newValue == "Others") {
sub = new TextField();
} else {
sub = new ComboBox(listofCombo());
}
root.getChildren().remove(1);
root.getChildren().add(1, sub);
}
});
save.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println(mainCombo.getValue());
if(sub.getClass() == ComboBox.class) {
ComboBox sub1 = (ComboBox)sub;
System.out.println(sub1.getValue());
} else {
TextField field = (TextField)sub;
System.out.println(field.getText());
}
}
});
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public ObservableList listofCombo() {
ObservableList<String> list = FXCollections.observableArrayList();
for (int i = 0; i < 10; i++) {
list.add(String.valueOf("Hello" + i));
}
list.add("Others");
return list;
}
}