在javafx中

问题描述

我希望在用户删除表行时将其更新为删除线。我是javafx的新手,一直没有运气。

        donationsTable.setRowFactory(tv -> {
            TableRow<Donation> row = new TableRow<Donation>() {
                // to force updateItem called
                @Override
                protected boolean isItemChanged(Donation d,Donation d2) {
                    return true;
                }
                
                @Override
                public void updateItem(Donation d,boolean empty) {
                    super.updateItem(d,empty) ;
                    if (d == null) {
                        setStyle("");
                    } else if (d.getAction().equals(Donation.DELETE_DONATION)) {
                        setStyle("delete-row");
                    } else if (d.getAction().equals(Donation.NEW_DONATION)) {
                        setStyle("-fx-font-weight: bold;");
                    } else {
                        setStyle("");
                    }           
                }
            };
            row.setonMouseClicked(event -> {
                    deleteDonation.setdisable(false);
            });
            return row;
        });

粗体字用于新捐赠,但我无法删除线起作用。我确实看到需要在文本而不是行上进行设置,所以我的css是:

.delete-row .text {
    -fx-strikethrough: true;
}

但是,我收到警告:警告CSS错误,解析'* {delete-row}:在[1,12]处预期冒号 我对CSS仅有一个非常基本的了解。这是我在其他答案中看到的,但是我不明白为什么它对我不起作用。

非常感谢您的帮助。

根据James_D的建议,我更改了updateItem:


        public void updateItem(Donation d,empty) ;
                    
                    PseudoClass delete = PseudoClass.getPseudoClass("delete-row");
                    pseudoClassstateChanged(delete,d != null && d.getAction().equals(Donation.DELETE_DONATION));

                    PseudoClass add = PseudoClass.getPseudoClass("add-row");
                    pseudoClassstateChanged(add,d != null && d.getAction().equals(Donation.NEW_DONATION));

                }

css有

.table-row-cell:delete-row .text {
    -fx-strikethrough: true;
}

.table-row-cell:add-row {
    -fx-font-weight: bold;
}

删除线仍然不起作用,粗体停止工作。

解决方法

setStyle方法将在Node上设置内联样式;这种样式采用CSS规则的形式。这是使用粗体显示的情况:

if (d.getAction().equals(Donation.NEW_DONATION)) {
    setStyle("-fx-font-weight: bold;");
}

要将CSS类添加到节点的类列表中,请使用getStyleClass()获取节点的CSS类的列表,然后对其进行操作。

这里您必须要小心一点,因为列表可以包含相同值的多个副本,此外,您无法控制调用updateItem()的次数以及调用Donation的次数。作为参数。最好的选择是删除类delete-row的所有实例,并在正确的条件下重新添加一个实例:

@Override
public void updateItem(Donation d,boolean empty) {
    super.updateItem(d,empty) ;

    getStyleClass().removeAll(Collections.singleton("delete-row"));

    if (d == null) {
        setStyle("");
    } else if (d.getAction().equals(Donation.DELETE_DONATION)) {
        setStyle("");
        getStyleClass().add("delete-row");
    } else if (d.getAction().equals(Donation.NEW_DONATION)) {
        setStyle("-fx-font-weight: bold;");
    } else {
        setStyle("");
    }           
}

另一种选择是改用CSS伪类:

@Override
public void updateItem(Donation d,empty) ;

    PseudoClass delete = PseudoClass.getPseudoClass("delete-row");
    pseudoClassStateChanged(delete,d != null && d.getAction().equals(Donation.DELETE_DONATION));

    if (d != null && d.getAction().equals(Donation.NEW_DONATION)) {
        setStyle("-fx-font-weight: bold;");
    } else {
        setStyle("");
    }           
}

使用

.table-row-cell:delete-row .text {
    -fx-strikethrough: true;
}

在这种情况下,为了保持一致性,我可能还会将NEW_DONATION样式重构为伪类。

这是使用伪类的完整示例。请注意,我将CSS更改为粗体(据我所知,使用font-weight取决于系统当前所选字体的字体是粗体;还是将通用名称(sans-serif)与{{1 }}规则更强大。)

Donation.java

-fx-font

App.java

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Donation {

    public enum Action { NEW_DONATION,DELETE_DONATION,NO_ACTION }
    
    private final StringProperty name = new SimpleStringProperty() ;
    private final ObjectProperty<Action> action = new SimpleObjectProperty<>() ;
    
    public Donation(String name,Action action) {
        setName(name);
        setAction(action);
    }

    public final StringProperty nameProperty() {
        return this.name;
    }
    

    public final String getName() {
        return this.nameProperty().get();
    }
    

    public final void setName(final String name) {
        this.nameProperty().set(name);
    }
    

    public final ObjectProperty<Action> actionProperty() {
        return this.action;
    }
    

    public final Action getAction() {
        return this.actionProperty().get();
    }
    

    public final void setAction(final Action action) {
        this.actionProperty().set(action);
    }
    
    
    
}

style.css:

import java.util.Random;
import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.property.Property;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;


public class App extends Application {

    @Override
    public void start(Stage stage) {
        TableView<Donation> table = new TableView<>();
        
        table.setRowFactory(tv -> {
            TableRow<Donation> row = new TableRow<>() {
                @Override
                protected void updateItem(Donation donation,boolean empty) {
                    super.updateItem(donation,empty);
                    PseudoClass add = PseudoClass.getPseudoClass("add-row");
                    pseudoClassStateChanged(add,donation != null && donation.getAction() == Donation.Action.NEW_DONATION);

                    PseudoClass delete = PseudoClass.getPseudoClass("delete-row");
                    pseudoClassStateChanged(delete,donation != null && donation.getAction() == Donation.Action.DELETE_DONATION);
                }
            };
            return row ;
        });
        
        Random rng = new Random();
        for (int i = 1 ; i <= 40 ; i++) {
            table.getItems().add(new Donation("Donation "+i,Donation.Action.values()[rng.nextInt(3)]));
        }
        
        table.getColumns().add(column("Donation",Donation::nameProperty));
        table.getColumns().add(column("Action",Donation::actionProperty));
        
        BorderPane root = new BorderPane(table);
        Scene scene = new Scene(root);
        scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
        stage.setScene(scene);
        stage.show();
    }
    
    private static <S,T> TableColumn<S,T> column(String name,Function<S,Property<T>> prop) {
        TableColumn<S,T> col = new TableColumn<>(name);
        col.setCellValueFactory(data -> prop.apply(data.getValue()));
        return col ;
    }

    public static void main(String[] args) {
        launch();
    }

}

enter image description here


更新:

如果其中某一列未观察到确定表行样式的属性(例如,在上面的示例中,“ action”列不存在),则需要安排该行观察该属性本身。这有点棘手,因为该行已用于不同的表项,因此您需要在正确的属性中添加和删除侦听器。看起来像:

.table-row-cell:delete-row .text {
    -fx-strikethrough: true;
}

.table-row-cell:add-row {
    /* -fx-font-weight: bold; */
    -fx-font: bold 1em sans-serif ;
}