In my GUI i am having a TABLEVIEW and a HTMLEditor.
TableView having two columns. 1st column without edit feature. 2nd column have edit option.
for HTMLEditor i have written setOnKeyPressed property. In that property, in handle method i am trying to update 2nd column data. But data is not reflecting at all in TableView Control . But when i try to print data for 2nd column it is showing HTMLEditor's data only. But the HTMLEditor's data is not reflecting in TableView 2nd Column.
Following is my code
public class BinderDocumnetController implements Initializable {
public BinderDocumnetController() {
this.details = FXCollections.observableArrayList();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
tblName.setCellValueFactory(new PropertyValueFactory<CData, String>("strName"));
tblRemarks.setCellValueFactory(new PropertyValueFactory<CData, String>("strRemarks"));
tblData.setItems(details);
tblData.setEditable(true);
Callback<TableColumn<CData, String>, TableCell<CData, String>> para4cellFactory
= new Callback<TableColumn<CData, String>, TableCell<CData, String>>() {
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
tblRemarks.setCellFactory(para4cellFactory);
htmlEditor.setOnKeyReleased(new EventHandler<KeyEvent>()
{
#Override
public void handle(KeyEvent t) {
textField.setText(htmlEditor.getHtmlText());
System.out.println("row no. is "+tblData.getSelectionModel().getSelectedIndex());
tblData.getItems().get(tblData.getSelectionModel().getSelectedIndex()).setStrRemarks(htmlEditor.getHtmlText());
System.out.println(" data at row no. "+tblData.getSelectionModel().getSelectedIndex()+"is");
System.out.println(" "+tblData.getItems().get(tblData.getSelectionModel().getSelectedIndex()).getStrRemarks());
}
}
);
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
htmlEditor.setHtmlText(textField.getText());
}
});
}
public void onbtnAddClicked(){
System.out.println(" in add");
CData cdata= new CData("XYZ","done");
details.add(cdata);
}
#FXML
HTMLEditor htmlEditor;
#FXML
TextField textField;
ObservableList<CData> details;
#FXML
TableView<CData> tblData;
#FXML
TableColumn<CData,String> tblRemarks,tblName;
#FXML
Button btnAdd;
class EditingCell extends TableCell<Object, String> {
private TextField textField;
public EditingCell() {
}
#Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2) {
if (!arg2) {
commitEdit(textField.getText());
}
}
});
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
htmlEditor.setHtmlText(textField.getText());
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
}
following is CData.java code
public class CData {
SimpleStringProperty strName = new SimpleStringProperty("");
SimpleStringProperty strRemarks = new SimpleStringProperty("");
public CData(String strName,String strRemarks) {
setStrName(strName);
setStrRemarks(strRemarks);
}
public String getStrName() {
return strName.get();
}
public void setStrName(String strName) {
this.strName.set(strName);
}
public String getStrRemarks() {
return strRemarks.get();
}
public void setStrRemarks(String strRemarks) {
this.strRemarks.set(strRemarks);
}
public SimpleStringProperty strName() {
return strName;
}
public SimpleStringProperty strRemarks() {
System.out.println("\nRemarks: "+strRemarks.get()+"\n\n");
return strRemarks;
}
}
public SimpleStringProperty strNameProperty() {
return strName;
}
public SimpleStringProperty strRemarksProperty() {
System.out.println("\nRemarks: "+strRemarks.get()+"\n\n");
return strRemarks;
}
Done changes to above code now its working
Related
I have the following code to create a TreeTableView with a CheckComboBox in one column.
public class TreeTableViewSample extends Application {
List<Employee> employees = Arrays.<Employee>asList(
new Employee("Ethan Williams", ""),
new Employee("Emma Jones", ""),
new Employee("Michael Brown", ""),
new Employee("Anna Black", ""),
new Employee("Rodger York", ""),
new Employee("Susan Collins", ""));
final TreeItem<Employee> root = new TreeItem<>(new Employee("Department", ""));
final TreeItem<Employee> root1 = new TreeItem<>(new Employee("Executive Department", ""));
final TreeItem<Employee> root2 = new TreeItem<>(new Employee("Sales Department", ""));
public static void main(String[] args) {
Application.launch(TreeTableViewSample.class, args);
}
#Override
public void start(Stage stage) {
root.setExpanded(true);
employees.stream().forEach((employee) -> {
root1.getChildren().add(new TreeItem<>(employee));
root2.getChildren().add(new TreeItem<>(employee));
});
root.getChildren().addAll(root1, root2);
stage.setTitle("Tree Table View Sample");
final Scene scene = new Scene(new Group(), 400, 400);
scene.setFill(Color.LIGHTGRAY);
Group sceneRoot = (Group) scene.getRoot();
TreeTableColumn<Employee, String> empColumn
= new TreeTableColumn<>("Employee");
empColumn.setPrefWidth(150);
empColumn.setCellValueFactory(
(TreeTableColumn.CellDataFeatures<Employee, String> param)
-> new ReadOnlyStringWrapper(param.getValue().getValue().getName())
);
TreeTableColumn<Employee, String> emailColumn
= new TreeTableColumn<>("Email");
emailColumn.setPrefWidth(190);
emailColumn.setEditable(true);
emailColumn.setCellFactory((TreeTableColumn<Employee, String> p) -> new CheckComboCell());
emailColumn.setCellValueFactory(
(TreeTableColumn.CellDataFeatures<Employee, String> param)
-> new ReadOnlyStringWrapper(param.getValue().getValue().getEmail())
);
TreeTableView<Employee> treeTableView = new TreeTableView<>(root);
treeTableView.setEditable(true);
treeTableView.getColumns().setAll(empColumn, emailColumn);
sceneRoot.getChildren().add(treeTableView);
stage.setScene(scene);
stage.show();
}
public class Employee {
private SimpleStringProperty name;
private SimpleStringProperty email;
public SimpleStringProperty nameProperty() {
if (name == null) {
name = new SimpleStringProperty(this, "name");
}
return name;
}
public SimpleStringProperty emailProperty() {
if (email == null) {
email = new SimpleStringProperty(this, "email");
}
return email;
}
private Employee(String name, String email) {
this.name = new SimpleStringProperty(name);
this.email = new SimpleStringProperty(email);
}
public String getName() {
return name.get();
}
public void setName(String fName) {
name.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
}
Cell Factory Class
public class CheckComboCell extends TreeTableCell<TreeTableViewSample.Employee, String> {
private final ComboBox<CheckComboCellModel> cb = new ComboBox<CheckComboCellModel>() {
#SuppressWarnings("restriction")
#Override
protected javafx.scene.control.Skin<?> createDefaultSkin() {
return new ComboBoxListViewSkin<CheckComboCellModel>(this) {
#Override
protected boolean isHideOnClickEnabled() {
return false;
}
};
}
};
private final ObservableList<CheckComboCellModel> items = FXCollections.observableArrayList();
private final Tooltip tooltip = new Tooltip();
public CheckComboCell() {
super();
populateAllocationType();
cb.setItems(items);
cb.setCellFactory((ListView<CheckComboCellModel> p) -> new ListCell<CheckComboCellModel>() {
private final CheckBox checkBox = new CheckBox();
private BooleanProperty booleanProperty;
{
checkBox.setOnAction(e -> getListView().getSelectionModel().select(getItem()));
}
#Override
protected void updateItem(CheckComboCellModel item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
checkBox.setText(item.toString());
if (booleanProperty != null) {
checkBox.selectedProperty().unbindBidirectional(booleanProperty);
}
booleanProperty = item.checkProperty();
checkBox.selectedProperty().bindBidirectional(booleanProperty);
setGraphic(checkBox);
} else {
setGraphic(null);
setText(null);
}
}
});
cb.setButtonCell(new ListCell<CheckComboCellModel>() {
#Override
protected void updateItem(CheckComboCellModel item, boolean empty) {
super.updateItem(item, empty);
String selected = cb.getItems().stream().filter(i -> i.getCheck())
.map(i -> i + "").collect(Collectors.joining(","));
setText(selected);
}
});
setGraphic(null);
}
private void populateAllocationType() {
items.add(new CheckComboCellModel("mail_1"));
items.add(new CheckComboCellModel("mail_2"));
items.add(new CheckComboCellModel("mail_3"));
items.add(new CheckComboCellModel("mail_4"));
items.add(new CheckComboCellModel("mail_5"));
}
#Override
public void startEdit() {
if (!isEditable() || !getTreeTableView().isEditable() || !getTableColumn().isEditable()) {
return;
}
super.startEdit();
setGraphic(cb);
}
#Override
public void commitEdit(String value) {
super.commitEdit(value);
setGraphic(null);
setText(cb.getButtonCell().getText());
}
#Override
public void cancelEdit() {
super.cancelEdit();
setGraphic(null);
setText(cb.getButtonCell().getText());
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
setText(this.cb.getButtonCell().getText());
setGraphic(null);
}
}
}
Model class
public class CheckComboCellModel {
private final BooleanProperty check = new SimpleBooleanProperty(false);
private final StringProperty item = new SimpleStringProperty();
public CheckComboCellModel() {
}
public CheckComboCellModel(String item) {
this.item.set(item);
}
public CheckComboCellModel(String item, Boolean check) {
this.item.set(item);
this.check.set(check);
}
public BooleanProperty checkProperty() {
return check;
}
public Boolean getCheck() {
return check.getValue();
}
public void setCheck(Boolean value) {
check.set(value);
}
public StringProperty itemProperty() {
return item;
}
public String getItem() {
return item.getValueSafe();
}
public void setItem(String value) {
item.setValue(value);
}
#Override
public String toString() {
return item.getValue();
}
}
With this i get what i expect (i.e) a Column with CheckComboBox. But the issue is:
The application looks like this:
I selected some values
The values are updated in cell
But when the node is minimized
The updated value is displayed in next node. What i am doing wrong ? How can i solve this?
I know my problem is trivilant and solution is on the surface, but I still can't deal with it and so need help. The problem is that TableView ListChangeListener in my code does not show updated changes. I have read many topics, manuals and examples before asked a question
Javafx: Detect ALL changes made to tableView including addition/deletion of table rows and cell edits on any table rows
Java ListChangeListener WasUpdated() doesn't work
https://docs.oracle.com/javase/8/javafx/api/javafx/collections/ListChangeListener.Change.html#wasUpdated--
http://java-buddy.blogspot.com/2014/11/example-of-listchangelistener-for.html
but still can't understand why my code does not work. I have added extractor but it's not helped me.
Here is a part of my code
public class mainTableOverviewController {
#FXML
private TableView<EmailData> emailTableView;
#FXML
private TableColumn<EmailData, String> emailNameColumn;
#FXML
private TableColumn<EmailData, String> emailLoginColumn;
#FXML
private TableColumn<EmailData, String> emailPasswordColumn;
#FXML
private TableColumn<EmailData, String> emailCommentsColumn;
#FXML
private Button handleDeletePerson;
private MainApp mainApp;
public mainTableOverviewController() {
}
#FXML
private void initialize() {
emailTableView.setEditable(true);
emailTableView.getSelectionModel().setCellSelectionEnabled(true);
emailTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
Callback<TableColumn<EmailData, String>, TableCell<EmailData, String>> cellFactory =
new Callback<TableColumn<EmailData, String>, TableCell<EmailData, String>>() {
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
emailNameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
emailNameColumn.setCellFactory(cellFactory);
emailNameColumn.setOnEditCommit(
t -> t.getTableView().getItems().get(
t.getTablePosition().getRow()).setName(t.getNewValue())
);
emailLoginColumn.setCellValueFactory(cellData -> cellData.getValue().loginProperty());
emailLoginColumn.setCellFactory(cellFactory);
emailLoginColumn.setOnEditCommit(
t -> t.getTableView().getItems().get(
t.getTablePosition().getRow()).setLogin(t.getNewValue())
);
emailPasswordColumn.setCellValueFactory(cellData -> cellData.getValue().passwordProperty());
emailPasswordColumn.setCellFactory(cellFactory);
emailPasswordColumn.setOnEditCommit(
t -> t.getTableView().getItems().get(
t.getTablePosition().getRow()).setPassword(t.getNewValue())
);
emailCommentsColumn.setPrefWidth(120);
emailCommentsColumn.setCellValueFactory(cellData -> cellData.getValue().commentsProperty());
emailCommentsColumn.setCellFactory(cellFactory);
emailCommentsColumn.setOnEditCommit(
t -> t.getTableView().getItems().get(
t.getTablePosition().getRow()).setComments(t.getNewValue())
);
emailData.addListener((Change<? extends EmailData> c) -> {
while (c.next()) {
if (c.wasAdded()) {
System.out.println("Added:");
c.getAddedSubList().forEach(System.out::println);
System.out.println();
}
if (c.wasRemoved()) {
System.out.println("Removed:");
c.getRemoved().forEach(System.out::println);
System.out.println();
}
if (c.wasUpdated()) {
System.out.println("Updated:");
emailData.subList(c.getFrom(), c.getTo()).forEach(System.out::println);
System.out.println();
}
}
});
emailTableView.getColumns().setAll(emailNameColumn, emailLoginColumn, emailPasswordColumn, emailCommentsColumn, actionCol);
}
}
#FXML
private void handleDeletePerson() {
int selectedIndex = emailTableView.getSelectionModel().getSelectedIndex();
if (selectedIndex >= 0) {
deletedDataList.add(emailTableView.getItems().get(selectedIndex));
emailTableView.getItems().remove(selectedIndex);
menuItemDisable.set(false);
} else {
nothingSelected();
}
}
class EditingCell extends TableCell<EmailData, String> {
TextField textField;
EditingCell() {
}
#Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
Platform.runLater(new Runnable() {
#Override
public void run() {
textField.requestFocus();
textField.selectAll();
}
});
}
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
emailTableView.getColumns().get(0).setVisible(false);
emailTableView.getColumns().get(0).setVisible(true);
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()
* 2);
textField.focusedProperty().addListener(
new ChangeListener<Boolean>() {
#Override
public void changed(
ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2) {
if (!arg2) {
commitEdit(textField.getText());
}
}
});
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(textField.getText());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
} else if (t.getCode() == KeyCode.TAB) {
commitEdit(textField.getText());
TableColumn nextColumn = getNextColumn(!t.isShiftDown());
if (nextColumn != null) {
getTableView().edit(getTableRow().getIndex(),
nextColumn);
}
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem();
}
private TableColumn<EmailData, ?> getNextColumn(boolean forward) {
List<TableColumn<EmailData, ?>> columns = new ArrayList<>();
for (TableColumn<EmailData, ?> column : getTableView().getColumns()) {
columns.addAll(getLeaves(column));
}
// There is no other column that supports editing.
if (columns.size() < 2) {
return null;
}
int nextIndex = columns.indexOf(getTableColumn());
if (forward) {
nextIndex++;
if (nextIndex > columns.size() - 1) {
nextIndex = 0;
}
} else {
nextIndex--;
if (nextIndex < 0) {
nextIndex = columns.size() - 1;
}
}
return columns.get(nextIndex);
}
private List<TableColumn<EmailData, ?>> getLeaves(
TableColumn<EmailData, ?> root) {
List<TableColumn<EmailData, ?>> columns = new ArrayList<>();
if (root.getColumns().isEmpty()) {
if (root.isEditable()) {
columns.add(root);
}
return columns;
} else {
for (TableColumn<EmailData, ?> column : root.getColumns()) {
columns.addAll(getLeaves(column));
}
return columns;
}
}
}
}
And the Class where list declaration are:
public class MainApp extends Application {
public static ObservableList<EmailData> backupList = FXCollections.observableArrayList();
public static ObservableList<EmailData> emailData = FXCollections.observableArrayList(ed ->
new Observable[]{
ed.nameProperty(),
ed.loginProperty(),
ed.passwordProperty(),
ed.commentsProperty()
});
private BorderPane rootLayout;
public MainApp() {
}
public static void readCryptedData(String s) {
try {
switch (s) {
case "initData":
emailData = readDataFromStream(decryptFileBytes(libraryPath, salt, nonce));
break;
default:
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
launch(args);
}
public static ObservableList<EmailData> getEmailData() {
return emailData;
}
#Override
public void start(Stage primaryStage) {
MainApp.primaryStage = primaryStage;
MainApp.primaryStage.setResizable(false);
MainApp.primaryStage.getIcons().add(new Image(imageFile.toURI().toString()));
initRootLayout();
try {
showFirstView();
} catch (IOException e) {
e.printStackTrace();
}
}
private void initRootLayout() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("/fxml/RootLayout.fxml"));
rootLayout = loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
menuItemDisable.set(true);
} catch (IOException e) {
e.printStackTrace();
}
}
public Stage getPrimaryStage() {
return primaryStage;
}
#Override
public void stop() {
if (emailData.size() != 0) {
saveDataToFile();
}
}
}
I will much appreciated for any help.
After looking for comments and minuses to my question, I saw that I need to search a problem in my code by myself. Hope somebody will find this question and answer usefull.
The problem was in my read method readDataFromStream(). Before reading topics mentioned above I used such way declaration of ObservableList
public static ObservableList<EmailData> emailData = FXCollections.observableArrayList();
And my readDataFromStream looked like:
public static ObservableList<EmailData> readDataFromStream(byte[] bytes) {
ObservableList<EmailData> emailData = FXCollections.observableArrayList();
try {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
List<EmailData> list = (List<EmailData>) ois.readObject();
emailData = FXCollections.observableList(list);
bis.close();
ois.close();
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return emailData;
}
And then I have read that I need create the list with an extractor. And I changed ObservableList declaration to:
ObservableList<EmailData> emailData = FXCollections.observableArrayList(ed ->
new Observable[]{
ed.nameProperty(),
ed.loginProperty(),
ed.passwordProperty(),
ed.commentsProperty()
});
but my readDataFromStream() method remained the same. Now I changed it to:
public static ObservableList<EmailData> readDataFromStream(byte[] bytes) {
ObservableList<EmailData> emailData = FXCollections.observableArrayList(ed ->
new Observable[]{
ed.nameProperty(),
ed.loginProperty(),
ed.passwordProperty(),
ed.commentsProperty()
});
try {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
List<EmailData> list = (List<EmailData>) ois.readObject();
emailData = FXCollections.observableList(
list,
(EmailData tp) -> new Observable[]{tp.nameProperty(), tp.passwordProperty(),
tp.loginProperty(), tp.commentsProperty()});
bis.close();
ois.close();
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return emailData;
}
and wasUpdated() method of ListChangeListener.Change now works like a charm.
Hope it will help newbies like me.
I've got a listview where I can select different panes that will show up in the main pane. Now for a particular pane I need some objects to use every function. On the listview there is a listener on the selectedItemProperty. I want to check if the objects I need are available, otherwise the objects oldValue and newValue should keep their value. Is there a way of doing that?
listView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Object>()
{
#Override
public void changed(ObservableValue<? extends Object> observable, Object oldValue,
Object newValue)
{
if(obj == null)
{
// keep the oldValues for both
}
});
}
Here is a runnable example in the first code snippet the second snippet is what it would look like in your program
public class MainNoFXML extends Application {
public static void main(String[] args) { launch(args); }
#Override
public void start(Stage primaryStage) {
ListView<Object> listView = new ListView<>(FXCollections.observableArrayList(new String[]{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"}));
listView.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal)->{
if(newVal != null && (!newVal.equals("Monday") && !newVal.equals("Tuesday")))
Platform.runLater(() -> listView.getSelectionModel().select(oldVal));
});
Scene scene = new Scene(listView);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Your Program(I think this is correct not exactly sure what your working with)
listView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Object>() {
#Override
public void changed(ObservableValue<? extends Object> observable, Object oldValue,
Object newValue)
{
if(obj == null)
{
Platform.runLater(() -> listView.getSelectionModel().select(oldValue));
// keep the oldValues for both
}
});
});
In this case you should use a custom selection model to prevent some items from being selected.
The following implementation is simplified. It doesn't handle changes of the item list. Furthermore it implements single selection only, but hopefully it shows the general approach:
public class CustomSelectionModel<T> extends MultipleSelectionModel<T> {
private final ListView<T> listView;
private final ObservableList<Integer> selectedIndices = FXCollections.observableArrayList();
private final ObservableList<Integer> selectedIndicesUnmodifiable = FXCollections.unmodifiableObservableList(selectedIndices);
private final ObservableList<T> selectedItems;
private BiPredicate<Integer, T> leavePredicate;
private BiPredicate<Integer, T> enterPredicate;
public BiPredicate<Integer, T> getLeavePredicate() {
return leavePredicate;
}
public void setLeavePredicate(BiPredicate<Integer, T> leavePredicate) {
this.leavePredicate = leavePredicate;
}
public BiPredicate<Integer, T> getEnterPredicate() {
return enterPredicate;
}
public void setEnterPredicate(BiPredicate<Integer, T> enterPredicate) {
this.enterPredicate = enterPredicate;
}
public CustomSelectionModel(ListView<T> listView) {
if (listView == null) {
throw new IllegalArgumentException();
}
this.listView = listView;
this.selectedItems = new TransformationList<T, Integer>(selectedIndices) {
#Override
protected void sourceChanged(ListChangeListener.Change<? extends Integer> c) {
beginChange();
while (c.next()) {
if (c.wasReplaced()) {
nextReplace(c.getFrom(), c.getTo(), c.getRemoved().stream().map(listView.getItems()::get).collect(Collectors.toList()));
} else if (c.wasRemoved()) {
nextRemove(c.getFrom(), c.getRemoved().stream().map(listView.getItems()::get).collect(Collectors.toList()));
} else if (c.wasAdded()) {
nextAdd(c.getFrom(), c.getTo());
}
}
endChange();
}
#Override
public int getSourceIndex(int index) {
return index;
}
#Override
public T get(int index) {
return listView.getItems().get(getSource().get(index));
}
#Override
public int size() {
return getSource().size();
}
};
}
#Override
public ObservableList<Integer> getSelectedIndices() {
return selectedIndicesUnmodifiable;
}
#Override
public ObservableList<T> getSelectedItems() {
return selectedItems;
}
#Override
public void selectIndices(int index, int... indices) {
clearAndSelect(index); // ignore all indices but the first
}
#Override
public void selectAll() {
selectFirst();
}
#Override
public void selectFirst() {
if (!listView.getItems().isEmpty()) {
clearAndSelect(0);
}
}
#Override
public void selectLast() {
if (!listView.getItems().isEmpty()) {
clearAndSelect(listView.getItems().size() - 1);
}
}
private void moveSelection(int oldIndex, int newIndex) {
if ((leavePredicate == null || leavePredicate.test(oldIndex, oldIndex == -1 ? null : listView.getItems().get(oldIndex)))
&& (enterPredicate == null || enterPredicate.test(newIndex, newIndex == -1 ? null : listView.getItems().get(newIndex)))) {
setSelectedIndex(newIndex);
if (newIndex == -1) {
selectedItems.clear();
setSelectedItem(null);
} else {
setSelectedItem(listView.getItems().get(newIndex));
if (isEmpty()) {
selectedIndices.add(newIndex);
} else {
selectedIndices.set(0, newIndex);
}
}
listView.getFocusModel().focus(newIndex);
}
}
#Override
public void clearAndSelect(int index) {
moveSelection(getSelectedIndex(), index);
}
#Override
public void select(int index) {
clearAndSelect(index);
}
#Override
public void select(T obj) {
int index = listView.getItems().indexOf(obj);
if (index >= 0) {
clearAndSelect(index);
}
}
#Override
public void clearSelection(int index) {
if (getSelectedIndex() == index) {
clearSelection();
}
}
#Override
public void clearSelection() {
moveSelection(getSelectedIndex(), -1);
}
#Override
public boolean isSelected(int index) {
return selectedIndices.contains(index);
}
#Override
public boolean isEmpty() {
return selectedIndices.isEmpty();
}
#Override
public void selectPrevious() {
int index = getSelectedIndex() - 1;
if (index >= 0) {
clearAndSelect(index);
}
}
#Override
public void selectNext() {
int index = getSelectedIndex() + 1;
if (index < listView.getItems().size()) {
clearAndSelect(index);
}
}
}
#Override
public void start(Stage primaryStage) throws Exception {
ListView<Integer> listView = new ListView<>();
for (int i = 0; i < 100; i++) {
listView.getItems().add(i);
}
CustomSelectionModel<Integer> selectionModel = new CustomSelectionModel<>(listView);
listView.setSelectionModel(selectionModel);
CheckBox moveAllowed = new CheckBox("disallow movement");
moveAllowed.selectedProperty().addListener((o, oldValue, newValue) -> selectionModel.setLeavePredicate(newValue ? (index, item) -> false : null));
CheckBox enterOdd = new CheckBox("enter odd items disallowed");
enterOdd.selectedProperty().addListener((o, oldValue, newValue) -> selectionModel.setEnterPredicate(newValue ? (index, item) -> (index & 1) == 0 : null));
Scene scene = new Scene(new ScrollPane(new HBox(listView, new VBox(moveAllowed, enterOdd))));
primaryStage.setScene(scene);
primaryStage.show();
}
I have create my own SpreadsheetCellEditor to show a ColorPicker, but I don't want to return back the ColorPicker.getValue().toString, I want to return a label with
Background color of selected value. I have searched for setContentDisplay(ContentDisplay.GRAPHIC_ONLY) but it seems not exist on SpreadsheetCell.
So how I can achieve this?
Here is my implementation so far,
public class comboboxCellEditor extends SpreadsheetCellEditor {
private final ColorPicker colorPicker = new ColorPicker();
private EventHandler<KeyEvent> eh;
private ChangeListener<Color> cl;
private boolean ending = false;
public comboboxCellEditor(SpreadsheetView view) {
super(view);
}
#Override
public void startEdit(Object value) {
if (value instanceof Color) {
this.colorPicker.setValue((Color) value);
}
attachEnterEscapeEventHandler();
this.colorPicker.show();
this.colorPicker.requestFocus();
}
#Override
public Control getEditor() {
return colorPicker;
}
public String getControlValue() {
return this.colorPicker.getValue().toString();
}
#Override
public void end() {
if (this.colorPicker.isShowing()) {
this.colorPicker.hide();
}
this.colorPicker.removeEventFilter(KeyEvent.KEY_PRESSED, this.eh);
this.colorPicker.valueProperty().removeListener(this.cl);
}
private void attachEnterEscapeEventHandler() {
this.eh =
new EventHandler<KeyEvent>() {
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
comboboxCellEditor.this.ending = true;
comboboxCellEditor.this.endEdit(true);
comboboxCellEditor.this.ending = false;
} else if (t.getCode() == KeyCode.ESCAPE) {
comboboxCellEditor.this.endEdit(false);
}
}
};
this.colorPicker.addEventFilter(KeyEvent.KEY_PRESSED, this.eh);
this.cl = new ChangeListener<Color>() {
public void changed(ObservableValue<? extends Color> observable, Color oldValue, Color newValue) {
if (!comboboxCellEditor.this.ending)
comboboxCellEditor.this.endEdit(true);
}
};
this.colorPicker.valueProperty().addListener(this.cl);
}
}
public class SpreadSheetComboboxCellType extends SpreadsheetCellType<Color> {
#Override
public SpreadsheetCellEditor createEditor(SpreadsheetView spreadsheetView) {
return new comboboxCellEditor(spreadsheetView);
}
#Override
public String toString(Color color) {
return color.toString();
}
#Override
public boolean match(Object o) {
return true;
}
#Override
public Color convertValue(Object o) {
if (o instanceof Color)
return (Color) o;
else {
return Color.valueOf((String) o);
}
}
public SpreadsheetCell createCell(int row, int column, int rowSpan, int columnSpan, Color value) {
SpreadsheetCellBase cell = new SpreadsheetCellBase(row, column, rowSpan, columnSpan, this);
cell.setItem(value);
Label label = new Label();
label.setGraphic(null);
label.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
cell.setGraphic(label);
return cell;
}
}
The SpreadsheetCell has an updateText method each time you modify the item. Therefore it's meant to display text first.
You have several options.
The easiest one is to add a listener to the cell and modify your graphic at that moment :
The text shown in the cell will be the result of the conversion of your SpreadsheetCellType. Since you don't want text, return nothing in your SpreadSheetComboboxCellType :
#Override
public String toString(Color color) {
return "";
}
Then simply add a Listener on your SpreadsheetCell and modify the graphic :
cell.itemProperty().addListener(new ChangeListener<Object>() {
#Override
public void changed(ObservableValue<? extends Object> ov, Object t, Object newValue) {
if (newValue != null && newValue instanceof Color ) {
//Do something
cell.setGraphic(My_Graphic_Object);
} else {
cell.setGraphic(null);
}
}
});
This should do the trick. Now you can implement your own SpreadsheetCell in order to have a total control on the display. It will be more efficient. Basically copy all the code for SpreadsheetCellBase (here : https://bitbucket.org/controlsfx/controlsfx/src/755c59605e623476ff0a6c860e2c218488776aec/controlsfx/src/main/java/org/controlsfx/control/spreadsheet/SpreadsheetCellBase.java?at=default&fileviewer=file-view-default )
And simply modify the updateText method :
private void updateText() {
if(getItem() == null){
text.setValue(""); //$NON-NLS-1$
}else if (!("").equals(getFormat())) { //$NON-NLS-1$
text.setValue(type.toString(getItem(), getFormat()));
} else {
text.setValue(type.toString(getItem()));
}
}
Instead of modifying the text, you would be modifying the graphic with the new color.
I´m currently working on a TreeView and want to implement a ContextMenu which pops up on rightClick on a TreeCell. I´ve studied the examples but I´m not sure of how I can set the ContextMenu to popup on every cell, not just the ones that are filled with children.
Here my code (pretty much the sample code):
Constructor
.
.
.
this.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>()
{
#Override
public TreeCell<String> call(TreeView<String> p)
{
return new TextFieldTreeCellImpl();
}
});
}
private final class TextFieldTreeCellImpl extends TreeCell<String>
{
private TextField textField;
private ContextMenu addMenu = new ContextMenu();
#SuppressWarnings({ "rawtypes", "unchecked" })
public TextFieldTreeCellImpl()
{
MenuItem addMenuItem = new MenuItem("Add Note");
addMenu.getItems().add(addMenuItem);
addMenuItem.setOnAction(new EventHandler()
{
public void handle(Event t)
{
ImageView noteIcon = new ImageView(new Image(getClass().getResourceAsStream("../icons/note.png")));
noteIcon.setFitHeight(16);
noteIcon.setFitWidth(16);
TreeItem newNote = new TreeItem<String>("New Note");
getTreeItem().getChildren().add(newNote);
}
});
}
#Override
public void startEdit()
{
super.startEdit();
if (textField == null)
{
createTextField();
}
setText(null);
setGraphic(textField);
textField.selectAll();
}
#Override
public void cancelEdit()
{
super.cancelEdit();
setText((String) getItem());
setGraphic(getTreeItem().getGraphic());
}
#Override
public void updateItem(String item, boolean empty)
{
super.updateItem(item, empty);
if (empty)
{
setText(null);
setGraphic(null);
}
else
{
if (isEditing())
{
if (textField != null)
{
textField.setText(getString());
}
setText(null);
setGraphic(textField);
}
else
{
setText(getString());
setGraphic(getTreeItem().getGraphic());
if (!getTreeItem().isLeaf()&&getTreeItem().getParent()!= null)
{
setContextMenu(addMenu);
}
}
}
}
private void createTextField()
{
textField = new TextField(getString());
textField.setOnKeyReleased(new EventHandler<KeyEvent>()
{
#Override
public void handle(KeyEvent t)
{
if (t.getCode() == KeyCode.ENTER)
{
commitEdit(textField.getText());
}
else if (t.getCode() == KeyCode.ESCAPE)
{
cancelEdit();
}
}
});
}
private String getString()
{
return getItem() == null ? "" : getItem().toString();
}
}
}
Showing contextMenu to "filled with children" cells only is controlled with lines:
if (!getTreeItem().isLeaf() && getTreeItem().getParent() != null) {
setContextMenu(addMenu);
}
remove if control to popup contextMenu to all nodes/cells.