【问题标题】:Issue with selecting items in ListView - JavaFX在 ListView 中选择项目的问题 - JavaFX
【发布时间】:2016-03-17 20:23:17
【问题描述】:

我写了如下方法,用来当我按下按钮时做出反应:

private void handlePlayButton(ActionEvent e){
    for (int i = 0; i < commands.size(); i++) {
        list.getSelectionModel().select(i);

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ie){
            System.out.println("Error at handlPlayButton: interruption");
        }

    }

}

在这段代码中,我尝试从第一行开始选择每个元素,然后等待 1 秒来选择下一个元素,但它似乎等待 n-1 秒(其中 n 是项目的大小),然后选择最后一项。有没有办法解决这个问题?

顺便说一下,list 字段是 ListView&lt;String&gt;

【问题讨论】:

  • 也许您正在尝试实现与 Timeline to Display Random images one by one 类似模式的逻辑,但也许不是,我很难理解您在这里真正想要完成的事情。永远不要在 JavaFX 应用程序线程上调用 sleep(它只会挂起你的 UI)。
  • 好吧,我有一个 ListView,假设其中有 4 个元素(所以 4 行),我有一个按钮。当我按下按钮时,它必须选择第一个元素,等待 1 秒,然后选择第二个元素,等待 1 秒,等等。但在我的情况下,它等待 3 秒,然后选择最后一个元素而不选择之前的元素之一.所以我想解决这个问题。
  • 好的,我想我明白你现在想要做什么,但我不知道你为什么想做这样的事情(看起来很奇怪)。此外,如果用户再次按下按钮或在 ListView 中选择另一个项目,而自动循环逻辑正在进行中,会发生什么情况?当到达列表末尾时会发生什么,自动化过程是停止,还是再次循环到第一个项目然后继续?
  • 嗯非常好的问题:重新按下按钮只会结束当前循环并重新启动它。如果用户在循环期间选择了一个项目,它将停止循环并选择用户选择的项目(显然)。当过程结束时,它只选择最后一个项目,就是这样。这个问题确实看起来很奇怪,但列表中的每个元素都与 GUI 的不同部分连接,它会根据列表值输出内容,但您不必担心

标签: java listview javafx


【解决方案1】:

这个问题比较晦涩难懂,所以我认为该解决方案不会普遍适用于其他任何人。基本解决方案是当用户在 UI 中按下“循环”按钮时,使用时间轴自动更新 ListView 中的选择。

还有一些额外的逻辑来处理边缘情况,例如如果用户在循环进行时修改了选择,或者如果用户重新启动循环过程,该怎么办。如果用户点击当前选择的项目,自动循环不会停止,所以如果他采用类似的解决方案,原始提问者可能希望添加一些他自己的代码来做到这一点。

还有一些将 ImageViews 放置在 ListView 中的逻辑,但这不是应用程序的核心,对于存储在 ListView 中使用的更常见的类型(例如字符串)可以忽略。 ImageView 相关的东西只是为了让应用看起来更好一点。

import javafx.animation.*;
import javafx.application.Application;
import javafx.collections.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.util.Arrays;
import java.util.stream.Collectors;

public class RotatingSushiMenu extends Application {

    private static final Duration AUTO_CHANGE_PAUSE = Duration.seconds(2);

    private boolean autoChange;

    @Override
    public void start(Stage stage) {
        ObservableList<Image> images = FXCollections.observableList(
                Arrays.stream(IMAGE_LOCS)
                        .map(Image::new)
                        .collect(Collectors.toList())
        );

        ListView<Image> list = new ListView<>(FXCollections.observableList(images));
        list.setCellFactory(param -> new ImageListCell());

        Timeline timeline = new Timeline(
                new KeyFrame(Duration.ZERO),
                new KeyFrame(
                        AUTO_CHANGE_PAUSE,
                        e -> {
                            int curIdx = list.getSelectionModel().getSelectedIndex();
                            if (curIdx < list.getItems().size() - 1) {
                                autoChange = true;
                                list.scrollTo(curIdx + 1);
                                list.getSelectionModel().select(curIdx + 1);
                                autoChange = false;
                            }
                        }
                )
        );
        timeline.setCycleCount(list.getItems().size());

        Button cycle = new Button("Cycle");
        cycle.setOnAction(event -> {
            if (list.getItems().size() > 0) {
                list.scrollTo(0);
                list.getSelectionModel().select(0);
                timeline.playFromStart();
            }
        });

        list.getSelectionModel().getSelectedItems().addListener((ListChangeListener<Image>) c -> {
            if (!autoChange) {
                timeline.stop();
            }
        });

        VBox layout = new VBox(10, cycle, list);
        layout.setPadding(new Insets(10));
        stage.setScene(new Scene(layout));
        stage.show();
    }

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

    private class ImageListCell extends ListCell<Image> {
        final ImageView imageView = new ImageView();

        ImageListCell() {
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }

        @Override
        protected void updateItem(Image item, boolean empty) {
            super.updateItem(item, empty);

            if (empty || item == null) {
                imageView.setImage(null);
                setText(null);
                setGraphic(null);
            }

            imageView.setImage(item);
            setGraphic(imageView);
        }
    }

    // image license: linkware - backlink to http://www.fasticon.com
    private static final String[] IMAGE_LOCS = {
            "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Blue-Fish-icon.png",
            "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Red-Fish-icon.png",
            "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Yellow-Fish-icon.png",
            "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Green-Fish-icon.png"
    };
}

【讨论】:

  • 您有什么理由使用由ObservableList 支持的ObservableList 支持的List(特别是因为支持列表从未在其他任何地方使用过)?我个人会使用FXCollections.observableArrayList(Arrays.stream(IMAGE_LOCS).map(Image::new).toArray(Image[]::new))Arrays.stream(IMAGE_LOCS).map(Image::new).collect(Collectors.toCollection(FXCollections::observableArrayList)
  • 选择特定数据结构链的原因是我想到的第一个。我没有想太多。我意识到这不是解决问题的最有效的数据结构选择。鉴于样本中只有四个项目,这对样本数据无关紧要,只会对非常大的数据集产生影响,从问题的性质来看,这将是出乎意料的。随意编辑答案中的示例代码以使用可提供更高效率或清晰度的替代数据结构。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-26
  • 1970-01-01
  • 2011-01-18
  • 2018-09-29
相关资源
最近更新 更多