在
JavaFX 2中,使用CSS,是否可以创建2种颜色的背景?想想例如一个高度为10像素的TableCell.我希望前2 px(垂直)为红色,其余8 px(垂直)应保持默认背景颜色.可以在JavaFX 2中使用CSS吗?怎么样?
例:
原始背景:
期望的结果:
(上面2个像素被红色取代)
感谢您提供任何暗示!
解决方法
我使用了一层简单的背景颜色来产生红色高光(类似于Stefan建议的解决方案).
/** * file: table.css * Place in same directory as TableViewPropertyEditorWithCSS.java. * Have your build system copy this file to your build output directory. **/ .highlighted-cell { -fx-text-fill: -fx-text-inner-color; -fx-background-color: firebrick,gainsboro; -fx-background-insets: 0,2 0 0 0; }
对于像stackpane这样的标准区域,您真正需要做的就是应用上面的css(少了-fx-text-fill)来获得所需的结果.
以下是使用渐变定义颜色的另一种棘手方法:
-fx-background-color: linear-gradient( from 0px 0px to 0px 2px,firebrick,firebrick 99%,gainsboro );
在下面的屏幕截图中,如果值为false,则突出显示值单元格(通过将高亮显示的单元格css类应用于它们).
突出显示单元格样式类切换逻辑:
public void updateItem(Object item,boolean empty) { super.updateItem(item,empty); if (empty) { .... getStyleClass().remove("highlighted-cell"); } else { if (getItem() instanceof Boolean && (Boolean.FALSE.equals((Boolean) getItem()))) { getStyleClass().add("highlighted-cell"); } else { getStyleClass().remove("highlighted-cell"); } ... } }
当突出显示的单元格样式类应用于标准表格单元格(在updateItem调用自定义单元格期间)时,它看起来很好,但确实有一些缺点.表着色方案非常微妙和复杂.它具有奇数/偶数值的突出显示,所选行的突出显示,所选悬停行的突出显示,聚焦行和单元格的突出显示等.此外,它具有上述所有内容的各种组合.只是直接在高亮单元类中设置背景颜色是一种蛮力的方式来实现你想要的东西,因为它没有考虑所有这些其他细微之处并且只是覆盖它们,因此使用这个突出显示的单元格无论临时css psuedo-class状态应用于什么样式,样式总是看起来一样.
它确实很好,但是一个更好的解决方案会根据伪类状态对突出显示的单元格进行不同的着色.这是一个相当棘手的事情,你可以浪费大量时间玩各种状态和CSS选择器组合,以尝试获得不错的变化突出显示.总而言之,对于这个例子来说,对我来说似乎不值得额外的努力,尽管它可能适合你.
测试程序(对此的长度和复杂性表示道歉,我更容易将样式突出显示逻辑集成到现有程序中):
import java.lang.reflect.*; import java.util.logging.*; import javafx.application.Application; import javafx.beans.property.*; import javafx.beans.value.*; import javafx.collections.*; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.control.TableColumn.CellEditEvent; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.*; import javafx.stage.Stage; import javafx.util.Callback; // click in the value column (a couple of times) to edit the value in the column. // property editors are defined only for String and Boolean properties. // change focus to something else to commit the edit. public class TableViewPropertyEditorWithCSS extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) { final Person aPerson = new Person("Fred",false,"Much Ado About Nothing"); final Label currentObjectValue = new Label(aPerson.toString()); TableView<NamedProperty> table = new TableView(); table.setEditable(true); table.setItems(createNamedProperties(aPerson)); TableColumn<NamedProperty,String> nameCol = new TableColumn("Name"); nameCol.setCellValueFactory(new PropertyValueFactory<NamedProperty,String>("name")); TableColumn<NamedProperty,Object> valueCol = new TableColumn("Value"); valueCol.setCellValueFactory(new PropertyValueFactory<NamedProperty,Object>("value")); valueCol.setCellFactory(new Callback<TableColumn<NamedProperty,Object>,TableCell<NamedProperty,Object>>() { @Override public TableCell<NamedProperty,Object> call(TableColumn<NamedProperty,Object> param) { return new EditingCell(); } }); valueCol.setOnEditCommit( new EventHandler<CellEditEvent<NamedProperty,Object>>() { @Override public void handle(CellEditEvent<NamedProperty,Object> t) { int row = t.getTablePosition().getRow(); NamedProperty property = (NamedProperty) t.getTableView().getItems().get(row); property.setValue(t.getNewValue()); currentObjectValue.setText(aPerson.toString()); } }); table.getColumns().setAll(nameCol,valueCol); table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); VBox layout = new VBox(10); layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;"); layout.getChildren().setAll( currentObjectValue,table); VBox.setVgrow(table,Priority.ALWAYS); Scene scene = new Scene(layout,650,600); scene.getStylesheets().add(getClass().getResource("table.css").toExternalForm()); stage.setScene(scene); stage.show(); } private ObservableList<NamedProperty> createNamedProperties(Object object) { ObservableList<NamedProperty> properties = FXCollections.observableArrayList(); for (Method method : object.getClass().getMethods()) { String name = method.getName(); Class type = method.getReturnType(); if (type.getName().endsWith("Property")) { try { properties.add(new NamedProperty(name,(Property) method.invoke(object))); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { Logger.getLogger(TableViewPropertyEditorWithCSS.class.getName()).log(Level.SEVERE,null,ex); } } } return properties; } public class NamedProperty { public NamedProperty(String name,Property value) { nameProperty.set(name); valueProperty = value; } private StringProperty nameProperty = new SimpleStringProperty(); public StringProperty nameProperty() { return nameProperty; } public StringProperty getName() { return nameProperty; } public void setName(String name) { nameProperty.set(name); } private Property valueProperty; public Property valueProperty() { return valueProperty; } public Object getValue() { return valueProperty.getValue(); } public void setValue(Object value) { valueProperty.setValue(value); } } public class Person { private final SimpleStringProperty firstName; private final SimpleBooleanProperty married; private final SimpleBooleanProperty hasChildren; private final SimpleStringProperty favoriteMovie; private Person(String firstName,Boolean isMarried,Boolean hasChildren,String favoriteMovie) { this.firstName = new SimpleStringProperty(firstName); this.married = new SimpleBooleanProperty(isMarried); this.hasChildren = new SimpleBooleanProperty(hasChildren); this.favoriteMovie = new SimpleStringProperty(favoriteMovie); } public SimpleStringProperty firstNameProperty() { return firstName; } public SimpleBooleanProperty marriedProperty() { return married; } public SimpleBooleanProperty hasChildrenProperty() { return hasChildren; } public SimpleStringProperty favoriteMovieProperty() { return favoriteMovie; } public String getFirstName() { return firstName.get(); } public void setFirstName(String fName) { firstName.set(fName); } public Boolean getMarried() { return married.get(); } public void setMarried(Boolean isMarried) { married.set(isMarried); } public Boolean getHasChildren() { return hasChildren.get(); } public void setHasChildren(Boolean hasChildren) { this.hasChildren.set(hasChildren); } public String getFavoriteMovie() { return favoriteMovie.get(); } public void setFavoriteMovie(String movie) { favoriteMovie.set(movie); } @Override public String toString() { return firstName.getValue() + ",isMarried? " + married.getValue() + ",hasChildren? " + hasChildren.getValue() + ",favoriteMovie: " + favoriteMovie.get(); } } class EditingCell extends TableCell<NamedProperty,Object> { private TextField textField; private CheckBox checkBox; public EditingCell() { } @Override public void startEdit() { if (!isEmpty()) { super.startEdit(); if (getItem() instanceof Boolean) { createCheckBox(); setText(null); setGraphic(checkBox); } else { createTextField(); setText(null); setGraphic(textField); textField.selectAll(); } } } @Override public void cancelEdit() { super.cancelEdit(); if (getItem() instanceof Boolean) { setText(getItem().toString()); } else { setText((String) getItem()); } setGraphic(null); } @Override public void updateItem(Object item,boolean empty) { super.updateItem(item,empty); if (empty) { setText(null); setGraphic(null); getStyleClass().remove("highlighted-cell"); } else { if (getItem() instanceof Boolean && (Boolean.FALSE.equals((Boolean) getItem()))) { getStyleClass().add("highlighted-cell"); } else { getStyleClass().remove("highlighted-cell"); } if (isEditing()) { if (getItem() instanceof Boolean) { if (checkBox != null) { checkBox.setSelected(getBoolean()); } setText(null); setGraphic(checkBox); } else { if (textField != null) { textField.setText(getString()); } setText(null); setGraphic(textField); } } else { setText(getString()); setGraphic(null); } } } private void createTextField() { textField = new TextField(getString()); textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2); textField.focusedProperty().addListener(new ChangeListener<Boolean>() { @Override public void changed(ObservableValue<? extends Boolean> observable,Boolean oldValue,Boolean newValue) { if (!newValue) { commitEdit(textField.getText()); } } }); } private void createCheckBox() { checkBox = new CheckBox(); checkBox.setSelected(getBoolean()); checkBox.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2); checkBox.focusedProperty().addListener(new ChangeListener<Boolean>() { @Override public void changed(ObservableValue<? extends Boolean> observable,Boolean newValue) { if (!newValue) { commitEdit(checkBox.isSelected()); } } }); } private String getString() { return getItem() == null ? "" : getItem().toString(); } private Boolean getBoolean() { return getItem() == null ? false : (Boolean) getItem(); } } }