问题
So I have a list which is full of names from my database. Those names represent employees that work or used to work in the firm. I've seen that is possible to change cell's text color but when I apply it, it changes all of them. What I really want is to change color of the clients that are no more working.
I've added "not active" in List so I can separate "active" and "not active" clients.
Here is the code where I add employees names in the ArrayList:
public ArrayList<String> search(String unit, String name)
{
ArrayList<String> temp= new ArrayList<String>();
String sql="";
if(unit=="all units")
sql="SELECT * FROM employees WHERE name='"+name+"';";
else
sql="SELECT * FROM employees WHERE unit='"+unit+"' AND name='"+name+"';";
try {
ResultSet rs=bp.select(sql);
while(rs.next())
{
if(rs.getInt("active")==1)
temp.add(rs.getString("name"));
else
temp.add(rs.getString("name")+" - not active");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Collections.sort(temp);
return temp;
}
And here is the code where I add that ArrayList in my ListView:
for (String item: u.search(unitCB.getValue(),nameTF.getText()))
SearchLW.getItems().add(item);
Now, I wounder is it possible to change text-color in this list using css to red for all employees that are not active anymore? If it's not, another solution on how to change this specific ListView cell's text-color would be helpful.
回答1:
You can use a CSS pseudoclass to represent an "inactive" style and set the style in a CSS file. With your current code it would look something like:
ListView<String> listView = new ListView<>();
PseudoClass inactive = PseudoClass.getPseudoClass("inactive");
listView.setCellFactory(lv -> new ListCell<String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? null : item);
pseudoClassStateChanged(inactive, item != null && item.endsWith(" - not active"));
}
});
Then in an external css file you can define the style you want:
.list-cell:inactive {
-fx-text-fill: red ;
}
Just testing the string value here is pretty fragile (imagine what would happen if you tried to internationalize the application, or when your boss told you to change the presentation so that "not active"
was in parentheses, or whatever...). I would recommend creating an Employee
class:
public class Employee {
private final String name ;
private final boolean active ;
public Employee(String name, boolean active) {
this.name = name ;
this.active = active ;
}
public String getName() {
return name ;
}
public boolean isActive() {
return active ;
}
}
and then you do
ListView<Employee> listView = new ListView<>();
PseudoClass inactive = PseudoClass.getPseudoClass("inactive");
listView.setCellFactory(lv -> new ListCell<Employee>() {
@Override
protected void updateItem(Employee employee, boolean empty) {
super.updateItem(employee, empty);
if (empty) {
setText(null);
pseudoClassStateChanged(inactive, false);
} else {
if (employee.isActive()) {
setText(employee.getName());
pseudoClassStateChanged(inactive, false);
} else {
setText(employee.getName() + " - not active");
pseudoClassStateChanged(inactive, true);
}
}
}
});
and make the obvious update to the method you posted:
public ArrayList<Employee> search(String unit, String name) {
ArrayList<Employee> temp= new ArrayList<>();
String sql="SELECT * FROM employees WHERE unit like ? AND name=?";
try (PreparedStatement pStmnt = conn.prepareStatement(sql)) {
if("all units".equals(unit))
pStmnt.setString(1, "%");
else
pStmnt.setString(1, unit);
pStmnt.setString(2, name);
ResultSet rs=pStmnt.executeQuery();
while(rs.next())
{
temp.add(new Employee(rs.getString("name"), rs.getInt("active")==1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
temp.sort(Comparator.comparing(Employee::getName));
return temp;
}
回答2:
Here is an alternate implementation which just uses a style class rather than a psuedo-class. In this instance, a pseudo-class implementation is probably better.
Though, perhaps, this solution might scale a little better, as you can specify separate psuedo-class styles for things such as selected vs unselected or focused vs unfocused cells, which might be difficult if you use a custom pseudo-class (though I don't know for sure).
ActivityListViewer.java
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
public class ActivityListViewer extends Application {
@Override
public void start(Stage stage) throws Exception {
ListView<Activity> activityListView = new ListView<>(
FXCollections.observableArrayList(
new Activity("Fetch super suit from drycleaner", false),
new Activity("Interview governor with Jimmy", false),
new Activity("Rescue stranded kitten", true),
new Activity("Dinner date with Lois", false)
)
);
activityListView.setCellFactory(param -> new ListCell<Activity>() {
static final String ACTIVE_CLASS = "active";
@Override
protected void updateItem(Activity item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null || item.getName() == null) {
setText(null);
getStyleClass().remove(ACTIVE_CLASS);
} else {
if (item.isActive()) {
setText(item.getName() + " - active");
} else {
setText(item.getName());
}
if (item.isActive() && !getStyleClass().contains(ACTIVE_CLASS)) {
getStyleClass().add(ACTIVE_CLASS);
} else {
getStyleClass().remove(ACTIVE_CLASS);
}
}
}
});
activityListView.setPrefHeight(150);
Scene scene = new Scene(activityListView);
scene.getStylesheets().add(
this.getClass().getResource("activity.css").toExternalForm()
);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class Activity {
private final StringProperty nameProperty;
private final BooleanProperty activeProperty;
public Activity(String name, boolean active) {
this.nameProperty = new SimpleStringProperty(name);
this.activeProperty = new SimpleBooleanProperty(active);
}
public String getName() {
return nameProperty.get();
}
public StringProperty nameProperty() {
return nameProperty;
}
public boolean isActive() {
return activeProperty.getValue() != null
? activeProperty.getValue()
: false;
}
public BooleanProperty activeProperty() {
return activeProperty;
}
}
activity.css
.active {
-fx-text-fill: forestgreen;
}
.active:selected {
-fx-text-fill: lawngreen;
}
来源:https://stackoverflow.com/questions/37930153/how-to-change-listview-cells-text-color-in-javafx-using-css