简体   繁体   English

JavaFX中有2种颜色的背景?

[英]Background with 2 colors in JavaFX?

In JavaFX 2, using CSS, is it possible to create a background with 2 colors? 在JavaFX 2中,可以使用CSS创建具有2种颜色的背景吗? Think of eg a TableCell with a height of 10 px. 考虑一下一个高度为10像素的TableCell I want to the first 2 px (vertically) to be red, the remaining 8 px (vertically) shall stay at the default background color. 我希望前2像素(垂直)为红色,其余8像素(垂直)应保持默认背景色。 Is that possible using CSS in JavaFX 2? 在JavaFX 2中使用CSS是否可行? How? 怎么样?

Example: 例:

Original background: 原始背景:

在此处输入图片说明

Desired result: 所需结果:

在此处输入图片说明 (the upper 2 pixels were replaced by red) (上方的2个像素已替换为红色)

Thanks for any hint on this! 感谢您对此的任何提示!

I used a simple layer of background colors to produce a red highlight (similar to Stefan' suggested solution). 我使用了简单的背景颜色层来产生红色高光(类似于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;
}

For a standard region like a stackpane, all you really need to do is apply the above css (less the -fx-text-fill ) to get the desired result. 对于像堆栈窗格这样的标准区域,您真正需要做的就是应用上面的css(减去-fx-text-fill )以获得所需的结果。


Here is another tricky way to define the color using a gradient: 这是使用渐变定义颜色的另一种技巧:

-fx-background-color: 
  linear-gradient(
    from 0px 0px to 0px 2px, 
      firebrick, firebrick 99%, 
    gainsboro
  );

In the screenshot below, the value cells are highlighted (by having the highlighted-cell css class applied to them) if have the value false . 在下面的屏幕快照中,如果值为false ,则将值单元格突出显示(通过将highlighted-cell css类应用于它们)。

高亮单元格

Highlight cell style class switch logic: 突出显示单元格样式类切换逻辑:

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");
    }
    ...
  }
}

It looks good when the highlighted-cell style class applied to a standard table cell (during an updateItem call for a custom cell) but does have a couple of drawbacks. highlighted-cell样式类应用于标准表单元格(在对自定义单元格的updateItem调用期间)时,看起来不错,但确实有一些缺点。 The table coloring scheme is very subtle and complex. 表格的着色方案非常微妙和复杂。 It has highlights for odd/even values, highlights for selected rows, highlights for selected hovered rows, highlights for focused rows and cells, etc. Plus it has various combinations of all of the above. 它具有奇数/偶数值的突出显示,选定行的突出显示,选定悬停的行的突出显示,聚焦行和单元格的突出显示等。此外,它还具有上述所有内容的各种组合。 Just setting the background-color directly in the highlight-cell class is a kind of brute force way to achieve what you want because it does not take all these other subtleties into account and just overrides them, so a cell which has been highlighted using this style always looks the same no matter what temporary css psuedo-class state has been applied to it. 只是直接在Highlight-Cell类中设置背景颜色是一种实现所需内容的蛮力方式,因为它没有考虑所有其他细微之处,而是将它们覆盖了,因此使用此方法突出显示的单元格无论已将哪种临时CSS伪类状态应用于样式,样式始终看起来相同。

It's fine really, but a nicer solution would color the highlighted cell differently depending on psuedo-class states. 真的很好,但是更好的解决方案将根据伪类状态对突出显示的单元格进行不同的着色。 That is quite a tricky thing to do though and you could waste a lot of time playing around with various states and css selector combinations to try to get the nice changing highlight. 但这是一件非常棘手的事情,您可能会浪费大量时间来尝试各种状态和CSS选择器组合,以尝试获得变化多端的亮点。 In all, for this example it didn't seem worth that extra effort for me, though it may be for you. 总体而言,对于本示例而言,对我来说似乎不值得付出额外的努力,尽管这可能对您而言。


Test program (apologies for length and complexity of this, it was just easier for me to integrate the style highlighting logic into an existing program): 测试程序(对此的长度和复杂性深表歉意,对我而言,将样式突出显示逻辑集成到现有程序中比较容易):

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, 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 oldValue, Boolean newValue) {
          if (!newValue) {
            commitEdit(checkBox.isSelected());
          }
        }
      });
    }

    private String getString() {
      return getItem() == null ? "" : getItem().toString();
    }

    private Boolean getBoolean() {
      return getItem() == null ? false : (Boolean) getItem();
    }
  }
}

Look, how to understand the CSSRef: 看,如何理解CSSRef:

http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html

Look at 看着

-fx-background-image : -fx-background-image:

uri [ , uri ]* uri [,uri] *

A series of image URIs separated by commas. 一系列图像URI,以逗号分隔。

Look at 看着

-fx-background-repeat -fx背景重复

repeat-style [ , repeat-style ]* 重复样式[,重复样式] *

where repeat-style = repeat-x | 其中repeat-style = repeat-x | repeat-y | 重复- [repeat | [重复| space | 空间 round | 圆形 stretch | 伸展 no-repeat]{1,2} 无重复] {1,2}

A series of values separated by commas. 一系列用逗号分隔的值。 Each repeat-style item in the series applies to the corresponding image in the background-image series. 系列中的每个重复样式项均适用于背景图像系列中的相应图像。

Look at : -fx-background-position 看:-fx-background-position

bg-position [ , bg-position ]* where = [ [ [ size | bg-position [,bg-position] *其中= [[[size | left | 左| center | 中心| right ] [ size | 对] [大小| top | 顶部| center | 中心| bottom ]? 底部]? ] | ] | [ [ center | [[中心| [ left | [左| right ] size? 合适的尺码? ] || ] || [ center | [中心| [ top | [顶部| bottom ] size? 底部]大小? ] ] ]

A series of values separated by commas. 一系列用逗号分隔的值。 Each bg-position item in the series applies to the corresponding image in the background-image series. 系列中的每个bg-position项目都适用于背景图像系列中的相应图像。

So, what can you see : you should describe 2 images, (2x2 pixels each - one red and one - grey) Two bg positions, and two repeat styles for each of them corresponding. 因此,您会看到什么:您应该描述2张图像(每个2x2像素-一个红色和一个-灰色)两个bg位置,以及每个图像对应的两个重复样式。

How? 怎么样?

example : 例如:

{
-fx-backdround-image : "path_to_red", "path_to_grey";
-fx-background-repeat : repeat-x, stretch;
-fx-background-position : 0px 0px, 0px 2px;
}

I don't give a garantee on workness of the code, but the idea seems correct. 我不保证代码的实用性,但是这个想法似乎是正确的。

Maybe possible with only colors instead of images when using insets. 使用插图时,可能仅使用颜色而不是图像。 Example from original JavaFX CSS: 来自原始JavaFX CSS的示例:

.table-row-cell:odd {
  -fx-background-color: -fx-table-cell-border-color, derive(-fx-control-inner-background,-5%);
  -fx-background-insets: 0, 0 0 1 0;
}

[6 characters...] [6个字符...]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM