javafx: หลายเหตุการณ์ใน setRowFactory และรวมคลาสภายในที่ไม่ระบุชื่อและนิพจน์แลมบ์ดา

ฉันมีเหตุการณ์ 2 ชุดที่เปลี่ยนรูปลักษณ์ของแถวในตาราง

  1. ตารางจะกะพริบเมื่อมีเงื่อนไขบางอย่างกะพริบ
  2. ตารางที่เน้นเมื่อมีการเพิ่มรายการใหม่

สมมติว่า TableView ของฉันชื่อ table โครงสร้างโค้ดของฉันจะเป็นดังนี้:

TableView<Trade> table = ... ;
table.setRowFactory(            private final BooleanBinding itemIsNewTrade = Bindings.isNotNull(itemProperty()).and(Bindings.equal(itemProperty(), recentlyAddedTrade));

        {
            // anonymous constructor:
            itemIsNewTrade.addListener((obs, wasNew, isNew) -> pseudoClassStateChanged(newTradePseudoClass, isNew));
        }   

            tv -> {
            TableRow<Trade> row = new TableRow<>();
            Timeline flasher = new Timeline(

                    new KeyFrame(Duration.seconds(0.5), e -> {
                        row.pseudoClassStateChanged(flashHighlight, true);
                    }),

                    new KeyFrame(Duration.seconds(1.0), e -> {
                        row.pseudoClassStateChanged(flashHighlight, false);
                    })
            );
            flasher.setCycleCount(Animation.INDEFINITE);

            ChangeListener<Boolean> cautionListener = (obs, cautionWasSet, cautionIsNowSet) -> {
                if (cautionIsNowSet) {
                    flasher.play();
                } else {
                    flasher.stop();
                    row.pseudoClassStateChanged(flashHighlight, false);
                }
            };

            row.itemProperty().addListener((obs, oldItem, newItem) -> {
                if (oldItem != null) {
                    oldItem.cautionProperty().removeListener(cautionListener);
                }
                if (newItem == null) {
                    flasher.stop();
                    row.pseudoClassStateChanged(flashHighlight, false);
                } else {
                    newItem.cautionProperty().addListener(cautionListener);
                    if (newItem.cautionProperty().get()) {
                        flasher.play();
                    } else {
                        flasher.stop();
                        row.pseudoClassStateChanged(flashHighlight, false);
                    }
                }
            });
            return row ;
        }
    );

อัปเดต: รหัสสำหรับการกะพริบตารางมาจากที่นี่ ในขณะที่โค้ดสำหรับการไฮไลต์ตารางมาจากที่นี่ ฉันพยายามรวมทั้งสองเข้าด้วยกันโดยมีโครงสร้างเหมือนด้านบน

แต่ฉันได้รับข้อผิดพลาด ฉันไม่รู้ว่าจะรวมชนชั้นภายในที่ไม่เปิดเผยตัวตนและนิพจน์แลมบ์ดาเข้าด้วยกันได้อย่างไร

ฉันจะเอาชนะสิ่งนี้ได้อย่างไร?


person mynameisJEFF    schedule 24.08.2015    source แหล่งที่มา


คำตอบ (1)


วิธีที่ดีที่สุดในการทำเช่นนี้คือการสร้างคลาส TableRow แยกกัน แทนที่จะเป็นคลาสภายในที่ไม่ระบุชื่อ

ฉันสร้างตัวอย่างการใช้งานด้านล่าง

บางสิ่งที่ควรค่าแก่การกล่าวถึง:

  1. คุณต้องกำหนดสไตล์ .table-row-cell:new ในไฟล์ CSS ของคุณสำหรับ TableRow ที่เพิ่มเข้ามาใหม่
  2. คุณต้องกำหนดสไตล์ .table-row-cell:flash ในไฟล์ CSS ของคุณสำหรับ TableRow ที่กำลังกะพริบอยู่ในขณะนี้
  3. Constructor จำเป็นต้องทราบ (ObjectExpression) ว่ารายการที่เพิ่มล่าสุดถูกจัดเก็บไว้ที่ไหน ซึ่งอาจเป็น recentlyAddedTrade ในกรณีของคุณ
  4. ตัวสร้างจำเป็นต้องรู้ (Function<T, BooleanExpression>) วิธีแยกคุณสมบัติที่กำหนดสถานะการกะพริบ ในกรณีของคุณควรจะเป็น Trade::cautionProperty

นี่คือตัวอย่างการใช้งาน:

public static class AnimatedTableRow<T> extends TableRow<T> {

    private static final PseudoClass PS_NEW = PseudoClass.getPseudoClass("new");
    private static final PseudoClass PS_FLASH = PseudoClass.getPseudoClass("flash");

    private final ObjectExpression<T> recentItem;
    private final InvalidationListener recentlyAddedListener = fObs -> recentItemChanged();

    private final Function<T, BooleanExpression> flashExtractor;
    private final ChangeListener<Boolean> flashListener = (fObs, fOld, fNew) -> flasherChanged(fNew);
    private final Timeline flashTimeline;

    public AnimatedTableRow(ObjectExpression<T> fRecentlyAddedProperty,
            Function<T, BooleanExpression> fFlashExtractor) {
        recentItem = fRecentlyAddedProperty;
        recentItem.addListener(new WeakInvalidationListener(recentlyAddedListener));

        flashExtractor = fFlashExtractor;
        flashTimeline = new Timeline(
                new KeyFrame(Duration.seconds(0.5), e -> pseudoClassStateChanged(PS_FLASH, true)),
                new KeyFrame(Duration.seconds(1.0), e -> pseudoClassStateChanged(PS_FLASH, false)));
        flashTimeline.setCycleCount(Animation.INDEFINITE);
    }

    private void flasherChanged(boolean fNew) {
        if (fNew) {
            flashTimeline.play();
        } else {
            flashTimeline.stop();
            pseudoClassStateChanged(PS_FLASH, false);
        }
    }

    private void recentItemChanged() {
        final T tmpRecentItem = recentItem.get();
        pseudoClassStateChanged(PS_NEW, tmpRecentItem != null && tmpRecentItem == getItem());
    }

    @Override
    protected void updateItem(T item, boolean empty) {
        if (getItem() != null) {
            final BooleanExpression be = flashExtractor.apply(getItem());
            if (be != null) {
                be.removeListener(flashListener);
            }
        }

        super.updateItem(item, empty);

        if (getItem() != null) {
            final BooleanExpression be = flashExtractor.apply(getItem());
            if (be != null) {
                be.addListener(flashListener);
                flasherChanged(be.get());
            }
        }

        recentItemChanged();
    }
}

การใช้งาน:

table.setRowFactory(tableView -> new AnimatedTableRow<>(recentlyAddedPerson, Person::flashProperty));
person eckig    schedule 27.08.2015
comment
และฉันจะเรียกคลาสนี้ว่า setRowFactory() อย่างไร - person mynameisJEFF; 27.08.2015