JavaFX: ComboBox - conflict setButtonCell & setPromptText - javafx

I'm using a JFoenix library and I have a problem with ComboBox.
When I want to setPromtText and setButtonCell - the text duplicates.
I want to change the size of font on ButtonCell.
Here is my code:
#FXML
private JFXComboBox versionList;
#Override
public void initialize(URL location, ResourceBundle resources) {
versionList.setPromptText("<");
versionList.setButtonCell(new ListCell<String>() {
#Override
protected void updateItem(String version, boolean empty) {
if (empty) {
setText(null);
} else {
setText(version);
setFont(Font.font(15));
}
}
});
}
And as the result I get this:
Or if promt text "Select":
What I'm doing wrong? Thanks in advance.

You have omitted to call the superclass implementation of updateItem(...) in your overridden updateItem(...) method. According to the documentation this will prevent the item and empty properties from being set; so I suspect that what is happening is that the cell still has empty==true, and consequently draws the prompt text when it shouldn't.
The correct implementation should be
#Override
public void initialize(URL location, ResourceBundle resources) {
versionList.setPromptText("<");
versionList.setButtonCell(new ListCell<String>() {
#Override
protected void updateItem(String version, boolean empty) {
super.updateItem(version, empty);
if (empty) {
setText(null);
} else {
setText(version);
setFont(Font.font(15));
}
}
});
}

Related

JavaFX: add contextmenu to TableView cell

I'm trying to add a context menu for every individual cell in a column, that gets activated by rightclicking on the cell. The menuitems would also depend on the cell clicked.
I would think using a cell factory would be the best way, but I cant figure out how to do it.
Edit: This is my implementation for one of my columns. setText in updateItem() adds the text to my column, but I want to add it as a label, how should I do that?
moColumn = new TableColumn<>("Maandag");
moColumn.setSortable(false);
moColumn.setCellValueFactory(new PropertyValueFactory<>("Mo"));
getColumns().add(moColumn);
moColumn.setCellFactory(new Callback<TableColumn<RowData, Label>, TableCell<RowData, Label>>() {
#Override
public TableCell<RowData, Label> call(TableColumn<RowData, Label> col) {
final TableCell<RowData, Label> cell = new TableCell<RowData, Label>() {
#Override
protected void updateItem(Label item, boolean empty) {
super.updateItem(item, empty);
if(empty){
setText(null);
} else {
setText(item.getText());
}
}
};
//cell.textProperty().bind(cell.getItem().textProperty());
cell.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if(event.getButton() == MouseButton.SECONDARY){
ContextMenu contextMenu = new ContextMenu();
MenuItem menuItem = new MenuItem(cell.getText());
contextMenu.getItems().add(menuItem);
cell.setContextMenu(contextMenu);
}
}
});
return cell;
}
});
Edit: How can I right click on a cell in tableview in Javafx (fxml)?
I've found this, but the link to the blog isn't working anymore...
Changed:
#Override
protected void updateItem(Label item, boolean empty) {
super.updateItem(item, empty);
if(empty){
setText(null);
} else {
setText(item.getText());
}
}
To:
#Override
protected void updateItem(Label item, boolean empty) {
super.updateItem(item, empty);
if(empty){
setText(null);
} else {
setGraphic(item);
}
}

Table cell combobox - action not performed

I'm applying the below cell factory to a column.
targetEnviroment.setCellFactory(new Callback<TableColumn<DevWorkTabBench, String>, TableCell<DevWorkTabBench, String>>() {
#Override
public TableCell<DevWorkTabBench, String> call(TableColumn<DevWorkTabBench, String> param) {
TableCell<DevWorkTabBench, String> cell = new TableCell<DevWorkTabBench, String>() {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
String status = null;
try {
status = getTableView().getItems().get(getIndex()).getObjectStatus();
} catch (IndexOutOfBoundsException ex) {
status = "";
}
if (status.equalsIgnoreCase("ReadyForDeployment")) {
ComboBox<String> comboBox = new ComboBox(environmentList);
comboBox.valueProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
commitEdit(newValue);
}
});
comboBox.setOnShown(new EventHandler<Event>() {
#Override
public void handle(Event event) {
getTableView().edit(getIndex(), getTableColumn());
getTableView().getSelectionModel().select(getIndex());
}
});
comboBox.setValue(item);
setGraphic(comboBox);
} else {
setGraphic(null);
}
if (empty) {
setGraphic(null);
}
}
};
return cell;
}
});
When I change the status to the mentioned status, I get the look of ComboBox in that particular cell but the drop down does not occur. Even after multiple clicks no action seems to be performed on the combobox. I do not get any exception other than the handled one. Other columns are editable and performing task as expected.
I have no idea what is wrong here. Can anyone please help me.
Since you are always displaying the combo box in the (non-empty) cells, you don't really need to go into "editing" mode as the standard TextFieldTableCell etc does. Your implementation is more similar to the CheckBoxTableCell, which essentially bypasses the editing mechanism. From the documentation for that class:
Note that the CheckBoxTableCell renders the CheckBox 'live', meaning
that the CheckBox is always interactive and can be directly toggled by
the user. This means that it is not necessary that the cell enter its
editing state (usually by the user double-clicking on the cell). A
side-effect of this is that the usual editing callbacks (such as on
edit commit) will not be called. If you want to be notified of
changes, it is recommended to directly observe the boolean properties
that are manipulated by the CheckBox.
So your cell implementation behaves similarly: don't invoke edit(...) (which I think is messing things up) and don't rely on the commitEdit(...), cancelEdit() etc methods (which won't work as you're not in editing state), but just update the model class directly.
I can't test, since there isn't a MCVE to work from, so this might not work directly, but it should be enough to get you started toward something that will work.
targetEnviroment.setCellFactory(new Callback<TableColumn<DevWorkTabBench, String>, TableCell<DevWorkTabBench, String>>() {
#Override
public TableCell<DevWorkTabBench, String> call(TableColumn<DevWorkTabBench, String> param) {
TableCell<DevWorkTabBench, String> cell = new TableCell<DevWorkTabBench, String>() {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null) ;
} else {
String status = getTableView().getItems().get(getIndex()).getObjectStatus();
if (status.equalsIgnoreCase("ReadyForDeployment")) {
ComboBox<String> comboBox = new ComboBox(environmentList);
comboBox.valueProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
//commitEdit(newValue);
getTableView().getItems().get(getIndex()).setObjectStatus(newValue);
}
});
comboBox.setValue(item);
setGraphic(comboBox);
} else {
setGraphic(null);
}
}
}
};
return cell;
}
});

Graphic on TreeItem dissapears on drag and drop

I have this basic code which adds drag and drop functionality to tree views.
The code works just fine, but when one treeitem is dragged, dropped and added over to another treeitem, the graphic on the treeitem in the original treecell dissapears, while the graphic follows the dragged element and is visible in the new treeitem.
See the image for example, the treeitem "Name" has been dragged over to "Column Name" and lost it's graphic. Alltough the new TreeItem under "Column Name" still has it graphics.
The code for adding drag and drop is this:
private void addDragAndDrop(TreeCell<String> treeCell, MainFXMLController mainFXMLController) {
treeCell.setOnDragDetected(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("setOnDragDetected");
Dragboard db = treeCell.startDragAndDrop(TransferMode.ANY);
ClipboardContent content = new ClipboardContent();
content.putString(event.toString());
db.setContent(content);
DRAGGEDSOURCE = treeCell;
DRAGGEDINDEX = (treeCell.getTreeView().getSelectionModel().getSelectedIndex());
}
});
treeCell.setOnDragOver(new EventHandler<DragEvent>() {
//brukeren har dragget det over et element
public void handle(DragEvent event) {
DRAGGEDTARGET = treeCell.getTreeItem();
if (event.getGestureSource() != treeCell
&& event.getDragboard().hasString()) {
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
}
});
treeCell.setOnDragDropped(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
DRAGGEDTARGET.getChildren().add(DRAGGEDSOURCE.getTreeItem());
}
);
}
public void makeTreeViewDragAble(TreeView treeView, MainFXMLController mainFXMLController) {
treeView.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
#Override
public TreeCell<String> call(TreeView<String> stringTreeView) {
TreeCell<String> treeCell = new TreeCell<String>() {
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
setText(item);
setGraphic(getTreeItem().getGraphic());
} else {
setText(null);
setGraphic(null);
}
}
};
addDragAndDrop(treeCell, mainFXMLController);
treeView.setEditable(true);
return treeCell;
}
});
}
As #James_D and I have concluded on, this is because I am trying to have two instances of the imageView. The solution is to set a new image view on the old item.

JavaFX editable ComboBox in a table view

I am using a editable ComboBox cell in a table view. Here is my ComboBox cell class
public class ComboBoxCell extends TableCell<ClassesProperty, String> {
private ComboBox<String> comboBox;
public ComboBoxCell() {
}
#Override
public void startEdit() {
super.startEdit();
if (comboBox == null) {
createComboBox();
}
setGraphic(comboBox);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
Platform.runLater(new Runnable() {
#Override
public void run() {
comboBox.requestFocus();
comboBox.getEditor().requestFocus();
comboBox.getEditor().selectAll();
}
});
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText(String.valueOf(getItem()));
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (comboBox != null) {
comboBox.setValue(getString());
}
setGraphic(comboBox);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
private void createComboBox() {
// ClassesController.getLevelChoice() is the observable list of String
comboBox = new ComboBox<>(ClassesController.getLevelChoice());
comboBox.setEditable(true);
comboBox.setMinWidth(this.getWidth() - this.getGraphicTextGap()*2);
comboBox.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(comboBox.getSelectionModel().getSelectedItem());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
The problem I need to press three clicks on the table cell to get the text field of the combo box to edit the contents. Is there a way to make it in two clicks? I even used Platforn runlater but when I try to edit a cell at first time it takes three mouse clicks but at the second time only two clicks.
In your overridden cell.startEdit() method, Add a ListView with a textfield, then add this listview to setGraphic. This will show the listview directly once the row is selected and the cell is clicked, the listview will be inside the tablecell, I am yet to find a way to make it as a popup

setOnMouseEntered and setOnMouseExited foreverloop

I use a PopOver from controlsfx to display detail-data from a TableCell. I use a tableCellFactory to create individual PopOvers. I have a problem with this code:
public class PopupTableCell extends TableCell {
#Override
protected void updateItem(final Object item, boolean empty) {
super.updateItem(item, empty);
if (empty){
setText(null);
} //if
else {
setText(item.toString());
// PopUp Anzeigen.
final PopOver PopUp = new PopOver();
PopUp.setContentNode(new Label(item.toString()));
setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
Point MouseLocation = MouseInfo.getPointerInfo().getLocation();
PopUp.show(PopupTableCell.this, MouseLocation.getX(), MouseLocation.getY());
System.out.println("entered");
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
System.out.println("exited");
PopUp.hide();
}
});
}
}
When I place the cursor over a cell, it begins firing the entered and the exited events forever (even with a non moving mouse cursor.
How can I achieve the wanted behavior:
Mouse inside table cell -> popover.show()
Mouse leaves table cell -> popover.hide()
This is how I solved the same problem for me.
owner.setOnMouseMoved(evt -> {
if (owner.getLayoutBounds().contains(evt.getX(), evt.getY())) {
if (!popOver.isShowing()) {
popOver.show(owner);
}
}
});
owner.setOnMouseExited(evt -> {
if (owner.getLayoutBounds().contains(evt.getX(), evt.getY())) {
if (!popOver.isShowing())
popOver.show(owner);
} else {
popOver.hide();
}
});

Resources