I have a question regarding text selection when clicking on the editable Combobox.
Currently what happens, is that the mouse cursor just goes to that place of the input and does not select the whole text field. I would like to highlight/select whole textfield on the click, but it doesn't do that.
What I want that a click on the textfield would do:
This is my AutoComplete class:
public class AutoCompleteComboBoxListener<T> implements EventHandler<KeyEvent> {
private ComboBox comboBox;
private StringBuilder sb;
private ObservableList<T> data;
private boolean moveCaretToPos = false;
private int caretPos;
private Button button;
public AutoCompleteComboBoxListener(final ComboBox comboBox, final Button button) {
this.comboBox = comboBox;
sb = new StringBuilder();
data = comboBox.getItems();
this.comboBox.setEditable(true);
this.button = button;
this.comboBox.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
System.out.println("misaja");
System.out.println(t);
comboBox.hide();
}
});
this.comboBox.setOnKeyReleased(AutoCompleteComboBoxListener.this);
}
#Override
public void handle(KeyEvent event) {
System.out.println("nonoh");
System.out.println(event.getCode());
UI.bitLogger.logging(String.valueOf(event.getCode()));
if (event.getCode() == (KeyCode.ENTER)) {
System.out.println("erki");
button.fire();
}
if (event.getCode() == KeyCode.UP) {
caretPos = -1;
moveCaret(comboBox.getEditor().getText().length());
return;
} else if (event.getCode() == KeyCode.DOWN) {
if (!comboBox.isShowing()) {
comboBox.show();
}
caretPos = -1;
moveCaret(comboBox.getEditor().getText().length());
return;
} else if (event.getCode() == KeyCode.BACK_SPACE) {
moveCaretToPos = true;
caretPos = comboBox.getEditor().getCaretPosition();
} else if (event.getCode() == KeyCode.DELETE) {
moveCaretToPos = true;
caretPos = comboBox.getEditor().getCaretPosition();
}
if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT
|| event.isControlDown() || event.getCode() == KeyCode.HOME
|| event.getCode() == KeyCode.END || event.getCode() == KeyCode.TAB) {
return;
}
ObservableList list = FXCollections.observableArrayList();
for (int i = 0; i < data.size(); i++) {
if (data.get(i).toString().toLowerCase().startsWith(
AutoCompleteComboBoxListener.this.comboBox
.getEditor().getText().toLowerCase())) {
list.add(data.get(i));
}
}
String t = comboBox.getEditor().getText();
comboBox.setItems(list);
comboBox.getEditor().setText(t);
if (!moveCaretToPos) {
caretPos = -1;
}
moveCaret(t.length());
if (!list.isEmpty()) {
comboBox.show();
}
}
private void moveCaret(int textLength) {
if (caretPos == -1) {
comboBox.getEditor().positionCaret(textLength);
} else {
comboBox.getEditor().positionCaret(caretPos);
}
moveCaretToPos = false;
}
I am creating the ComboBox here:
final ComboBox comboBox = new ComboBox(options);
comboBox.setPrefWidth(320);
comboBox.setValue("");
//ComboBox comboBox = new ComboBox();
new AutoCompleteComboBoxListener<>(comboBox, goButton);
comboBox.addEventFilter(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent ke) {
if (ke.getCode() == KeyCode.ENTER) {
//System.out.println("ENTER was released");
goButton.fire();
}
}
});
comboBox.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
System.out.println("mouse click detected2! " + mouseEvent.getSource());
//comboBox.getEditor().requestFocus();
//comboBox.getEditor().requestFocus();
//comboBox.requestFocus();
//comboBox.getEditor().selectAll();
//comboBox.requestFocus();
//None of these seem to work.
}
});
What I added now is this:
comboBox.getEditor().focusedProperty().addListener(new ChangeListener<Boolean>()
{
#Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean oldPropertyValue, Boolean newPropertyValue)
{
if (newPropertyValue)
{
System.out.println("Textfield on focus");
comboBox.requestFocus();
comboBox.getEditor().selectAll();
}
else
{
System.out.println("Textfield out focus");
}
}
});
But all it does is that it selects/highlights the text for just a moment and then removes the highlight once again.
You should try to do it by adding a focus listener on the textfield as next:
comboBox.getEditor().focusedProperty().addListener(
(observable, oldValue, newValue) -> {
if (newValue) {
// Select the content of the field when the field gets the focus.
Platform.runLater(comboBox.getEditor()::selectAll);
}
}
);
This code is for Java 8, for previous versions the corresponding code is:
comboBox.getEditor().focusedProperty().addListener(
new ChangeListener<Boolean>() {
#Override
public void changed(final ObservableValue<? extends Boolean> observable,
final Boolean oldValue, final Boolean newValue) {
if (newValue) {
Platform.runLater(
new Runnable() {
#Override
public void run() {
comboBox.getEditor().selectAll();
}
}
);
}
}
}
);
Related
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 am fairly new to JavaFX. I have a table with multiple columns and rows. Where new rows can be added at the top of the table. Editing cell is also enabled. But I am facing a problem.
When I add new rows at the top and go to edit that, cell fills up with a value from the bellow cell automatically when edit starts!! But I don't want that. Is it a feature like excel? if yes how can I stop that? Here is a sample picture and my custom EditingCell.java
class EditingCell <S, T>extends TableCell<S, T> {
private TextField textField;
public EditingCell() {
}
#Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
// textField.selectAll();
Platform.runLater(new Runnable() {
#Override
public void run() {
textField.requestFocus();
textField.selectAll();
}
});
}
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
#Override
public void updateItem (T 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 {
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
#Override
public void commitEdit(T item) {
if (! isEditing() && ! item.equals(getItem())) {
TableView<S> table = getTableView();
if (table != null) {
TableColumn<S, T> column = getTableColumn();
CellEditEvent<S, T> event = new CellEditEvent<>(table,
new TablePosition<S,T>(table, getIndex(), column),
TableColumn.editCommitEvent(), item);
Event.fireEvent(column, event);
}
super.cancelEdit(); // this fires an invalid EditCancelEvent.
// update the item within this cell, so that it represents the new value
updateItem(item, false);
if (table != null) {
// reset the editing cell on the TableView
table.edit(-1, null);
}
}
super.commitEdit(item);
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((T)textField.getText());
}
}
});
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit((T)textField.getText());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
} else if (t.getCode() == KeyCode.TAB) {
commitEdit((T)textField.getText());
TableColumn nextColumn = getNextColumn(!t.isShiftDown());
if (nextColumn != null) {
getTableView().edit(getTableRow().getIndex(),
nextColumn);
}
}
else if (t.getCode() == KeyCode.RIGHT) {
commitEdit((T)textField.getText());
getTableView().getSelectionModel().selectRightCell();
TableColumn nextColumn = getNextColumn(!t.isShiftDown());
if (nextColumn != null) {
getTableView().edit(getTableRow().getIndex(),
nextColumn);
}
t.consume();
} else if (t.getCode() == KeyCode.LEFT) {
commitEdit((T)textField.getText());
getTableView().getSelectionModel().selectLeftCell();
TableColumn prevColumn = getNextColumn(false);
if (prevColumn != null) {
getTableView().edit(getTableRow().getIndex(),
prevColumn);
}
t.consume();
} else if (t.getCode() == KeyCode.UP) {
commitEdit((T)textField.getText());
getTableView().getSelectionModel().selectAboveCell();
int i=getTableView().getSelectionModel().getSelectedIndex();
if(i>=0)
getTableView().edit(i,
getTableColumn());
t.consume();
} else if (t.getCode() == KeyCode.DOWN) {
commitEdit((T)textField.getText());
getTableView().getSelectionModel().selectBelowCell();
int i=getTableView().getSelectionModel().getSelectedIndex();
if(i>=0)
getTableView().edit(i,
getTableColumn());
t.consume();
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
private TableColumn<S, ?> getNextColumn(boolean forward) {
List<TableColumn<S, ?>> columns = new ArrayList<>();
for (TableColumn<S, ?> column : getTableView().getColumns()) {
columns.addAll(getLeaves(column));
}
// There is no other column that supports editing.
if (columns.size() < 2) {
return null;
}
int currentIndex = columns.indexOf(getTableColumn());
int nextIndex = currentIndex;
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<S, ?>> getLeaves(
TableColumn<S, ?> root) {
List<TableColumn<S, ?>> columns = new ArrayList<>();
if (root.getColumns().isEmpty()) {
// We only want the leaves that are editable.
if (root.isEditable()) {
columns.add(root);
}
return columns;
} else {
for (TableColumn<S, ?> column : root.getColumns()) {
columns.addAll(getLeaves(column));
}
return columns;
}
}
}
Inside my initialize method I have code like below
Callback<TableColumn, TableCell> cellFactory = new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
colName.setCellValueFactory(new PropertyValueFactory<ModelBrBuilding,String>("BranchName"));
colName.setCellFactory(cellFactory);
colName.setOnEditCommit(
new EventHandler<CellEditEvent<ModelBrBuilding, String>>() {
#Override
public void handle(CellEditEvent<ModelBrBuilding, String> t) {
oldName= ((ModelBrBuilding) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).getBranchName(); // catch old value before edit
((ModelBrBuilding) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setBranchName(t.getNewValue());
newName=t.getNewValue(); // catch new value after edit
boolean edit=((ModelBrBuilding) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).isEdit();
if(edit==false) {
if(oldName!= null )
{
if(!oldName.trim().equals(newName.trim()) && !newName.isEmpty())
{
((ModelBrBuilding) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setEdit(true);
}
}
else if(!newName.isEmpty()&& newName != null)
((ModelBrBuilding) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setEdit(true);
}
}
}
);
And here is my method for adding new row at the top of the table.
public ObservableList<ModelBrBuilding> BuildingData;// contains searched data if there is any in database
//tableBuilding is sorted
// Method for adding new row
#FXML
private void addBuilding() {
tableBuilding.setEditable(true);
tableBuilding.getSelectionModel().setCellSelectionEnabled(true);
colName.setEditable(true);
//colShortCode.setEditable(true);
//colActive.setEditable(true);
if(BuildingData==null)//When search result is empty & there is now row in the table
{
tableBuilding.requestFocus();
tableBuilding.getItems().add(0,new ModelBrBuilding());
tableBuilding.layout();
tableBuilding.edit(0, colName);
}
//when search data is not empty
else {
ModelBrBuilding building = new ModelBrBuilding();
try {
BuildingData.add(0,building);
tableBuilding.layout();
tableBuilding.edit(0, colName);
//editBuilding();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
Can anyone help me in this regards please?
Finally, I have resolved it. I have to refresh the table after adding a new row.
#FXML
private void addBuilding() {
tableBuilding.setEditable(true);
tableBuilding.getSelectionModel().setCellSelectionEnabled(true);
colName.setEditable(true);
//colShortCode.setEditable(true);
//colActive.setEditable(true);
if(BuildingData==null)//When search result is empty & there is now row in the table
{
tableBuilding.requestFocus();
tableBuilding.getItems().add(0,new ModelBrBuilding());
tableBuilding.refresh();
tableBuilding.layout();
tableBuilding.edit(0, colName);
}
//when search data is not empty
else {
ModelBrBuilding building = new ModelBrBuilding();
try {
BuildingData.add(0,building);
tableBuilding.refresh();
tableBuilding.layout();
tableBuilding.edit(0, colName);
//editBuilding();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
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 have created a swt textbox and trying to do undo and redo functionality but when i press "ctrl+z" the listener itself is not working .so how can we do undo and redo operations.the code to implement undo and redo is as follows
private static class CTabItemControl extends Composite {
private static class UndoRedoStack<T> {
private Stack<T> undo;
private Stack<T> redo;
public UndoRedoStack() {
undo = new Stack<T>();
redo = new Stack<T>();
}
public void pushUndo(T delta) {
undo.add(delta);
}
public void pushRedo(T delta) {
redo.add(delta);
}
public T popUndo() {
T res = undo.pop();
return res;
}
public T popRedo() {
T res = redo.pop();
return res;
}
public T peekUndo() {
T res = undo.peek();
return res;
}
public void clearRedo() {
redo.clear();
}
public void clearUndo() {
undo.clear();
}
public boolean hasUndo() {
return !undo.isEmpty();
}
public boolean hasRedo() {
return !redo.isEmpty();
}
}
//private StyledText editor;
private UndoRedoStack<ExtendedModifyEvent> stack;
private boolean isUndo;
private boolean isRedo;
public CTabItemControl(Composite parentComposite,final CTabItem tabitem){
super(parentComposite, SWT.NONE);
setLayout(new GridLayout(1, false));
editor = new StyledText(this, SWT.MULTI | SWT.V_SCROLL);
editor.setLayoutData(new GridData(GridData.FILL_BOTH));
editor.setFont(new Font(Display.getDefault(),"Cambria", 10, SWT.NORMAL));
editor.addListener(SWT.KeyDown, new Listener(){
public void handleEvent(Event event) {
event.doit = true;
if(!tabitem.getText().contains("*"))
{
tabitem.setText('*'+tabitem.getText());
System.out.println("inserted *");
}
}
});
editor.addExtendedModifyListener(new ExtendedModifyListener(){
//editor.addKeyListener(this);
public void modifyText(ExtendedModifyEvent event) {
if (isUndo) {
stack.pushRedo(event);
} else { // is Redo or a normal user action
stack.pushUndo(event);
if (!isRedo) {
stack.clearRedo();
}
}
}
});
editor.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
// Listen to CTRL+Z for Undo, to CTRL+Y or CTRL+SHIFT+Z for Redo
boolean isCtrl = (e.stateMask & SWT.CTRL) > 0;
boolean isAlt = (e.stateMask & SWT.ALT) > 0;
if (isCtrl && !isAlt) {
boolean isShift = (e.stateMask & SWT.SHIFT) > 0;
if (!isShift && e.keyCode == 'z') {
{
System.out.println("call undo");
undo();
}
} else if (!isShift && e.keyCode == 'y' || isShift
&& e.keyCode == 'z') {
redo();
}
}
if(e.stateMask == SWT.CTRL && e.keyCode == 'a'){
editor.selectAll();
}
}
public void keyReleased(KeyEvent e) {
// ignore
}
});
//this.editor = editor;
stack = new UndoRedoStack<ExtendedModifyEvent>();
}
private void revertEvent(ExtendedModifyEvent event) {
System.out.println("calling revertevent");
editor.replaceTextRange(event.start, event.length, event.replacedText);
// (causes the modifyText() listener method to be called)
editor.setSelectionRange(event.start, event.replacedText.length());
}
private void undo() {
System.out.println("calling undo");
if (stack.hasUndo()) {
isUndo = true;
revertEvent(stack.popUndo());
isUndo = false;
}
}
private void redo() {
if (stack.hasRedo()) {
isRedo = true;
revertEvent(stack.popRedo());
isRedo = false;
}
}
public void clearUndoRedo() {
stack.clearUndo();
stack.clearRedo();
}
public boolean hasUndo() {
return stack.hasUndo();
}
public String peekUndo() {
return stack.peekUndo().toString();
}
}
When you press Ctrl + Z or Ctrl + Y, you get 2 key events, one for Ctrl and one for another key. So it is better to check for the character of the second event
e.character == 0x1a
for Ctr + Z, and
e.character == 0x19
for Ctrl + Y
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.