I am trying to create a ComboBox that will display a preview of selected Image, but the ComboBox displays the string value instead.
The only way appears to work is to create ComboBox of Node, but that causes once selected option disappear from the drop down menu, would appreciate if someone has any suggestions.
My code below:
String notOnLine = "file:Java1.png";
String onLine = "file:Java2.png";
ObservableList<String> options = FXCollections.observableArrayList();
options.addAll(notOnLine, onLine);
final ComboBox<String> comboBox = new ComboBox(options);
comboBox.setCellFactory(c -> new StatusListCell());
and the ListCell:
public class StatusListCell extends ListCell<String> {
protected void updateItem(String item, boolean empty){
super.updateItem(item, empty);
setGraphic(null);
setText(null);
if(item!=null){
ImageView imageView = new ImageView(new Image(item));
imageView.setFitWidth(40);
imageView.setFitHeight(40);
setGraphic(imageView);
setText("a");
}
}
}
I'd like the image to be displayed in the ComboBox itself once the list is closed. Right now it's just showing the URL (e.g. file:Java1.png).
You can specify the buttonCellProperty of the ComboBox:
comboBox.setButtonCell(new StatusListCell());
The button cell is used to render what is shown in the ComboBox
'button' area.
Related
I wanna design a custom listview in JavaFX, And I need to add some different fonts with different sizes, but my code doesn't work.
Here is my updateItem Function :
list.setCellFactory(param -> new ListCell<String>() {
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
ImageView imageView = new ImageView();
switch (item) {
case "Back":
imageView.setImage(image1);
System.out.println(imageView.getImage());
break;
case "Shop":
imageView.setImage(image0);
break;
}
imageView.setFitHeight(100);
imageView.setFitWidth(100);
Text text = new Text(item);
text.setFont(Font.font("B Aria", 500));
Text text1 = new Text("100");
text1.setFont(Font.font("Arial", 200));
setText(text.getText() + "\n" + text1.getText());
setGraphic(imageView);
setStyle("-fx-background-color: white");
setStyle("-fx-text-fill:#5aa6f0;");
}
}
});
As you see, Two texts are same in Font and size:
How can I fix this? Thanks.
The text property of the cell is just a string: it doesn't carry any style or font information with it. So all you are doing here is setting the text of the cell to the concatenation of the two strings, with a newline between them. The style of the text is determined solely by styles set on the cell itself (i.e. a text fill of #5aa6f0).
To achieve what you want here, you'll need to display the two Text objects with their styles as part of the graphic. Since you already have an image view as the graphic, you'll need to combine these: e.g. you can have a VBox containing the two Texts, and an HBox containing the image and the VBox. You may need to experiment with the layout to get it exactly as you want, but this should give you the idea:
list.setCellFactory(param -> new ListCell<String>() {
private final VBox textContainer = new VBox();
private final Text itemText = new Text();
private final Text valueText = new Text();
private final HBox graphic = new HBox();
private final ImageView imageView = new ImageView();
{
textContainer.getChildren().addAll(itemText, valueText);
graphic.getChildren().addAll(imageView, textContainer);
// may be better to put styles in an external CSS file:
itemText.setFill(Color.web("#5aa6f0"));
itemText.setFont(Font.font("B Aria", 500));
valueText.setFill(Color.web("#5aa6f0"));
valueText.setFont(Font.font("Arial", 200));
setStyle("-fx-background-color: white;");
imageView.setFitHeight(100);
imageView.setFitWidth(100);
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
switch (item) {
case "Back":
imageView.setImage(image1);
break;
case "Shop":
imageView.setImage(image0);
break;
}
itemText.setText(item);
valueText.setText("100");
setGraphic(graphic);
}
}
});
I'm using a treeview in a javafx application and today I added drag and drop support to reorder the elements of the treeview. To do this i had to create my own CellFactory class but my code has a bug.
When the content of my treeview gets smaller the area under the treeview that should be empty still contains text that shouldn't be there.
This is what my treeview looks like before collapsing and after collapsing:
before collapsing the item
after collapsing the item
I got my inspiration for the drag and drop feature from this blogpost
https://brianyoung.blog/2018/08/23/javafx-treeview-drag-drop/
Before I had my own cellFactory class I had a lambda function in the setCellFactory method of my treeview and that solution didn't have this problem.
In my CellFactory class I override the call method. I think this is where i need to somehow refresh the content of the treeview to get rid of the residue text.
public class CellFactory implements Callback<TreeView<QuizElement>, TreeCell<QuizElement>> {
...
#Override
public TreeCell<QuizElement> call(TreeView<QuizElement> treeView) {
TreeCell<QuizElement> cell = new TreeCell<QuizElement>() {
#Override
protected void updateItem(QuizElement item, boolean empty) {
super.updateItem(item, empty);
if (item == null) return;
if (empty) {
setText("");
} else {
textProperty().bind(item.getNameProperty());
}
}
};
cell.setOnDragDetected((MouseEvent event) -> dragDetected(event, cell));
cell.setOnDragOver((DragEvent event) -> dragOver(event, cell));
cell.setOnDragDropped((DragEvent event) -> drop(event, cell, treeView));
cell.setOnDragDone((DragEvent event) -> clearDropLocation());
return cell;
}
...
In the after collapsing picture I expected the area under the last openable element to be white.
I'm using JFXListView and JFXListCell from the library called jfoenix and the purpose and function are same as the regular ListView.
The list contains some Label, Button and AnchorPane. At the very top and bottom of the list, I want to add non-selectable item. The item should not be selectable on mouse click, should not be able to focus and should not be able to scroll.
I though of using updateItem() function and setting the item disable:
#FXML
JFXListView listView;
ObservableList<AnchorPane> list = FXCollections.observableArrayList();
private void initializeListView(){
AnchorPane headerBottomPane = new AnchorPane();
headerBottomPane.setId("headerBottomPane");
....//some property of AnchorPane
list.add(headerBottomPane); //Add header AnchorPane
while(true){
AnchorPane listContainer = new AnchorPane();
Label title = new Label();
Label subtitle = new Label();
Button button = new Button();
Button button2 = new Button();
//Some code here...
listContainer.getChildren().addAll(label, subtitle, button, button2);
list.add(listContainer);
//some code here...
}
list.add(headerBottomPane); //Add bottom AnchorPane
listView.setCellFactory(new CallBack<JFXListView, JFXListCell>(){
#Override
public JFXListCell call(JFXListView param){
return new JFXListCell<AnchorPane>(){
#Override
protected void updateItem(AnchorPane anchorPane, boolean empty){
super.updateItem(anchorPane, empty);
if(anchorPane != null){
if(anchorPane.getId.equals("headerBottomPane")){
setDisable(true);
}
setItem(anchorPane);
}else{
setItem(null);
}
}
};
}
});
}
I am able to disable the top and last item of the list, the item is no longer able to select using mouseClick.
But the problem is, it is focusable when I use the Keyboard arrow up and arrow down another strange thing is when I use the mouse wheel to scroll the list, some of the item are becoming non-selectable too.
I would think of just using a VBox, and putting your top unselectable item first, then the ListView with all the selectable items, then the bottom unselectable item...
I think you have to put your listView.setCellFactory() function at the top of the code where you adding those items, try to initialize it before you add the item.
and inside your updateItem() try to use setMouseTransparent() and setFocusTravesable().
#Override
protected void updateItem(AnchorPane anchorPane, boolean empty){
super.updateItem(anchorPane, empty);
if(anchorPane != null){
if(anchorPane.getId.equals("headerBottomPane")){
setItem(anchorPane); //moved at the top
setMouseTransparent(true); //added this line
setFocusTraversable(false); //added this line
setDisable(true);
}else{
setItem(null);
}
}
I haven't test it but I hope it work.
I made a custom listview, following is the code:
ListView<Sector> sectorList = new ListView();
sectorList.setStyle("-fx-font-size: 21px;");
sectorList.setItems(data2);
sectorList.setCellFactory(new Callback<ListView<Sector>, ListCell<Sector>>() {
#Override
public ListCell<Sector> call(ListView<Sector> param) {
return new XCell();
}
});
.
class XCell extends ListCell<Sector>{
#Override
protected void updateItem(Sector sector, boolean empty){
super.updateItem(sector, empty);
if(!empty){
CheckBox checkbox = new CheckBox(sector.getName());
checkbox.setStyle("-fx-font-weight: bold;");
checkbox.setSelected(true);
Label label = new Label(" "+sector.getDescription());
label.setStyle("-fx-font-style: italic;");
VBox root = new VBox(5);
root.setPadding(new Insets(8));
root.getChildren().addAll(checkbox,label);
setGraphic(root);
}else{
setGraphic(null);
}
}
}
Is there a way to loop through the listview's items and check if the checkbox is selected or not? How?
There is isSelected() method in JavaFX for the same.
You could add a CheckBox field to Sector and assign it in the updateItem method:
sector.setCheckBox(checkbox);
You can then iterate through all the elements in your ListView:
sectorList.getItems().forEach((sector) -> {
boolean selected = sector.getCheckBox().isSelected();
// do whatever needs to be done
})
Update
You could also add a BooleanProperty to Sector and bind it to the selectedProperty of the CheckBox like this:
checkbox.selectedProperty().bind(selector.yourBooleanProperty);
And the check this property in the foreach loop
I have the following problem creating custom cell factory of a ComboBox from an FXML file created with Scene Builder in JavaFX:
I created a custom cell factory of Labels. It works fine when the user clicks on the items. The y are displayed in the "button" area. But when the user wants to click on another items the previously clicked item is gone.
Here is the code of the combobox cell factory:
idCardOnlineStatusComboBox.setCellFactory(new Callback<ListView<Label>, ListCell<Label>>() {
#Override public ListCell<Label> call(ListView<Label> param) {
final ListCell<Label> cell = new ListCell<Label>() {
#Override public void updateItem(Label item,
boolean empty) {
super.updateItem(item, empty);
if(item != null || !empty) {
setGraphic(item);
}
}
};
return cell;
}
});
I suppose there is a problem in the cell factory but i can't figure out where it is.
I extract the combobox from the fxml with this code:
#FXML private ComboBox idCardOnlineStatusComboBox;
then i fill the combobox with this:
idCardOnlineStatusComboBox.getItems().addAll(
new Label(Resource.getStringFor("MainForm.Pane.MenuBar.Vortex.OnlineStatus.Online.Title"), new ImageView(onlineImg)),
new Label(Resource.getStringFor("MainForm.Pane.MenuBar.Vortex.OnlineStatus.Away.Title"), new ImageView(awayImg)),
new Label(Resource.getStringFor("MainForm.Pane.MenuBar.Vortex.OnlineStatus.DoNotDisturb.Title"), new ImageView(doNotDisturbImg)),
new Label(Resource.getStringFor("MainForm.Pane.MenuBar.Vortex.OnlineStatus.Invisible.Title"), new ImageView(offlineImg)),
new Label(Resource.getStringFor("MainForm.Pane.MenuBar.Vortex.OnlineStatus.Offline.Title"), new ImageView(offlineImg))
);
The disappearing behavior may be a bug. You can file it to JavaFX Jira, and let the Oracle guys decide it further. Additionally you can investigate the ComboBox.setCellFactory(...) source code for the reason of this behavior and find workaround. But my suggestion is to use the ComboBox Cell's (ListCell) internal Labelled component, instead of yours:
#Override
public void updateItem(Label item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setText(item.getText());
setGraphic(item.getGraphic());
} else {
setText(null);
setGraphic(null);
}
}
Note the else part of the code, cover all use cases when writing an if-statement.