0

In my programme I've a large array of strings(say 1600) which I want to show as a CheckBox list. The array is actually the location of all the songs in one's PC, and thus can gradually be bigger. I don't wanna use ListView<String> as the CheckBox list is more efficient and above all visually better for my purpose. I'm currently doing the below :

private void listAll() {
    songs = MediaManager.getAllSongs();
    VBox vb = new VBox();
    vb.setSpacing(5);
    vb.getStyleClass().add("background");
    if (songs != null) {
        Service s = new Service() {

            @Override
            protected Task createTask() {
                Task t = new Task() {
                    @Override
                    protected Object call() throws Exception {
                        for (String song : songs) {
                            addSong(song, vb);
                            c++;
                            updateMessage(c+" songs");
                        }
                        return null;
                    }
                };
                t.messageProperty().addListener((obs,o,n)->{
                    count.setText(n);
                });
                return t;
            }
        };
        s.start();
        ScrollPane sp = new ScrollPane(vb);
        getChildren().add(sp);
    }
}

private void addSong(String n, Pane p) {
    String toAdd = "";
    Media m = new Media(Paths.get(n).toUri().toString());
    if (m.getMetadata().get("title") == null || !(m.getMetadata().get("title").equals(""))) {
        toAdd = m.getSource().split("/")[m.getSource().split("/").length - 1].replace("%20", " ").replace(".mp3", "");
    } else {
        toAdd = ((String) m.getMetadata().get("title"));
    }
    SongBox s = new SongBox(toAdd);
    s.setUserData(n);
    p.getChildren().add(s);
}

class SongBox extends CheckBox {

    public SongBox(String t) {
        this();
        setText(t);
    }

    public SongBox() {
        super();

        setOnAction((ActionEvent evt) -> {
            if (isSelected()) {
                if (!playNow.isVisible()) {
                    playNow.setVisible(true);
                }
                path = (String) getUserData();
                selected.add((String) getUserData());
            } else {
                selected.remove((String) getUserData());
                if (selected.size() == 0) {
                    playNow.setVisible(false);
                }
            }
        });
    }
}

First of all, that is not showing the complete array. Whenever I'm going back and returning to it, the number of songs get changed. Secondly, the whole UI is getting sluggish(sometimes also hanging my PC). Moreover, I can't cancel the Service when I've gone to the previous window, as it's always returning false. Anyone have a better approach?

Subhranil
  • 851
  • 1
  • 8
  • 23
  • Why do you think a `ComboBox` is more efficient than a `ListView`? And as a user, I would not want a combo box here at all: you would have to scroll through a list in a popup, and would lose the position when the popup was hidden. A `ListView` is exactly the right way to display something like this. – James_D Jul 30 '15 at 17:35
  • Not "a" combobox, but a list of comboboxes actually as you can see wrapped up in a VBox. The main moto is flexible selection. The comboboxes are giving a much more clearer and smarter view of the selections to the user, as for the program both are the same. Can't the comboboxes be used in anyway? The ListView is also taking the same time. – Subhranil Jul 30 '15 at 18:01
  • I don't see any `ComboBox` in your code. – James_D Jul 30 '15 at 18:05
  • Extremely sorry. That would be CheckBox. Updated my question. And thanks a lot. – Subhranil Jul 30 '15 at 18:09
  • That makes more sense. I would still use a `ListView` though, because it is more efficient via virtualization. You can use a cell factory to customize the display (using a check box for selection even, if you like). However, you have far more fundamental problems with multithreading that you need to fix first. Read the [documentation for `Task`](http://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html) and maybe http://stackoverflow.com/questions/30249493/using-threads-to-make-database-requests – James_D Jul 30 '15 at 18:20
  • That's called an example must say. Nice one. But how to fulfill all those in this? Please help. – Subhranil Jul 30 '15 at 18:30
  • I guess this is just too broad a question and there is too much wrong with your code as it stands to fix it in a single question. You should break this up into pieces: use a `ListView` to display the files. Use a cell factory to display using check boxes (if that's what you really want). See if you can get all that working first. Then try to add a feature where you change the name to the metadata title in a background task (this is hard, I think), but obeying the threading rules of JavaFX. Post individual questions if you get stuck with those pieces. Just my opinion... – James_D Jul 30 '15 at 18:41
  • What's the most time consuming part in this? Adding to the Pane no? And I've tried to list out the check boxes separtely in a thread when they are done while the UI being usually displayed. But FX's single threading policy is the bar in that case. – Subhranil Jul 30 '15 at 19:10
  • You can't add to the pane in a background thread, for reasons outlined in the pages I linked. I would assume the performance issues you are experiencing are caused by creating 1600 `Media` objects... – James_D Jul 30 '15 at 20:05
  • I've managed the fluidity in another way. Instead of creating all the checkboxes every time, I've add a method to MediaManager to store the static instance of the whole checkbox array and whenever a new song is added, a checkbox is created. In that way, when i wanna display all the songs, I'm just fetching those from MediaManager and showing them in that Pane. That's really a good tweak as no visible delay is occuring and according to the rules outlined by you, the whole work is separated from the GUI. Thanks a lot. – Subhranil Jul 31 '15 at 22:43

0 Answers0