In a tree table view, we can re-arrange the columns by dragging the column headers.
I want to restrict the user from dragging the first column alone. Which means my first column should be the first column all the time.
Is this possible?
Thanks in advance.
This is a simple example where I am storing the column arrangement in a temporary list and when ever we are trying to move or replace the first column we are resetting the column arrangement.
!change.getList().get(0).equals(col1)
checks if the col1 is still at the first location after the change. If not, we replace it with the old list.
MCVE
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class FixFiestColumnTable extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
final TableView tableView = new TableView();
TableColumn col1 = new TableColumn("Col 1");
TableColumn col2 = new TableColumn("Col 2");
TableColumn col3 = new TableColumn("Col 3");
tableView.getColumns().setAll(col1, col2, col3);
tableView.getColumns().addListener(new ListChangeListener() {
public ObservableList<TableColumn> tempList = FXCollections.observableArrayList();
#Override
public void onChanged(Change change) {
change.next();
if (change.wasReplaced() && !change.getList().get(0).equals(col1)) {
tableView.getColumns().setAll(tempList);
}
tempList.setAll(change.getList());
}
});
stage.setScene(new Scene(tableView));
stage.show();
}
}
There's no API for that. A solution according to this post is to revert the changes using a ChangeListener.
In your case you'd have to check if the 1st column changes and only revert then.
Here's an example:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.stage.Stage;
public class TreeTableTest extends Application {
#SuppressWarnings({ "unchecked", "rawtypes" })
#Override
public void start(Stage stage) {
final TreeTableView treeTableView = new TreeTableView();
TreeTableColumn c1 = new TreeTableColumn("1");
TreeTableColumn c2 = new TreeTableColumn("2");
TreeTableColumn c3 = new TreeTableColumn("3");
TreeTableColumn c4 = new TreeTableColumn("4");
treeTableView.getColumns().setAll(c1, c2, c3, c4);
treeTableView.getColumns().addListener(new ListChangeListener() {
public boolean suspended;
#Override
public void onChanged(Change change) {
change.next();
if (change.wasReplaced() && !suspended) {
List<TreeTableColumn> oldList = new ArrayList<>(change.getRemoved());
List<TreeTableColumn> newList = new ArrayList<>(treeTableView.getColumns());
// first column changed => revert to original list
if (oldList.get(0) != newList.get(0)) {
this.suspended = true;
treeTableView.getColumns().setAll(oldList);
this.suspended = false;
}
}
}
});
stage.setScene(new Scene(treeTableView));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Related
I am making a Editable ComboBox which show any values contain the input and it works fine.
But the problem is in the input field, whenever i typed Space or arrow buttons the input field keep reseting.
I tried setonKeyPressed and setonKeyTyped too but it isn't solve the problem.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
ObservableList<String> fruit = FXCollections.observableArrayList();
fruit.add("apple");
fruit.add("orange");
fruit.add("banana");
ComboBox myComboBox = new ComboBox();
myComboBox.setEditable(true);
myComboBox.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent keyEvent) {
myComboBox.getItems().clear();
myComboBox.show();
String input = myComboBox.getEditor().getText();
for ( int i = 0 ; i < fruit.size(); i++) {
if(fruit.get(i).contains(input)) { //Check if the list contains the input
myComboBox.getItems().add(fruit.get(i));
}
}
}
});
HBox hbox = new HBox(myComboBox);
primaryStage.setScene(new Scene(hbox, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I have a table view that shows the time sheets of employees working hours on different projects, from Monday to Friday. The data source is a list of time sheet classes with float properties to each day of the week. I would like to, for instance, show a value that adds all the hours from the Monday column and show a Monday Hours total. I thought it would be easy to do with a little research because, to me, wanting a column total would be common in data driven applications that would use TableViews but I can't seem to find an elegant answer, or really any answer at all. It would be easier if I could just calculate a column total whenever the list of timesheets changed, but I also have to listen for when the column values change/are edited by the user. Any ideas?
Here is a non-tornadofx version. In setOnEditCommit, update the observable list and sum the column.
Main
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class App extends Application
{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage)
{
Label total = new Label("0");
ObservableList<Time> data = FXCollections.observableArrayList();
data.add(new Time(0));
data.add(new Time(3));
TableView<Time> tableView = new TableView();
tableView.setEditable(true);
tableView.setItems(data);
total.setText(Integer.toString(data.stream().mapToInt(Time::getHours).sum()));
TableColumn<Time, Integer> column1 = new TableColumn("Time");
column1.setCellValueFactory(new PropertyValueFactory<>("hours"));
column1.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<Integer>()
{
#Override
public String toString(Integer t)
{
return Integer.toString(t);
}
#Override
public Integer fromString(String string)
{
return Integer.parseInt(string);
}
}));
column1.setOnEditCommit((CellEditEvent<Time, Integer> t) -> {
((Time) t.getTableView().getItems().get(
t.getTablePosition().getRow())).setHours(t.getNewValue());
total.setText(Integer.toString(data.stream().mapToInt(Time::getHours).sum()));
});;
tableView.getColumns().add(column1);
VBox vbox = new VBox(tableView, total);
Scene scene = new Scene(vbox);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Time
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
public class Time
{
private final IntegerProperty hours = new SimpleIntegerProperty();
public Time(int hours)
{
this.hours.set(hours);
}
public IntegerProperty hoursProperty()
{
return hours;
}
public void setHours(int hours)
{
this.hours.set(hours);
}
public Integer getHours()
{
return this.hours.getValue();
}
}
i have a textfield with autocomplete and i want to show button near each item appeared into that list
this is my code
List<String> s = ms.getUsernames(ms.getUser(7).getListamis());
TextFields.bindAutoCompletion(txtsearch, s);
this is the method getusernames
public List<String> getUsernames(String list_amis) {
List<String> ls = new ArrayList<>();
String [] idmember = list_amis.split("/");
for (String i : idmember) {
ls.add(getUser(Integer.parseInt(i)).getUsername());
}
return ls;
}
this is my output
i want to add a button near testing as a result i can get its ID
This is the solution I came up with. There certainly is a better way that is more elegant and works better, but I guess this would work for many situations. You would have to do something about the size of the ListView, though, and I didn't test this in an environment in which the appearing ListView might change something about the design of the rest of the UI. I suggest putting the whole thing into a PopOver or something.
import java.util.function.Predicate;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class NewFXMain extends Application {
#Override
public void start(Stage primaryStage) {
ObservableList<String> list = FXCollections.observableArrayList("one","two","three");
FilteredList<String> filteredList = new FilteredList<>(list);
VBox box = new VBox();
TextField textField = new TextField();
textField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
filteredList.setPredicate(new Predicate<String>() {
#Override
public boolean test(String s){
return s.toLowerCase().contains(newValue.toLowerCase());
}
});
}
});
ListView listView = new ListView();
listView.setItems(filteredList);
listView.visibleProperty().bind(textField.textProperty().isNotEmpty());
listView.setCellFactory(new Callback() {
#Override
public Object call(Object param) {
ListCell cell = new ListCell(){
#Override
public void updateItem(Object item, boolean empty){
if(item != null && !empty){
super.updateItem(item, empty);
HBox contentBox = new HBox();
Label label = new Label(item.toString());
Button button = new Button("delete");
HBox separator = new HBox();
HBox.setHgrow(separator, Priority.ALWAYS);
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println(item);
}
});
contentBox.getChildren().addAll(label, separator, button);
setGraphic(contentBox);
}else{
setText(null);
setGraphic(null);
}
}
};
return cell;
}
});
box.getChildren().addAll(textField,listView);
StackPane root = new StackPane();
root.getChildren().add(box);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Autocomplete");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I'm having some issues with the Constrained Resize Policy for a TableView inside a ScrollPane.
It seems as though the headings do not line up completely with its column. On scroll or resize the columns snap to their correct position.
I created a small example to demonstrate:
import java.util.ArrayList;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Test extends Application
{
public static void main(String[] args) throws Exception
{
launch(args);
}
#Override
public void start(Stage primarystage) throws Exception
{
// Create layout
VBox root = new VBox();
TableView<TableObject> table = new TableView<TableObject>();
TableColumn<TableObject, String> col1 = new TableColumn<TableObject, String>("Column 1");
TableColumn<TableObject, String> col2 = new TableColumn<TableObject, String>("Column 2");
table.getColumns().addAll(col1, col2);
col1.setCellValueFactory(new PropertyValueFactory<TableObject, String>("column1"));
col2.setCellValueFactory(new PropertyValueFactory<TableObject, String>("column2"));
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
root.getChildren().add(table);
ScrollPane scrollpane = new ScrollPane();
scrollpane.setFitToWidth(true);
scrollpane.setFitToHeight(true);
scrollpane.setPrefSize(500, 200);
scrollpane.setContent(root);
// Create and show scene
Scene scene = new Scene(scrollpane);
primarystage.setScene(scene);
primarystage.show();
// Populate table
ArrayList<TableObject> data = new ArrayList<TableObject>();
for (int i = 0; i < 20;)
{
TableObject entry = new TableObject(String.valueOf(i++), String.valueOf(i++));
data.add(entry);
}
table.setItems(FXCollections.observableArrayList(data));
}
public class TableObject
{
private StringProperty column1;
private StringProperty column2;
public TableObject(String col1, String col2)
{
column1 = new SimpleStringProperty(col1);
column2 = new SimpleStringProperty(col2);
}
public StringProperty column1Property()
{
return column1;
}
public StringProperty column2Property()
{
return column2;
}
}
}
The result is this:
Is there perhaps something I am missing here?
Thanks
just show the stage after setting table items:
stage.show();
table.setItems(FXCollections.observableArrayList(data));
I am working with Table in Java FX. The code is below :
package addsubject;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class AddSubject extends Application {
private TableView<Subject> table = new TableView<Subject>();
private final ObservableList<Subject> data
= FXCollections.observableArrayList(new Subject("Mobile Computing", "5623"));
final HBox hb = new HBox();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Add Subject");
stage.setWidth(700);
stage.setHeight(600);
final Label label = new Label("Subject Details");
label.setFont(new Font("Calibri", 20));
table.setEditable(true);
TableColumn sub = new TableColumn("Subject Name");
sub.setMinWidth(400);
sub.setCellValueFactory(
new PropertyValueFactory<Subject, String>("sub"));
sub.setCellFactory(TextFieldTableCell.forTableColumn());
sub.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Subject, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Subject, String> t) {
((Subject) t.getTableView().getItems().get(
t.getTablePosition().getRow())).setSubName(t.getNewValue());
}
}
);
TableColumn code = new TableColumn("Subject Code");
code.setMinWidth(150);
code.setCellValueFactory(
new PropertyValueFactory<Subject, String>("code"));
code.setCellFactory(TextFieldTableCell.forTableColumn());
code.setCellFactory(TextFieldTableCell.forTableColumn());
code.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Subject, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Subject, String> t) {
((Subject) t.getTableView().getItems().get(
t.getTablePosition().getRow())).setSubCode(t.getNewValue());
}
}
);
table.setItems(data);
table.getColumns().addAll(sub, code);
final TextField addSubName = new TextField();
addSubName.setPromptText("Subject Name");
addSubName.setPrefWidth(350);
final TextField addCode = new TextField();
addCode.setPrefWidth(150);
addCode.setPromptText("Subject Code");
final Button addButton = new Button("Add");
addButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
data.add(new Subject(
addSubName.getText(),
addCode.getText()));
addSubName.clear();
addCode.clear();
}
});
hb.getChildren().addAll(addSubName, addCode, addButton);
hb.setSpacing(5);
final VBox vbox = new VBox();
vbox.setSpacing(10);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table, hb);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
public static class Subject {
private final SimpleStringProperty sub;
private final SimpleStringProperty code;
private Subject(String subName, String subCode) {
this.sub = new SimpleStringProperty(subName);
this.code = new SimpleStringProperty(subCode);
}
public String getSubName() {
return sub.get();
}
public void setSubName(String subName) {
sub.set(subName);
}
public String getSubCode() {
return code.get();
}
public void setSubCode(String subCode) {
code.set(subCode);
}
}
}
I will say its working.
When I run the code, the Table should contain one row of information which is stored in 'data'. It is not displayed in the table when I run the code. How can I make it displayed ?
Next thing is to add new data to the Table when the 'Add' button is pressed after filling the 2 TextFields. I filled the 2 Text Fields, pressed the button and nothing appeared in the Table. How can I make it appear ?
The PropertyValueFactories are wrong. For example
new PropertyValueFactory<Subject, String>("sub")
This means your data object should have a method getSub() to return the value. But yours is
public String getSubName() {
return sub.get();
}
Either rename the Getter to getSub() or use new PropertyValueFactory<Subject, String>("subName")
The same applies to subject code.
You should read about JavaBeans naming conventions. Or this article on JavaFX Properties and Binding
Try implementing the following functions:
public StringProperty subProperty(){
return sub;
}
public StringProperty codeProperty(){
return code;
}
Why are these members final?