一个相对的Java新手问题。
我正在尝试根据是否选择TableRow
和/或数据模型中的布尔值是否为真来设置setRowFactory
的背景颜色。
我找到了在同一final ObservableSet<Integer> selectedRowIndexes = FXCollections.observableSet();
table.getSelectionModel().getSelectedCells().addListener((Change<? extends TablePosition> change) -> {
selectedRowIndexes.clear();
selectedRowIndexes.add( (table.getSelectionModel().getSelectedCells().get(0)).getRow() );
});
table.setRowFactory(tv -> {
TableRow<TestModel> row = new TableRow<>();
BooleanBinding selected = Bindings.createBooleanBinding(() ->
selectedRowIndexes.contains(new Integer(row.getIndex())), row.indexProperty(), selectedRowIndexes);
row.styleProperty().bind(Bindings.when(selected)
.then("-fx-background-color: green;")
.otherwise(""));
return row;
});
中一起做但不能一起做的方法。
我最后要说的是这个(尽管仅出于示例目的使用了可怕的颜色!):
我将如何实现这一目标?
这是我发现根据选择更改行颜色的结果。它是根据用户James_D在这里https://community.oracle.com/thread/3528543的回答改编的。
table.setRowFactory(tv -> {
TableRow<TestModel> row = new TableRow<TestModel>() {
@Override
public void updateItem(TestModel testmodel, boolean empty) {
super.updateItem(testmodel, empty);
boolean locked = false;
if ( getItem() != null ) {
locked = getItem().lockedProperty().get();
setEditable( ! locked);
}
if (!isEmpty() && locked ) {
setStyle("-fx-background-color: red;");
}else{
setStyle(null);
}
}
};
return row;
});
这就是我发现根据单元格值更改行颜色的结果。它是根据用户kleopatra在此处TreeTableView : setting a row not editable的回答改编而成的。
package test31;
import java.util.Arrays;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.collections.ObservableSet;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.converter.BooleanStringConverter;
public class Test31 extends Application {
private Parent createContent() {
TableView<TestModel> table = new TableView<>();
ObservableList<TestModel> olTestModel = FXCollections.observableArrayList(testmodel -> new Observable[] {});
olTestModel.add(new TestModel("1", true));
olTestModel.add(new TestModel("2", false));
olTestModel.add(new TestModel("3", false));
olTestModel.add(new TestModel("4", true));
olTestModel.add(new TestModel("5", false));
TableColumn<TestModel, String> colText = new TableColumn<>("textfield");
colText.setCellValueFactory(cb -> cb.getValue().textFieldProperty());
colText.setCellFactory(TextFieldTableCell.forTableColumn());
TableColumn<TestModel, Boolean> colBoolean = new TableColumn<>("locked");
colBoolean.setCellValueFactory(cb -> cb.getValue().lockedProperty());
colBoolean.setCellFactory(TextFieldTableCell.forTableColumn(new BooleanStringConverter()));
table.getSelectionModel().setCellSelectionEnabled(true);
table.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
table.setEditable(true);
table.getColumns().addAll(Arrays.asList(colText, colBoolean));
table.setItems(olTestModel);
//****************************************************************************************
//First row factory: Set background colour based on whether or not the row is selected
final ObservableSet<Integer> selectedRowIndexes = FXCollections.observableSet();
table.getSelectionModel().getSelectedCells().addListener((Change<? extends TablePosition> change) -> {
selectedRowIndexes.clear();
selectedRowIndexes.add( (table.getSelectionModel().getSelectedCells().get(0)).getRow() );
});
table.setRowFactory(tv -> {
TableRow<TestModel> row = new TableRow<>();
BooleanBinding selected = Bindings.createBooleanBinding(() ->
selectedRowIndexes.contains(new Integer(row.getIndex())), row.indexProperty(), selectedRowIndexes);
row.styleProperty().bind(Bindings.when(selected)
.then("-fx-background-color: green;")
.otherwise(""));
return row;
});
//****************************************************************************************
//Second row factory: Set background colour based on the value of a boolean property
table.setRowFactory(tv -> {
TableRow<TestModel> row = new TableRow<TestModel>() {
@Override
public void updateItem(TestModel testmodel, boolean empty) {
super.updateItem(testmodel, empty);
boolean locked = false;
if ( getItem() != null ) {
locked = getItem().lockedProperty().get();
setEditable( ! locked);
}
if (!isEmpty() && locked ) {
setStyle("-fx-background-color: red;");
}else{
setStyle(null);
}
}
};
return row;
});
BorderPane content = new BorderPane(table);
return content;
}
public class TestModel {
private StringProperty textField;
private BooleanProperty locked;
public TestModel() {
this("", false);
}
public TestModel(
String textField,
boolean locked
) {
this.textField = new SimpleStringProperty(textField);
this.locked = new SimpleBooleanProperty(locked);
}
public String getTextField() {
return textField.get().trim();
}
public void setTextField(String textField) {
this.textField.set(textField);
}
public StringProperty textFieldProperty() {
return textField;
}
public boolean getLocked() {
return locked.get();
}
public void setLocked(boolean locked) {
this.locked.set(locked);
}
public BooleanProperty lockedProperty() {
return locked;
}
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setTitle("Test");
stage.setWidth(500);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
但是,我最终得到了两排工厂,却无法弄清楚如何将它们合并为一个。
如果有帮助,这是我一直在玩的MVCE。它有两排工厂。我没有(很多!)尝试合并它们,因为没有任何效果。
我正在使用JavaFX8(JDK1.8.0_181),NetBeans 8.2和Scene Builder 8.3。
#include "h_node.h"
#define ASCII 256
/* How to check if we are at the leaflet */
int isLeaf(h_node *root) {
return !(root->left) && !(root->right);
}
/* To print the codes */
void printBin(h_node *root,char arr[], int n) {
/* To assign 0 */
if (root -> left){
arr[n] = 0;
printBin(root -> left, arr, ++n);
}
/* To assign 1 */
if (root -> right){
arr[n] = 1;
printBin(root -> right, arr, ++n );
}
// Check if we are at the leaf
if (isLeaf(root)){
int i;
printf(" \n %c: ", root -> letter);
for (i = 0; i < n; i++)
printf("%d", arr[i]);
printf("\n");
}
}
/* Creating the treeNode */
h_node *createNode(char a, int i, h_node *l, h_node *r) {
h_node *node = calloc(1,sizeof(h_node));
if (node) {
node -> letter = a;
node -> freq = i;
node -> next = NULL;
node -> left = l;
node -> right = r;
}
return node;
}
/* Function to check size of file */
off_t fsize(const char *file) {
struct stat filestat;
if (stat(file, &filestat) == 0) {
return filestat.st_size;
}
return 0;
}
/* Sorting algorithm */
void h_sort(h_node a[], int size){
for (int c = 0; c < (size-1); c++) {
int pos = c;
if ( a[c].freq != 0 ) {
for (int d = c + 1; d < size; d++) {
if(a[pos].freq > a[d].freq)
pos = d;
}
if ( pos != c ) {
h_node swap = a[c];
a[c] = a[pos];
a[pos] = swap;
}
}
}
}
///////////////////////////////////////////////////////////
int compare(h_node *one, h_node *two) {
int result;
result = (one -> freq) - (two -> freq);
if(!result) {
result = (one -> letter) - (two -> letter);
}
return result;
}
////////////
h_node *insert_ll(h_node *ll, h_node *t) {
h_node *temp;
if(!ll || (compare(ll, t) > 0)) {
t -> next = ll;
temp = t;
} else {
temp = ll;
while(ll -> next && (compare(ll -> next, t) < 0)) {
ll = ll -> next;
}
t -> next = ll -> next;
ll -> next = t;
}
return temp;
}
////////////////////
h_node *insert_tree(h_node *list, h_node *new) {
h_node *temp;
if(!list || new -> freq <= list -> freq) {
new -> next = list;
temp = new;
}else{
temp = list;
while(list -> next && list -> next -> freq < new -> freq) {
list = list -> next;
}
new -> next = list -> next;
list -> next = new;
}
return temp;
}
/* This will parse my sorted list and take two structures at a time */
h_node *create_tree(h_node *list) {
h_node *new, *head, *left, *right;
int sum;
head = list;
while(head -> next != NULL) {
left = head;
head = head -> next;
/*
* If head is null, end of list has been reached
*/
if(!head) {
break;
}
right = head;
head = head -> next;
sum = (left -> freq) + (right -> freq);
if (left -> freq > right -> freq)
new = createNode(left -> letter, sum, left, right);
if (left -> freq == right -> freq)
new = createNode(left -> letter,sum,left,right);
if (left -> freq < right -> freq)
new = createNode(right -> letter,sum,left,right);
head = insert_tree(head, new);
}
return head;
}
void treeprint(struct h_node *p){
if ( p != NULL ){
treeprint(p->left);
printf("\n %d %x \n",p->freq, p->letter);
treeprint(p->right);
}
}
/* Sorting algorithm */
void sort(int a[], int size){
for (int c = 0; c < (size-1); c++) {
int pos = c;
if ( a[c] != 0 ) {
for (int d = c + 1; d < size; d++) {
if(a[pos] > a[d])
pos = d;
}
if ( pos != c ) {
int swap = a[c];
a[c] = a[pos];
a[pos] = swap;
}
}
}
}
/* Finding the frequency */
void freq(char a[],int d[]) {
int c = 0;
while (a[c] != '\0'){
d[(int)a[c]]++;
c++;
}
}
/* Start of Main */
int main ( int argc, char *argv[] ){
char ch;
FILE *fp;
int i=0;
int j = 0;
int sameness = 0;
int size = fsize(argv[1]);
h_node *head = NULL;
//h_node *new;
printf("The size is %d\n",size);
fp = fopen(argv[1], "r"); // read mode
if (fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
/* Now we create that array of size .. size */
char *arr =calloc(fsize(argv[1]),sizeof(char));
int *count =calloc(ASCII,sizeof(int));
printf("The size of the file is %ld\n",fsize(argv[1]));
/* This will copy each charater from the file into an array */
while((ch = fgetc(fp)) != EOF){
arr[i++] = ch;
fflush(fp);
}
/* This is just to check to make sure everything properly prints out */
printf("The contents of the file are:\n");
for (int i = 0; i <= size-1; i++)
printf("%c ", arr[i]);
/* Now we want to selection sort the array so that it is in ascii value */
printf("\nThis is i : %d\n", i);
/* Now we want to count frequency */
freq(arr,count);
/* Now we want to sort by Frequency */
//sort(count,256);
printf("\n");
for (i = 0; i < ASCII; i++){
if(count[i] != 0){
sameness +=1;
printf("%c %d\n ",i,count[i]);
}
}
printf("\n this is the sizeof sameness : %d \n", sameness);
struct h_node* h_arr=calloc(sameness,sizeof(h_node));
/* This is just to check to make sure everything properly prints out */
printf("The contents of the file are:\n");
for (int i = 0; i < ASCII; i++)
if(count[i] != 0){
printf("0x%x happens: %d time(s)\n", i,count[i]);
h_arr[j].letter = i;
printf("0x%x \n",h_arr[j].letter);
h_arr[j].freq = count[i];
printf(" %d \n",h_arr[j].freq);
j++;
}
struct h_node* h_arr2=calloc(sameness,sizeof(h_node));
for (int i = 0; i < sameness; i++){
for (int p = i + 1 ; p < sameness; p++)
if(h_arr[i].freq > h_arr[i + 1].freq){
if( i == 0)
h_arr2[i] = *createNode(h_arr[i].letter,
h_arr[i].freq,NULL,NULL);
h_arr2[i]= *createNode(h_arr[i].letter,
h_arr[i].freq,&h_arr[i],&h_arr[i+1]);
}
else
if ( i == 0 )
h_arr2[i] = *createNode(h_arr[i + 1].letter,
h_arr[i + 1].freq,NULL,NULL);
h_arr2[i] = *createNode(h_arr[i].letter,
h_arr[i].freq,&h_arr[i],&h_arr[i]);
}
h_sort(h_arr2,sameness);
for (int i = 0; i < sameness; i++)
printf("\n hi %x %d %x %d\n", h_arr2[i].letter,
h_arr2[i].freq,h_arr2[i].left -> letter,h_arr2[i].right -> freq);
//This will be to input the nodes into a LL //
for (int i = 0; i < sameness; i++){
head = insert_ll(&h_arr2[i], &h_arr2[i+1]);
}
head = create_tree(head);
char *codes =(char *) malloc(sizeof(char));
printBin(head,codes,0);
/* Test to make sure it prints out correctly */
printf("\n\n");
printf("this is i: %d\n",i);
printf("%d\n",size);
free(arr);
free(count);
fclose(fp);
return 0;
}
答案 0 :(得分:1)
有两种方法可以执行此操作。这是一个使用外部CSS和伪类的示例:
Main.java
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView<>(createDummyData(100));
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
table.setRowFactory(t -> new ItemTableRow());
TableColumn<Item, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(features -> features.getValue().nameProperty());
table.getColumns().add(nameCol);
TableColumn<Item, Boolean> validCol = new TableColumn<>("Valid");
validCol.setCellValueFactory(features -> features.getValue().validProperty());
table.getColumns().add(validCol);
primaryStage.setScene(new Scene(new StackPane(table), 800, 600));
primaryStage.getScene().getStylesheets().add(getClass().getResource("Main.css").toExternalForm());
primaryStage.setTitle("JavaFX Application");
primaryStage.show();
}
private ObservableList<Item> createDummyData(int count) {
return IntStream.rangeClosed(1, count)
.mapToObj(i -> "Item #" + i)
.map(name -> new Item(name, Math.random() >= 0.5))
.collect(Collectors.toCollection(FXCollections::observableArrayList));
}
}
ItemTableRow.java
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
import javafx.css.PseudoClass;
import javafx.scene.control.TableRow;
public class ItemTableRow extends TableRow<Item> {
private static final PseudoClass VALID = PseudoClass.getPseudoClass("valid");
private final ChangeListener<Boolean> listener = (obs, oldVal, newVal) -> updateValidPseudoClass(newVal);
private final WeakChangeListener<Boolean> weakListener = new WeakChangeListener<>(listener);
public ItemTableRow() {
getStyleClass().add("item-table-row");
}
@Override
protected void updateItem(Item item, boolean empty) {
Item oldItem = getItem();
if (oldItem != null) {
oldItem.validProperty().removeListener(weakListener);
}
super.updateItem(item, empty);
if (empty || item == null) {
updateValidPseudoClass(false);
} else {
item.validProperty().addListener(weakListener);
updateValidPseudoClass(item.isValid());
}
}
private void updateValidPseudoClass(boolean active) {
pseudoClassStateChanged(VALID, active);
}
}
Item.java
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Item {
private final StringProperty name = new SimpleStringProperty(this, "name");
public final void setName(String name) { this.name.set(name); }
public final String getName() { return name.get(); }
public final StringProperty nameProperty() { return name; }
private final BooleanProperty valid = new SimpleBooleanProperty(this, "valid");
public final void setValid(boolean valid) { this.valid.set(valid); }
public final boolean isValid() { return valid.get(); }
public final BooleanProperty validProperty() { return valid; }
public Item() {}
public Item(String name, boolean valid) {
setName(name);
setValid(valid);
}
}
Main.css
.item-table-row:selected {
-fx-background-color: -fx-control-inner-background, green;
}
.item-table-row:valid {
-fx-background-color: -fx-control-inner-background, yellow;
}
.item-table-row:valid:selected {
-fx-background-color: -fx-control-inner-background, red;
}
如果您只想使用代码,请将ItemTableRow
更改为此(并从getStylesheets().add(...)
中删除Main
):
import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
import javafx.scene.control.TableRow;
public class ItemTableRow extends TableRow<Item> {
private final InvalidationListener listener = observable -> updateStyle();
private final WeakInvalidationListener weakListener = new WeakInvalidationListener(listener);
public ItemTableRow() {
getStyleClass().add("item-table-row");
selectedProperty().addListener(listener); // could also override updateSelected
}
@Override
protected void updateItem(Item item, boolean empty) {
Item oldItem = getItem();
if (oldItem != null) {
oldItem.validProperty().removeListener(weakListener);
}
super.updateItem(item, empty);
if (item != null) {
item.validProperty().addListener(weakListener);
}
updateStyle();
}
private void updateStyle() {
final Item item = getItem();
if (item == null || (!isSelected() && !item.isValid())) {
setStyle(null);
} else if (isSelected() && item.isValid()) {
setStyle("-fx-background-color: -fx-control-inner-background, red;");
} else if (isSelected()) {
setStyle("-fx-background-color: -fx-control-inner-background, green;");
} else if (item.isValid()) {
setStyle("-fx-background-color: -fx-control-inner-background, yellow;");
} else {
// I don't think this branch is possible, but not 100% sure
throw new AssertionError("Shouldn't be here?");
}
}
}
-fx-control-inner-background
的值在modena.css
(JavaFX 8+的默认样式表)中定义。它为TableRow
带来了一点点色填充。