JavaFX ListView MultipleSelection

  • Themenstarter Themenstarter hk
  • Beginndatum Beginndatum

hk

Bekanntes Mitglied
Hallo Forum,
ich möchte von einer ListView die selektierten Elemente abrufen, bekomme aber immer nur das zuletzt selektierte Element zurück. Was mache ich falsch?
Code:
import java.io.IOException;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;

public class PrimaryController {
 
  @FXML ListView fx_lvSelect;
  static ObservableList<String> items;
    
  @FXML private void lvSelected() {
    // In dieser Liste sollten alle selektierten Elemente aufscheinen
    // es ist jedoch immer nur die letzte Selektion in der Liste
    ObservableList<Integer> index =
            fx_lvSelect.getSelectionModel().getSelectedIndices();
    int a = 0;
  }
 
  @FXML public void initialize() {
    fx_lvSelect.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
    items =FXCollections.observableArrayList (
    "Single", "Double", "Suite", "Family App");
    fx_lvSelect.setItems(items);
    fx_lvSelect.getSelectionModel().select(0);
    fx_lvSelect.getSelectionModel().select(1);
  } 
}
 
ich möchte von einer ListView die selektierten Elemente abrufen, bekomme aber immer nur das zuletzt selektierte Element zurück. Was mache ich falsch?
Wie rufst Du es denn auf?

Denn das machst Du ja soweit alles richtig - wenn Du das so startest, dann sind die ersten beiden Elemente selektiert. Mit dem getSelectedIndices bekommst Du auch die Indices. Also die Methode einfach einmal etwas umgeschrieben:
Java:
    @FXML private void lvSelected() {
        // In dieser Liste sollten alle selektierten Elemente aufscheinen
        // es ist jedoch immer nur die letzte Selektion in der Liste
        ObservableList<Integer> index =
                fx_lvSelect.getSelectionModel().getSelectedIndices();
        index.forEach(System.out::println);
    }

dann funktioniert das auch. Ich habe es einfach einen Knopf zugewiesen und habe direkt die zugewiesenen Indices ausgegeben bekommen (0 und 1). Bei einer Veränderung habe ich dann auch die angepasste Auswahl komplett bekommen.

Daher ist es wirklich wichtig, dass Du uns genau zeigst, was Du da überhaupt machst. Denn Deine Methode macht ja nichts - Du holst Dir die Observable list und setzt eine lokale Variable a auf 0 und das ist alles, was Du uns da zeigst.
 
Wie rufst Du es denn auf?

Denn das machst Du ja soweit alles richtig - wenn Du das so startest, dann sind die ersten beiden Elemente selektiert. Mit dem getSelectedIndices bekommst Du auch die Indices. Also die Methode einfach einmal etwas umgeschrieben:
Java:
    @FXML private void lvSelected() {
        // In dieser Liste sollten alle selektierten Elemente aufscheinen
        // es ist jedoch immer nur die letzte Selektion in der Liste
        ObservableList<Integer> index =
                fx_lvSelect.getSelectionModel().getSelectedIndices();
        index.forEach(System.out::println);
    }

dann funktioniert das auch. Ich habe es einfach einen Knopf zugewiesen und habe direkt die zugewiesenen Indices ausgegeben bekommen (0 und 1). Bei einer Veränderung habe ich dann auch die angepasste Auswahl komplett bekommen.

Daher ist es wirklich wichtig, dass Du uns genau zeigst, was Du da überhaupt machst. Denn Deine Methode macht ja nichts - Du holst Dir die Observable list und setzt eine lokale Variable a auf 0 und das ist alles, was Du uns da zeigst.
Ich mache nichts mehr. Ich will das Abfragen von mehreren selektierten Elementen nur testen. Aber auch mit der Printfunktion wird nur das zuletzt selektierte angezeigt.
 
Wie rufst Du es denn auf?

Denn das machst Du ja soweit alles richtig - wenn Du das so startest, dann sind die ersten beiden Elemente selektiert. Mit dem getSelectedIndices bekommst Du auch die Indices. Also die Methode einfach einmal etwas umgeschrieben:
Java:
    @FXML private void lvSelected() {
        // In dieser Liste sollten alle selektierten Elemente aufscheinen
        // es ist jedoch immer nur die letzte Selektion in der Liste
        ObservableList<Integer> index =
                fx_lvSelect.getSelectionModel().getSelectedIndices();
        index.forEach(System.out::println);
    }

dann funktioniert das auch. Ich habe es einfach einen Knopf zugewiesen und habe direkt die zugewiesenen Indices ausgegeben bekommen (0 und 1). Bei einer Veränderung habe ich dann auch die angepasste Auswahl komplett bekommen.

Daher ist es wirklich wichtig, dass Du uns genau zeigst, was Du da überhaupt machst. Denn Deine Methode macht ja nichts - Du holst Dir die Observable list und setzt eine lokale Variable a auf 0 und das ist alles, was Du uns da zeigst.
Wenn ich die Abfrage in den "initialize" Funktion verlege funktioniert es. Aber wenn ich per Maus selektiere bekomme ich nur die zuletzt selektierte.
 
Zeige den konkreten Code! Was genau machst Du?

Der Code, den ich gezeigt habe, gibt eben genau alle selektierten Indices aus. Ich habe es hier getestet. Zeige die fxml Datei, zeige den Controller, mit dem Du es testest. Dein gezeigter Code gibt ja eben gar nichts aus, nicht einmal das letzte selektierte Element.
 
Zeige den konkreten Code! Was genau machst Du?

Der Code, den ich gezeigt habe, gibt eben genau alle selektierten Indices aus. Ich habe es hier getestet. Zeige die fxml Datei, zeige den Controller, mit dem Du es testest. Dein gezeigter Code gibt ja eben gar nichts aus, nicht einmal das letzte selektierte Element.
Ok,
Controller:
Java:
package com.hk.mybackup;

import java.io.IOException;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;

public class PrimaryController {
 
  @FXML ListView fx_lvSelect;
  static ObservableList<String> items;
 
  @FXML private void lvSelected() {
    // In dieser Liste sollten alle selektierten Elemente aufscheinen
    // es ist jedoch immer nur die letzte Selektion in der Liste
    ObservableList<Integer> index =
            fx_lvSelect.getSelectionModel().getSelectedIndices();
    index.forEach(System.out::println);
    int a = 0;
  }
 
  @FXML public void initialize() {
    fx_lvSelect.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
    items =FXCollections.observableArrayList (
    "Single", "Double", "Suite", "Family App");
    fx_lvSelect.setItems(items);
    fx_lvSelect.getSelectionModel().select(0);
    fx_lvSelect.getSelectionModel().select(1);
        ObservableList<Integer> index =
            fx_lvSelect.getSelectionModel().getSelectedIndices();
    index.forEach(System.out::println);
  } 
}
FXML:
Code:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>

<Pane prefHeight="425.0" prefWidth="569.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.hk.mybackup.PrimaryController">
   <children>
      <Button fx:id="primaryButton" layoutX="14.0" layoutY="45.0" onAction="#switchToSecondary" text="zur Wiederherstellen" />
      <Label layoutX="10.0" layoutY="10.0" text="Datensicherung">
         <font>
            <Font name="System Bold" size="22.0" />
         </font>
      </Label>
      <ListView fx:id="fx_lvSelect" layoutX="53.0" layoutY="92.0" onMousePressed="#lvSelected" prefHeight="200.0" prefWidth="200.0" />
   </children>
</Pane>
 
Ok, und wie testest Du es dann? das lvSelected wird ja jetzt aufgerufen, wenn Du mit der Maus in der ListView clickst.

Drückst Du evtl. nur die Maus? Dabei wird ja die Selektion aufgehoben und nur das angeklickte Elemente ausgewählt. Das wäre dann das, was Du beschreibst: Das zuletzt ausgewählte Element wird angezeigt (weil das ja so auch das einzig angeklickte Element ist).

Wenn Du die Strg Taste gedrück hältst, dann würdest Du die Auswahl verändern und Du bekommst auch die Auswahl angezeigt.
Oder mit der Shift Taste - da wird dann ein Bereich ausgewählt.

Bei Tests fällt aber auf, dass es nicht immer richtig funktioniert, wenn mehrere Elemente deselektiert werden. Hintergrund dürfte sein, dass auf dieses onClick Event mehrere Dinge ablaufen. Daher kommt die Ausgabe schneller als die Änderung selbst. (Halt ein Click von Anwender und im Rahmen der Verarbeitung laufen mehrere Dinge ab.)

Hier ist also die Frage, was Du auch genau erreichen willst. Mit den Clicks selbst machst Du ja nichts - die Logik mit dem selektieren willst Du ja nicht verändern. Da würde ich also gar nicht drauf reagieren.

Statt an den Clicks bist Du doch an den Veränderungen interessiert. Also willst Du immer dann etwas machen, wenn Du die Selektion verändert wird. Also etwas in der Art:

Java:
    ObservableList<Integer> index;  // Instanzvariable

    public void printAll() {
        System.out.println(index);
    }

    @FXML public void initialize() {
        fx_lvSelect.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        items = FXCollections.observableArrayList (
                "Single", "Double", "Suite", "Family App");
        fx_lvSelect.setItems(items);
        fx_lvSelect.getSelectionModel().select(0);
        fx_lvSelect.getSelectionModel().select(1);
        index =
                fx_lvSelect.getSelectionModel().getSelectedIndices();
        index.addListener((ListChangeListener) c -> printAll()); // Gibt zwei addListener - daher die Angabe, dass es um den ListChangeListener geht!
    }

Immer dann, wenn die Selektion angepasst wurde, wird das printAll aufgerufen.

Aber das ist nicht zwingend notwendig. Wenn Du das lvSelected z.B. bei einem Button machen würdest, dann wäre es auch alles ok, da ja erst die User Aktionen in der ListView abgearbeitet würden und der Klick auf den Button nach der Verarbeitung des ersten Events kommt.
 
Ok, und wie testest Du es dann? das lvSelected wird ja jetzt aufgerufen, wenn Du mit der Maus in der ListView clickst.

Drückst Du evtl. nur die Maus? Dabei wird ja die Selektion aufgehoben und nur das angeklickte Elemente ausgewählt. Das wäre dann das, was Du beschreibst: Das zuletzt ausgewählte Element wird angezeigt (weil das ja so auch das einzig angeklickte Element ist).

Wenn Du die Strg Taste gedrück hältst, dann würdest Du die Auswahl verändern und Du bekommst auch die Auswahl angezeigt.
Oder mit der Shift Taste - da wird dann ein Bereich ausgewählt.

Bei Tests fällt aber auf, dass es nicht immer richtig funktioniert, wenn mehrere Elemente deselektiert werden. Hintergrund dürfte sein, dass auf dieses onClick Event mehrere Dinge ablaufen. Daher kommt die Ausgabe schneller als die Änderung selbst. (Halt ein Click von Anwender und im Rahmen der Verarbeitung laufen mehrere Dinge ab.)

Hier ist also die Frage, was Du auch genau erreichen willst. Mit den Clicks selbst machst Du ja nichts - die Logik mit dem selektieren willst Du ja nicht verändern. Da würde ich also gar nicht drauf reagieren.

Statt an den Clicks bist Du doch an den Veränderungen interessiert. Also willst Du immer dann etwas machen, wenn Du die Selektion verändert wird. Also etwas in der Art:

Java:
    ObservableList<Integer> index;  // Instanzvariable

    public void printAll() {
        System.out.println(index);
    }

    @FXML public void initialize() {
        fx_lvSelect.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        items = FXCollections.observableArrayList (
                "Single", "Double", "Suite", "Family App");
        fx_lvSelect.setItems(items);
        fx_lvSelect.getSelectionModel().select(0);
        fx_lvSelect.getSelectionModel().select(1);
        index =
                fx_lvSelect.getSelectionModel().getSelectedIndices();
        index.addListener((ListChangeListener) c -> printAll()); // Gibt zwei addListener - daher die Angabe, dass es um den ListChangeListener geht!
    }

Immer dann, wenn die Selektion angepasst wurde, wird das printAll aufgerufen.

Aber das ist nicht zwingend notwendig. Wenn Du das lvSelected z.B. bei einem Button machen würdest, dann wäre es auch alles ok, da ja erst die User Aktionen in der ListView abgearbeitet würden und der Klick auf den Button nach der Verarbeitung des ersten Events kommt.
Gut, das mit der Strg-Taste funktioniert. So brauche ich aber das Mehrfachselektieren nicht.
Was ich eigentlich will ist eine Liste aus der ich mehrere Elemente aktivieren, deaktivieren kann ohne die nicht betroffenen zu verändern. Etwa so:
Screenshot 2023-01-06 170904.png
 
Ich verstehe jetzt gerade nicht, was Du meinst. Wenn Du die ListView irgendwie anders nutzt / bedienst, dann ist das ja auch ok. Du musst die AUswertung der selektierten Elemente halt an einer sinnvollen Stelle mache. Das onClick Event ist dazu eben nicht geeignet.

Generell kannst Du es so aufbauen, wie Du willst. Wenn Du eine Liste mit Checkboxen haben willst, dann kannst Du Dir auch sowas bauen. Da wird vermutlich einfach ein CheckBoxListCell ausreichen. Aber man kann da auch z.B. zu https://controlsfx.github.io/ greifen mit der CheckListView.
 
Ich verstehe jetzt gerade nicht, was Du meinst. Wenn Du die ListView irgendwie anders nutzt / bedienst, dann ist das ja auch ok. Du musst die AUswertung der selektierten Elemente halt an einer sinnvollen Stelle mache. Das onClick Event ist dazu eben nicht geeignet.

Generell kannst Du es so aufbauen, wie Du willst. Wenn Du eine Liste mit Checkboxen haben willst, dann kannst Du Dir auch sowas bauen. Da wird vermutlich einfach ein CheckBoxListCell ausreichen. Aber man kann da auch z.B. zu https://controlsfx.github.io/ greifen mit der CheckListView.
Danke, das werde ich mir ansehen!
 

Zurück
Oben