【问题标题】:Strikethough on table row in javafxjavafx中表格行的删除线
【发布时间】:2021-01-26 16:09:30
【问题描述】:

当用户删除它时,我想在 tableview 中更新一行以删除它。我对 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;
}

但是,我收到警告:WARNING CSS Error parsing '*{delete-row}: Expected COLON at [1,12] 我对css只有非常基本的了解。这是我在其他答案中看到的,但我不明白为什么它对我不起作用。

非常感谢任何帮助。

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


        public void updateItem(Donation d, boolean empty) {
                    super.updateItem(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;
}

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

【问题讨论】:

    标签: javafx tablerow strikethrough


    【解决方案1】:

    setStyle 方法将在Node 上设置内联样式;此样式采用 CSS 规则的形式。这就是你对粗体大小写所做的:

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

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

    这里你必须小心一点,因为列表可以包含相同值的多个副本,另外你无法控制调用updateItem() 的次数以及使用哪个Donations 作为参数。最好的选择是删除类 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, boolean empty) {
        super.updateItem(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 取决于系统对当前选择的字体使用粗体;使用带有 -fx-font 规则的通用(sans-serif)规则更健壮.)

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

    App.java

    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();
        }
    
    }
    

    style.css:

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


    更新:

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

        table.setRowFactory(tv -> {
            TableRow<Donation> row = new TableRow<>() {
    
                // Listener that updates style when the actionProperty() changes
                private final ChangeListener<Donation.Action> listener = 
                    (obs, oldAction, newAction) -> updateStyle();
                
                {
                    // make sure listener above is registered 
                    // with the correct actionProperty()
                    itemProperty().addListener((obs, oldDonation, newDonation) -> {
                        if (oldDonation != null) {
                            oldDonation.actionProperty().removeListener(listener);
                        }
                        if (newDonation != null) {
                            newDonation.actionProperty().addListener(listener);
                        }
                    });
                }
                
                @Override
                protected void updateItem(Donation donation, boolean empty) {
                    super.updateItem(donation, empty);
                    updateStyle();
                }
    
                private void updateStyle() {
                    Donation donation = getItem();
                    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 ;
        });
    

    【讨论】:

    • 尝试了这两个建议。删除和添加不起作用。我喜欢伪类选项,代码更干净,但仍然无法正常工作。我在我的问题中发布了更新的代码。
    • @ChrisWhitcomb 为我工作(稍作修改)。查看更新。
    • 这正是我想要的。表格所在的窗格是一个对话框。 app.java 启动函数中设置的 css 是否会传递到所有窗格,还是我需要将其设置在桌子上?我认为对话框窗格或表格可能看不到 css 文件。
    • 我没有在对话框的新场景上设置 css。一旦我这样做了,它就很好用!感谢您的帮助。
    • @ChrisWhitcomb 嗯,是的,显然表行的updateItem() 方法不会在项目列表中的更新事件上调用(这些是由提取器触发的)。请参阅更新以回答替代解决方案。
    猜你喜欢
    • 1970-01-01
    • 2015-06-21
    • 2016-04-23
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多