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);
}
}
});
Related
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.
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'am working on a java project using javafx multiple input types.but i am having a strangle ComboBox behaviours since i use Labels with images(ImageView) on it.
1- Combobox looks in white! but i need it in black.
2- and every time i choose an item.
3- it disappear!!!
Here is my code:
...
import javafx.scene.control.ComboBox;
import javafx.scene.image.ImageView;
ImageView img_tun = new ImageView("images/icones/flag/Tunisia.png");
Label lbl_tun=new Label("1",img_tun);
ImageView img_fr = new ImageView("images/icones/flag/France.png");
Label lbl_fr=new Label("2",img_fr);
ImageView img_aut = new ImageView("images/icones/flag/World.png");
Label lbl_aut=new Label("3",img_aut);
optionsnat=FXCollections.observableArrayList(lbl_tun,lbl_fr,lbl_aut);
#FXML
ComboBox<Label> cb_nat = new ComboBox<Label>();
private String nat="1";
...
#Override
public void initialize(URL location, ResourceBundle resources) {
...
cb_nat.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2) {
if(cb_nb.getItems().get((Integer) number2)=="1"){setNat("1");}
else if(cb_nb.getItems().get((Integer) number2)=="2"){setNat("2");}
else if(cb_nb.getItems().get((Integer) number2)=="3"){setNat("3");}
else{System.err.println("Erreur lors de changement de nation..");}
}
});
}
...
and code.fxml
<ComboBox fx:id="cb_nat" layoutX="40.0" layoutY="265.0" prefWidth="150.0" />
EDIT:
After reading this Article i know that my approach is tottaly wrong and strongly not recommended.. if anyone have another ideas to put bnation flags in ComboBox please help!!
thanks..(Sorry for my bad english)
What is causing this problem is that when you choose a ListCell, its item (Label in our situation) is being moved by the ComboBox from the ListCell (Items observableList) to the ButtonCell, the ButtonCell is the small box that is empty by default. However, we all know that any Node object cannot be placed twice anywhere inside the same scene, and since there is no clone function for the ListCell class, javafx removes it from its last place to the new place which is the ButtonCell.
The solution is to add strings
items in the list and provide a cell factory to create the label node inside the cell factory. Create a class called "StringImageCell" and do the following:
You need to set the cellFactory property:
cb_nat.setCellFactory(listview -> new StringImageCell());
You need to set the buttonCell property: cb_nat.setButtonCell(new StringImageCell());
Here is an example:
public class ComboBoxCellFactory extends Application {
#Override
public void start(Stage stage) throws Exception {
ComboBox<String> comboBox = new ComboBox<>();
comboBox.getItems().addAll("1", "2", "3");
//Set the cellFactory property
comboBox.setCellFactory(listview -> new StringImageCell());
// Set the buttonCell property
comboBox.setButtonCell(new StringImageCell());
BorderPane root = new BorderPane();
root.setCenter(comboBox);
Scene scene = new Scene(root, 600, 600);
stage.setScene(scene);
stage.show();
}
//A Custom ListCell that displays an image and string
static class StringImageCell extends ListCell<String> {
Label label;
static HashMap<String, Image> pictures = new HashMap<>();
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setItem(null);
setGraphic(null);
} else {
setText(item);
ImageView image = getImageView(item);
label = new Label("",image);
setGraphic(label);
}
}
}
private static ImageView getImageView(String imageName) {
ImageView imageView = null;
switch (imageName) {
case "1":
case "2":
case "3":
if (!pictures.containsKey(imageName)) {
pictures.put(imageName, new Image(imageName + ".png"));
}
imageView = new ImageView(pictures.get(imageName));
break;
default:
imageName = null;
}
return imageView;
}
public static void main(String[] args) {
launch(args);
}
}
I have a tree-view with costume TreeCell. tree cell is customized and it looks like below image.
On Right Side I selected the One Tree Cell or Tree item. as you can see there is image-view of hand on left side of each cell. By default it is in black color but i want to replace it with white color icon. as in above mock up.
How can i achieve this????
I want all text and image view icon on selection changed to white color. and last selected tree cell back to normal black color.
My Tree Cell Code is below.
private final class AlertTreeCell extends TreeCell<AlertListItem> {
private Node cell;
private Rectangle rectSeverity;
private Label mIncedentname;
private Label mAlertTitle;
private Label mSentTime;
private Label mSender;
private ImageView ivCategory;
public AlertTreeCell() {
FXMLLoader fxmlLoader = new FXMLLoader(
MainController.class
.getResource("/fxml/alert_list_item.fxml"));
try {
cell = (Node) fxmlLoader.load();
rectSeverity = (Rectangle) cell.lookup("#rectSeverity");
mIncedentname = (Label) cell.lookup("#lblIncidentName");
mAlertTitle = (Label) cell.lookup("#lblAlertTitle");
mSentTime = (Label) cell.lookup("#lblSentTime");
mSender = (Label) cell.lookup("#lblSender");
ivCategory = (ImageView) cell.lookup("#ivCategory");
} catch (IOException ex) {
mLogger.error(ex.getLocalizedMessage(),ex);
}
}
#Override
public void updateItem(AlertListItem item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
setText(null);
mAlertTitle.setText(item.getEvent());
mIncedentname.setText(item.getHeadline());
mSentTime.setText(MyUtils.getListDateFormattedString(item.getReceivedTime()));
mSender.setText(item.getSenderName());
Image image = new Image("/images/ic_cat_" + item.getCategoryIcon().toLowerCase() + "_black.png");
if(image != null){
ivCategory.setImage(image);
}
if(item.getSeverity() != null){
String severityColor = item.getSeverity().toString();
String severityColorCode = null;
if(severityColor != null) {
SeverityColorHelper severityColorHelper = new SeverityColorHelper();
severityColorCode = severityColorHelper.getColorBySeverity(AlertInfo.Severity.fromValue(severityColor));
}
rectSeverity.setFill(Color.web(severityColorCode,1.0) );
}
final AlertTreeCell this$=this;
setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if(event.getClickCount()==1){
Node cell$ = this$.getGraphic();
ImageView ivCategory$ = (ImageView) cell.lookup("#ivCategory");
Image image = new Image("/images/ic_cat_" + item.getCategoryIcon().toLowerCase() + "_white.png");
if(image != null){
ivCategory$.setImage(image);
}
}
}
});
this$.
setGraphic(cell);
}
}
}
problem is that new white icon properly selected and added but how to change back the last selected tree item's image view back to black color icon. actually I have two color images of same type. one is in black color and same image in white color. on selection i want the image and text changed to white colored and all other tree-items in to black color text and black color icon.
I'm not quite sure if the mouse handler is supposed to be changing the icon on selection: if so remove it. Don't use mouse handlers for detecting selection (what if the user navigates through the tree using the keyboard, for example?).
In your constructor, add a listener to the selectedProperty, and change the item accordingly:
public AlertTreeCell() {
FXMLLoader fxmlLoader = new FXMLLoader(
MainController.class
.getResource("/fxml/alert_list_item.fxml"));
try {
cell = (Node) fxmlLoader.load();
rectSeverity = (Rectangle) cell.lookup("#rectSeverity");
mIncedentname = (Label) cell.lookup("#lblIncidentName");
mAlertTitle = (Label) cell.lookup("#lblAlertTitle");
mSentTime = (Label) cell.lookup("#lblSentTime");
mSender = (Label) cell.lookup("#lblSender");
ivCategory = (ImageView) cell.lookup("#ivCategory");
this.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
String col ;
if (isNowSelected) {
col = "_black.png" ;
} else {
col = "_white.png" ;
}
if (getItem() != null) {
Image img = new Image("/images/ic_cat_" + item.getCategoryIcon().toLowerCase() + col);
ivCategory.setImage(img);
}
});
} catch (IOException ex) {
mLogger.error(ex.getLocalizedMessage(),ex);
}
}
In the updateItem(...) method, just check isSelected() and set the image accordingly there, but without the listener.
How can I make an auto wrap ListView (multiline when the text is too long) in JavaFX 2? I know that if I put a \n to the string, it will be multiline, but the content is too dynamic.
Or is there a good way to put \n to the String after every xyz pixel length?
You can put a TextArea in the ListCell.graphicProperty(). This is usually used to set an icon in a list cell but can just as easy to set to any Node subclass.
Here is the exact code how I did it finally.
ListView<String> messages = new ListView<>();
messages.relocate(10, 210);
messages.setPrefSize(this.getPrefWidth() - 20, this.getPrefHeight() - 250);
messages.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
#Override
public ListCell<String> call(ListView<String> list) {
final ListCell cell = new ListCell() {
private Text text;
#Override
public void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (!isEmpty()) {
text = new Text(item.toString());
text.setWrappingWidth(messages.getPrefWidth());
setGraphic(text);
}
}
};
return cell;
}
});
There is no need to create additional controls such as TextArea or Text. It is enough to just setWrapText(true) of the ListCell and setPrefWidth(50.0) or so. It will be automatically rewrapped on resize.
Here is my working code in Kotlin:
datasets.setCellFactory()
{
object : ListCell<Dataset>()
{
init
{
isWrapText = true
prefWidth = 50.0
}
override fun updateItem(item: Dataset?, empty: Boolean)
{
super.updateItem(item, empty)
text = item?.toString()
}
}
}
By the way, this is how I made it to correctly wrap CamelCase words:
replace(Regex("(?<=\\p{javaLowerCase})(?=\\p{javaUpperCase})|(?<=[_.])"), "\u2028")
Here \u2028 is the Unicode soft line break character, which javaFX respects.