मेरे पास एक कस्टम TableCell के selectedProperty() पर एक InvalidationListener सेट है। मैं डेटा मॉडल में बूलियन मान के आधार पर पंक्तियों की संपादन क्षमता और पृष्ठभूमि का रंग बदलने के लिए इसका उपयोग करता हूं।

जब मैं किसी सेल पर क्लिक करता हूं और फिर उसी पंक्ति में पिछले सेल पर क्लिक करता हूं, तो मैं पंक्ति रंग के रहस्यमय ढंग से गायब होने को डीबग कर रहा था और इसे बिंदु पर isSelected() के मान तक ट्रैक किया। कौन सा पंक्ति रंग सेट है।

मैं जो देख सकता था, उससे isSelected() एक पंक्ति में आगे बढ़ते हुए false से true में बदल जाता है, लेकिन पीछे की ओर जाने पर true से false में बदल जाता है।

ऐसा व्यवहार क्यों करता है? क्या यह उन परिवर्तनों के अनुरूप नहीं होना चाहिए जिनकी वह रिपोर्ट करता है?

मैंने isSelected() के बजाय selectedProperty.get() और InvalidationListener के बजाय ChangeListener का उपयोग करने का प्रयास किया, लेकिन वही परिणाम मिला। और यही बात तब होती है जब मैं माउस के बजाय कीबोर्ड से नेविगेट करता हूं।

यहां एक एमवीसीई है जो इस मुद्दे को प्रदर्शित करता है। यह यहां उपयोगकर्ता स्लाव के उत्तर पर आधारित है JavaFX8 TableView में डेटा मॉडल में चयनित है या नहीं और/या डेटा मॉडल में मान के आधार पर TableRow की पृष्ठभूमि का रंग कैसे सेट करें? और उपयोगकर्ता kleopatra का उत्तर यहां TreeTableView : एक पंक्ति को संपादन योग्य नहीं सेट करना

व्यवहार को पुन: पेश करने के लिए, पंक्ति के दूसरे या तीसरे सेल पर क्लिक करें। यह नीचे दिखाए गए मैट्रिक्स के अनुसार रंग बदलेगा। फिर उसी पंक्ति में पिछले सेल पर क्लिक करें। पंक्ति का रंग गायब हो जाना चाहिए और डिफ़ॉल्ट पर वापस आ जाना चाहिए। isSelected() और selectedProperty() के मान कंसोल पर आउटपुट होंगे।

enter image description here

मैं जावाएफएक्स 8 (जेडीके 1.8.0_181), नेटबीन 8.2 और सीन बिल्डर 8.3 का उपयोग कर रहा हूं।

Test45_Listeners.java

package test45_listeners;

import java.util.Arrays;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.Observable;
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.ObservableList;
import javafx.scene.Parent;
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 Test45_Listeners extends Application {

    private final ObservableList<TestModel> olTestModel 
            = FXCollections.observableArrayList(testmodel -> new Observable[] {});

    private Parent createContent() {

        //Initialise the TableView and data
        createDummyData(100);

        TableView<TestModel> table = new TableView<>();

        TableColumn<TestModel, String> colField1 = new TableColumn<>("field1");
        colField1.setCellValueFactory(features -> features.getValue().field1Property());
        colField1.setCellFactory(col -> TestTextCell.createStringTextCell(TestModel::lockedProperty));

        TableColumn<TestModel, String> colField2 = new TableColumn<>("field2");
        colField2.setCellValueFactory(features -> features.getValue().field2Property());
        colField2.setCellFactory(col -> TestTextCell.createStringTextCell(TestModel::lockedProperty));

        TableColumn<TestModel, String> colField3 = new TableColumn<>("field3");
        colField3.setCellValueFactory(features -> features.getValue().field3Property());
        colField3.setCellFactory(col -> TestTextCell.createStringTextCell(TestModel::lockedProperty));

        table.setItems(olTestModel);
        table.getColumns().addAll(Arrays.asList(colField1, colField2, colField3));
        table.setEditable(true);
        table.getSelectionModel().setCellSelectionEnabled(true);
        table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

        //Set a row factory to set the background colour of any LOCKED row to be yellow
        table.setRowFactory(tv -> {
            TableRow<TestModel> row = new TableRow<TestModel>() {
                @Override
                public void updateItem(TestModel item, boolean empty) {
                    super.updateItem(item, empty);
                    boolean locked = false;
                    if ( getItem() != null ) {
                        locked = getItem().lockedProperty().get();
                        setEditable( ! locked );
                    }

                    if ( !isEmpty() && locked ) {
                        setStyle("-fx-background-color: yellow;");
                    } else {
                        setStyle(null);
                    }

                }
            };
            return row;
        });

        BorderPane content = new BorderPane(table);
        return content;
    }

    private void createDummyData(int count) {

        for ( int i=0; i<count; i++ ) {
            boolean locked = Math.random() >= 0.5;
            olTestModel.add(new TestModel(locked, (locked ? "row LOCKED" : "row NOT locked"),
                    Integer.toString(i), "a"+Integer.toString(i)));
        }

    }

    private class TestModel {

        private final BooleanProperty locked;
        private final StringProperty field1;
        private final StringProperty field2;
        private final StringProperty field3;

        public TestModel(

            boolean locked,
            String field1,
            String field2,
            String field3
        ) {
            this.locked = new SimpleBooleanProperty(locked);
            this.field1 = new SimpleStringProperty(field1);
            this.field2 = new SimpleStringProperty(field2);
            this.field3 = new SimpleStringProperty(field3);
        }

        public boolean getLocked() {return locked.get();}
        public void setLocked(boolean locked) {this.locked.set(locked);}
        public BooleanProperty lockedProperty() {return locked;}

        public String getField1() {return field1.get();}
        public void setField1(String field1) {this.field1.set(field1);}
        public StringProperty field1Property() {return field1;}

        public String getField2() {return field2.get();}
        public void setField2(String field2) {this.field2.set(field2);}
        public StringProperty field2Property() {return field2;}

        public String getField3() {return field3.get();}
        public void setField3(String field3) {this.field3.set(field3);}
        public StringProperty field3Property() {return field3;}

    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        stage.setTitle("Test");
        stage.setWidth(350);
        stage.show();
    }

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

}

टेस्टटेक्स्टसेल.जावा

package test45_listeners;

import java.util.function.Function;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WeakChangeListener;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
import javafx.util.StringConverter;
import javafx.util.converter.DefaultStringConverter;

public class TestTextCell<S, T> extends TableCell<S, T> {

    public final TextField textField = new TextField();
    public final StringConverter<T> converter;

    private BooleanProperty isLockedProperty;

    private final InvalidationListener strongListener = (Observable observable) -> {
        updateStyle();
    };
    private final WeakInvalidationListener weakListener = new WeakInvalidationListener(strongListener);
/*
    public ChangeListener<Boolean> strongListener = (ObservableValue<? extends Boolean> observable, Boolean wasFocused, Boolean isNowFocused) -> {
        updateStyle();
    };
    public final WeakChangeListener<Boolean> weakListener = new WeakChangeListener<Boolean>(strongListener);
*/
    //********************************************************************************************************************* 
    public TestTextCell(StringConverter<T> converter, Function<S, BooleanProperty> methodGetLockedProperty) {

        this.converter = converter;
        setGraphic(textField);
        setContentDisplay(ContentDisplay.TEXT_ONLY);

        itemProperty().addListener((obx, oldItem, newItem) -> {
            if (newItem == null) {
                setText(null);
            } else {
                setText(converter.toString(newItem));
                if ( methodGetLockedProperty != null ) {
                    S datamodel = getTableView().getItems().get(getIndex());
                    isLockedProperty = methodGetLockedProperty.apply(datamodel);
                } else {
                    isLockedProperty = new SimpleBooleanProperty(false);
                }
            }
        });

        //Add the invalidation listener
        selectedProperty().addListener(strongListener);

    }

    //*******************************************************************************************************************    
    public static <S> TestTextCell<S, String> createStringTextCell(Function<S, BooleanProperty> methodGetLockedProperty) {
        return new TestTextCell<S, String>(new DefaultStringConverter(), methodGetLockedProperty);
    }

    //*******************************************************************************************************************    
    @Override
    protected void updateItem(T item, boolean empty) {

        T oldItem = (T) getItem();
        if (oldItem != null) {
            selectedProperty().removeListener(weakListener);
        }

        super.updateItem(item, empty);

        if (item != null) {
            selectedProperty().addListener(weakListener);

            if ( getTableRow() != null ) {
                if (getGraphic() != null) {
                    getGraphic().disableProperty().bind(
                        Bindings.not(getTableRow().editableProperty())
                    );
                }
            }
        }

    }

    @Override
    public void startEdit() {
        if ( ! isLockedProperty.get() ) {
            super.startEdit();
            if (getGraphic() != null) {
                textField.setText(converter.toString(getItem()));
                setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                getGraphic().requestFocus();
            }
        }
    }

    @Override
    public void cancelEdit() {
        super.cancelEdit();
        setContentDisplay(ContentDisplay.TEXT_ONLY);
    }

    //*******************************************************************************************************************    
    private void updateStyle() {

        System.out.println("in updateStyle(), isLockedProperty = " + isLockedProperty.get() 
                + ", isSelected() = " + isSelected() + ", selectedProperty.get() = " + selectedProperty().get());
        if ( getTableRow() != null ) {
            if ( isLockedProperty.get() && isSelected() ) {
//            if ( isLockedProperty.get() && selectedProperty().get() ) {
                getTableRow().setStyle("-fx-background-color: pink;");
            } else if ( isLockedProperty.get() && ! isSelected()) {
//            } else if ( isLockedProperty.get() && ! selectedProperty().get() ) {
                getTableRow().setStyle("-fx-background-color: yellow;");
            } else if ( ! isLockedProperty.get() && isSelected() ) {
//            } else if ( ! isLockedProperty.get() && selectedProperty().get() ) {
                getTableRow().setStyle("-fx-background-color: #b6e1fc;");
            } else if ( ! isLockedProperty.get() && ! isSelected() ) {
//            } else if ( ! isLockedProperty.get() && ! selectedProperty().get() ) {
                getTableRow().setStyle(null);
            } else {
                throw new AssertionError("how did I get here?");
            }
        }

    }

}
0
GreenZebra 22 अक्टूबर 2018, 07:14

1 उत्तर

सबसे बढ़िया उत्तर

टिप्पणियों में सभी अच्छे और मूल्यवान सुझावों के अलावा, "क्यों" के वास्तविक प्रश्न का उत्तर देने के लिए :: टेबलसेल की isSelected() विधि वास्तव में ठीक काम कर रही है और आपके कोड में एक समस्या है जो है आवश्यक तर्क की गलत गणना करना।

इसे सही ठहराने के लिए, मैं चाहूंगा कि आप अपने प्रिंट स्टेटमेंट को अपडेट स्टाइल () विधि में नीचे अपडेट करें

System.out.println(getItem() + " :: in updateStyle(), isLockedProperty = " + isLockedProperty.get() + ", isSelected() = " + isSelected());

आइए पहली पंक्ति के लिए विचार करें:

enter image description here

यदि मैं बाएं से दाएं कक्षों का चयन करता हूं, तो आउटपुट नीचे जैसा है ::

// When field1 is selected
row LOCKED :: in updateStyle(), isLockedProperty = true, isSelected() = true
row LOCKED :: in updateStyle(), isLockedProperty = true, isSelected() = true

// When field2 is selected
row LOCKED :: in updateStyle(), isLockedProperty = true, isSelected() = false
row LOCKED :: in updateStyle(), isLockedProperty = true, isSelected() = false
0 :: in updateStyle(), isLockedProperty = true, isSelected() = true
0 :: in updateStyle(), isLockedProperty = true, isSelected() = true

// When field3 is selected
0 :: in updateStyle(), isLockedProperty = true, isSelected() = false
0 :: in updateStyle(), isLockedProperty = true, isSelected() = false
a0 :: in updateStyle(), isLockedProperty = true, isSelected() = true
a0 :: in updateStyle(), isLockedProperty = true, isSelected() = true

कुछ समय के लिए, प्रत्येक चयन के दोहरे प्रिंट के बारे में परेशान न हों (क्योंकि आप मजबूत श्रोता और कमजोर श्रोता दोनों को सेट कर रहे हैं)। लेकिन आउटपुट से जो हम समझते हैं वह यह है कि हर बार जब हम किसी सेल का चयन करते हैं, तो पहले वाले सेल का चयनित मान गलत पर सेट हो जाता है जो कि सही है। यह आपकी शैली को अद्यतन करने के लिए अच्छी तरह से काम करता है क्योंकि 'सत्य' हमेशा 'झूठे' के बाद आता है।

अब दाएं से बाएं सेलों का चयन करने का प्रयास करें, आउटपुट नीचे जैसा है ::

// When field3 is selected
a0 :: in updateStyle(), isLockedProperty = false, isSelected() = true
a0 :: in updateStyle(), isLockedProperty = false, isSelected() = true

// When field2 is selected
0 :: in updateStyle(), isLockedProperty = false, isSelected() = true
0 :: in updateStyle(), isLockedProperty = false, isSelected() = true
a0 :: in updateStyle(), isLockedProperty = false, isSelected() = false
a0 :: in updateStyle(), isLockedProperty = false, isSelected() = false

// When field1 is selected
row NOT locked :: in updateStyle(), isLockedProperty = false, isSelected() = true
row NOT locked :: in updateStyle(), isLockedProperty = false, isSelected() = true
0 :: in updateStyle(), isLockedProperty = false, isSelected() = false
0 :: in updateStyle(), isLockedProperty = false, isSelected() = false

आउटपुट से यह बहुत स्पष्ट है कि 'असत्य' से पहले 'सत्य' आ रहा है। दूसरे शब्दों में शायद JavaFX आंतरिक रूप से हमेशा सेल चयन को बाएं से दाएं क्रमिक रूप से अपडेट करता है

यह वह जगह है जहाँ आपका कोड विफल रहता है। जब आप सिलेक्शन को राइट से लेफ्ट में बदलते हैं, तो लेफ्ट सेल अपडेट को पहले कॉल किया जाता है और फिर राइट सेल अपडेट को कहा जाता है। और चूंकि आपका दायां सेल नहीं चुना गया है, आप अपनी वांछित चयनित पंक्ति शैली कभी नहीं देख सकते हैं।

संभावित समाधान::

मैं फिर से उल्लेख कर रहा हूं कि कृपया टिप्पणियों में सभी सुझावों पर विचार करें। जैसा कि आप इस विचार को छोड़ने की योजना बना रहे हैं, मैं आपको केवल यह बताना चाहता हूं कि यह अभी भी एक कार्यान्वयन योग्य है। अन्य बेहतर तरीके हो सकते हैं, लेकिन यह एक संभावित समाधान है।

उपरोक्त विश्लेषण से, यह बहुत स्पष्ट है कि सेल चयन पर निर्भर अपना वांछित व्यवहार प्राप्त करना एक उपयुक्त समाधान नहीं है। मैं पंक्ति कारखाने में ही सभी पंक्ति स्टाइल करने की अनुशंसा करता हूं।

इसके लिए आपको टेबल आइटम में एक नई बूलियनप्रॉपर्टी की आवश्यकता है, ताकि आपको यह पता चल सके कि पंक्ति का चयन किया गया है या नहीं।

कृपया अपने वर्तमान कोड में निम्नलिखित परिवर्तन करें:

1) TestTextCell.java में अपडेट स्टाइल () विधि पर टिप्पणी करें और सभी श्रोताओं से छुटकारा पाएं।

2) टेस्टमोडेल और उपयुक्त गेटर्स और सेटर्स में एक नई संपत्ति जोड़ें।

private final BooleanProperty selected = new SimpleBooleanProperty();

3) मॉडल में आइटम चयन को अद्यतन करने के लिए तालिका दृश्य का चयनित इटैम श्रोता जोड़ें।

table.getSelectionModel().selectedItemProperty().addListener((obs, oldItem, newItem) -> {
    if (oldItem != null) {
        oldItem.setSelected(false);
    }
    if (newItem != null) {
        newItem.setSelected(true);
    }
});

4) अपनी पंक्ति फ़ैक्टरी कार्यान्वयन को नीचे अपडेट करें:

//Set a row factory to set the background colour of any LOCKED row to be yellow
table.setRowFactory(tv -> {
    TableRow<TestModel> row = new TableRow<TestModel>() {

        private final ChangeListener<Boolean> listener = (o, v, newValue) -> updateStyle();

        {
            itemProperty().addListener((obs, oldItem, newItem) -> {
                if (oldItem != null) {
                    oldItem.selectedProperty().removeListener(listener);
                }
                if (newItem != null) {
                    newItem.selectedProperty().addListener(listener);
                }
            });
        }

        @Override
        public void updateItem(TestModel item, boolean empty) {
            super.updateItem(item, empty);
            if (getItem() != null) {
                setEditable(!getItem().getLocked());
            } else {
                setEditable(false);
            }
            updateStyle();
        }

        private void updateStyle(){
            if (getItem() != null) {
                boolean isLocked = getItem().getLocked();
                boolean isSelected = getItem().isSelected();
                if (isLocked) {
                    if (isSelected) {
                        setStyle("-fx-background-color: pink;");
                    } else {
                        setStyle("-fx-background-color: yellow;");
                    }
                } else {
                    if (isSelected) {
                        setStyle("-fx-background-color: #b6e1fc;");
                    } else {
                        setStyle("-fx-background-color: transparent;");
                    }
                }
            } else {
                setStyle("-fx-background-color: transparent;");
            }
        }
    };
    return row;
});

मैं अपनी समझ में किसी भी सुधार के लिए वास्‍तव में स्‍वागत करूंगा।

1
wcmatthysen 19 नवम्बर 2019, 12:15