Reputation: 63
For my project in Java FX, I have a list of strings and I need to add them to a combo box with the requirement that only one of them (the first) be coloured in red.
I thought about encapsulating the strings in a Text and adding them to the combo box with appropriate setStyle("fx-text-fill: Color.xxx"). This calls for a setCellFactory() method and I don't know how to set up it correctly.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.Pane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Callback;
public class Mainu extends Application
{
final ObservableList<Text> SAMPUNITFRONT = FXCollections.observableArrayList(
new Text("complete"), new Text("seconds"), new Text("minutes"), new Text("hours"), new Text("days"));
@Override
public void start(Stage stage) throws Exception
{
ComboBox<Text> cb = new ComboBox<Text>();
for(int j = 0; j < SAMPUNITFRONT.size(); j++) // cycle over the list and generate a line with dashing defined by list
{
Text text = SAMPUNITFRONT.get(j);
if(text.getText().equals("complete"))
text.setStyle("-fx-text-fill: RED");
else
text.setStyle("-fx-text-fill: BLACK");
cb.getItems().add(text);
}
cb.setCellFactory(new Callback<ListView<Text>, ListCell<Text>>()
{
@Override public ListCell<Text> call(ListView<Text> p)
{
return new ListCell<Text>()
{
private final Text text;
{
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
text = new Text();
} // end Text
@Override protected void updateItem(Text item, boolean empty)
{
super.updateItem(item, empty);
if (item == null || empty)
{
setGraphic(null);
}
else
{
text.setStyle(item.getStyle());
setGraphic(text);
setItem(text);
}
} // end updateItem()
}; // end ListCell return
}
});
cb.getSelectionModel().selectFirst();
Pane root = new Pane();
root.getChildren().add(cb);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {launch(args);}
}
At the moment, the drop down list of the combo is empty.
Upvotes: 1
Views: 194
Reputation: 82461
Several recommendations to make here:
Node
as item type. Instead store the data needed to determine the look of the ListCell
in the items and let the ListCell
implementations deal with the rest. You could simply use String
as item type, if you the coloration should be done based on the text or index only or you could create a class containing 2 properties.setItem
yourself. Let the ComboBox
/ListView
deal with this.Text
you need to use the -fx-fill
css property instead of -fx-text-fill
. The latter one would work, if you use the text
property of the ListCell
itself.ObservableList
, it's pointless to create one. You could simply have used List
and Arrays.asList
instead of ObservableList
and FXCollections.observableArrayList
for SAMPUNITFRONT
final ObservableList<String> SAMPUNITFRONT = FXCollections.observableArrayList("complete",
"seconds", "minutes", "hours", "days");
@Override
public void start(Stage stage) throws Exception {
ComboBox<String> cb = new ComboBox<String>(SAMPUNITFRONT);
cb.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
@Override
public ListCell<String> call(ListView<String> p) {
return new ListCell<String>() {
private final Text text;
{
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
text = new Text();
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
text.setStyle(item.equals("complete") ? "-fx-fill: red" : "-fx-fill: black");
text.setText(item);
setGraphic(text);
}
}
};
}
});
cb.getSelectionModel().selectFirst();
Pane root = new Pane();
root.getChildren().add(cb);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Alternatively without using a Text
as graphic
:
return new ListCell<String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(item);
if (item != null) {
setStyle(item.equals("complete") ? "-fx-text-fill: red" : "-fx-text-fill: black");
}
}
};
Upvotes: 2
Reputation: 61
The problem is that you set style to Text objects. Try set the same style to cells. And you don't need encapsulating the strings in a Text. Here is your code with fixes:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Main extends Application
{
final ObservableList<String> SAMPUNITFRONT = FXCollections.observableArrayList("complete", "seconds", "minutes", "hours", "days");
@Override
public void start(Stage stage)
{
ComboBox<String> cb = new ComboBox<>();
cb.setCellFactory(cell -> new ListCell<String>()
{
@Override
protected void updateItem(String item, boolean empty)
{
super.updateItem(item, empty);
if (item == null || empty)
{
setGraphic(null);
setText("");
}
else
{
if (item.equals("complete"))
{
setStyle("-fx-text-fill: RED");
}
setText(item);
}
}
});
cb.getItems().addAll(SAMPUNITFRONT);
cb.getSelectionModel().selectFirst();
Pane root = new Pane();
root.getChildren().add(cb);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
And result:
I hope I understood you ritghtly and could help.
Upvotes: 0