Слушатель на BooleanProperty

222
02 апреля 2018, 23:30

Добрый день

Есть список объектов BooleanProperty, в который время от времени добавляются новые объекты (отрезки времени не одинаковые), изначально все эти объекты инициализированы со значением true. Так же в процессе работы программы у некоторых объектов из этого списка значение меняется на false (отрезки времени не одинаковые). Доступа к методу который меняет данное значение нет, то есть можно только слушать объекты списка. Heобходимо, что бы после изменения объекта, он удалялся из данного списка, а его индекс передавался в некоторый метод. Написал упрощенное решение того что нужно, но все работает как-то не так. При первом изменении удаления не происходит, при втором изменении удаляется объект с индексом 1, далее получаем исключение IndexOutOfBoundsException

 package example;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.SimpleBooleanProperty;
 public class Main {
     private static final List<BooleanProperty> LIST = new ArrayList<>();
     public static void main(String[] args) {
         fillList(3);
         change(3);                
    }
private static void fillList(int count) {
    for (int i=0; i<count; i++) {
        int time = (int) (Math.random() * 10000 + 1000);
        try {
            Thread.sleep(time);
        } catch (InterruptedException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
        LIST.add(new SimpleBooleanProperty(true));
    }

}
private static void change(int count) {
    for (int i=0; i<count; i++) {
        int time = (int) (Math.random() * 10000 + 1000);
        try {
            Thread.sleep(time);
        } catch (InterruptedException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
        switch (i + 1) {
            case 1:
                LIST.get(i).set(false);
                listner();
                break;
            case 2:
                LIST.get(i).set(false);
                listner();
                break;
            case 3:
                LIST.get(i).set(false);
                listner();
                break;
            default:
                break;
        }
    }
}
private static void listner() {
    for (int i=0; i<LIST.size(); i++) {
        int step = i;
        LIST.get(i).addListener((observable, oldValue, newValue) -> {
            if (!newValue) {
                LIST.get(step).set(true);
                doSomething(step);
                LIST.remove(step);
            }
        });    
    }
}
private static void doSomething(int step) {
    System.out.println("step: " + step);
}

}

Answer 1

В классе javafx.collections.FXCollections есть пара статических методов, создающих обертки и отличающихся от других наличием параметра extractor:

static <E> ObservableList<E> observableArrayList(Callback<E,Observable[]> extractor)
static <E> ObservableList<E> observableList(List<E> list, Callback<E,Observable[]> extractor)

Используя первый метод получаем:

package example;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
public class Main {
    private static final ObservableList<BooleanProperty> LIST =
            FXCollections.observableArrayList(p -> new Observable[]{p});
    public static void main(String[] args) {
        LIST.addListener(new ListChangeListener<BooleanProperty>() {
            @Override
            public void onChanged(Change<? extends BooleanProperty> c) {
                while (c.next()) {
                    // Чтобы посмотреть изменения:
                    if (c.wasPermutated()) {
                        for (int i = c.getFrom(); i < c.getTo(); ++i) {
                            System.out.println("Permuted: " + i + " " + LIST.get(i));
                        }
                    } else if (c.wasUpdated()) {
                        for (int i = c.getFrom(); i < c.getTo(); ++i) {
                            System.out.println("Updated: " + i + " " + LIST.get(i));
                        }
                    } else {
                        for (BooleanProperty removedItem : c.getRemoved()) {
                            System.out.println("Removed: " + removedItem);
                        }
                        for (BooleanProperty addedItem : c.getAddedSubList()) {
                            System.out.println("Added: " + addedItem);
                        }
                    }
                    // Полезная нагрузка:    
                    for (int step = c.getFrom(); step < c.getTo(); ++step) {
                        if (!LIST.get(step).get()) {
                            LIST.get(step).set(true);
                            doSomething(step);
                            LIST.remove(step);
                        }
                    }
                }
            }
        });
        fillList(3);
        change(3);
    }
    private static void fillList(int count) {
        for (int i = 0; i < count; i++) {
//            int time = (int) (Math.random() * 10000 + 1000);
//            try {
//                Thread.sleep(time);
//            } catch (InterruptedException ex) {
//                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
//            }
            LIST.add(new SimpleBooleanProperty(true));
        }

    }
    private static void change(int count) {
        for (int i = count - 1; i >= 0; --i) {
//            int time = (int) (Math.random() * 10000 + 1000);
//            try {
//                Thread.sleep(time);
//            } catch (InterruptedException ex) {
//                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
//            }
            switch (i + 1) {
                case 1:
                    LIST.get(i).set(false);
                    break;
                case 2:
                    LIST.get(i).set(false);
                    break;
                case 3:
                    LIST.get(i).set(false);
                    break;
                default:
                    break;
            }
        }
    }
    private static void doSomething(int step) {
        System.out.println("step: " + step);
    }
}

Слушатель устанавливается до внесения изменений (сразу в main()), так как он в прошлое не может послушать.

Вызовы Thread.sleep() закомментированны, потому что в этом примере только один поток - хоть сколько жди, а "race condition" не дождешься.

Answer 2

Если я вас правильно понял, то....

Создаем wrapper для коллекции

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import java.util.ArrayList;
import java.util.List;
class BooleanPropertyCollection {
private List<BooleanProperty> listBooleanProperty = new ArrayList<>();
private List<Event> listener = new ArrayList<>();
public void add(SimpleBooleanProperty item) {
    listBooleanProperty.add(item);
}
//Публичный лишь для примера, в вашем случае, как я вас понял, он будет private
public void change(int index, boolean newValue) {
    listBooleanProperty.set(index, new SimpleBooleanProperty(newValue));
    for (Event event: listener) {
        event.onChange(this,index);
    }
}
public void remove(int index){
    listBooleanProperty.remove(index);
}
public int getSize(){
    return listBooleanProperty.size();
}
public BooleanProperty getElementByIndex(int index){
    return listBooleanProperty.get(index);
}
public void subscribeOnChange(Event event) {
    listener.add(event);
}
}

Создадим iterface Event

public interface Event {
public void onChange(BooleanPropertyCollection booleanPropertyCollection, int index);
}

И пример использования:

BooleanPropertyCollection test =  new BooleanPropertyCollection();
    test.subscribeOnChange((BooleanPropertyCollection booleanPropertyCollection, int index) -> {
        System.out.println("Размер до: "+booleanPropertyCollection.getSize());
        System.out.println("Изменился элемент index: "+index);
        booleanPropertyCollection.remove(index);
        System.out.println("Удалили элемент с index: "+index);
        System.out.println("Размер после: "+booleanPropertyCollection.getSize());
    });
    test.add(new SimpleBooleanProperty(false));
    test.add(new SimpleBooleanProperty(true));
    test.change(1,true);
READ ALSO
Помощь в переводе кода на java AWT в JavaFX

Помощь в переводе кода на java AWT в JavaFX

Есть код на java awtИз него мне нужна была только "логика"

211
Сглаживание шрифтов в CSS, как? [требует правки]

Сглаживание шрифтов в CSS, как? [требует правки]

Сглаживание шрифтов в CSS, как?

216
Как подключить Bootstrap через @import в СSS

Как подключить Bootstrap через @import в СSS

Люди добрые!) Помогите пожалуйста подключить Bootstrap через @import в СSSСамое интересное Slick-carousel работает а bootstrap нет(( пример на скрине

231
Ошибка с подключением стилей в sass

Ошибка с подключением стилей в sass

Привет!Я начал изучать Angular и решил сделать приложение на нем и мне понадобилось подключить шрифты

236