JavaFX aktuelle Tabellenzeile bei Choice-Box-Auswahl in Zelle ermitteln

Diskutiere aktuelle Tabellenzeile bei Choice-Box-Auswahl in Zelle ermitteln im AWT, Swing, JavaFX & SWT Bereich.
P

Padde85

Hallo zusammen,

die Titelzeile klingt vielleicht etwas kryptisch, daher hier noch Mal erläutert :)

Ich habe eine editierbare TableView mit 3 Spalten. In diesen drei Spalten existieren zwei String-Propertys und eine Choice-Box.
Ich bekomme auch alles angezeigt und bekomme auch die Werte der Choice-Box. So weit so gut. Jetzt wird es aber interessant.

Wenn ich nun z.B. 5 Zeilen habe und der Anwender wählt in der 3. Zeile in der Choice-Box einen Eintrag aus, möchte ich darauf reagieren (onAction-Event der Choice-Box) und in der Zeile, wo die Choice-Box enthalten ist, einen Wert in Spalte 2 oder 3 abfragen bzw. eintragen.

Jetzt stellt sich mir die spannende Frage, wie ich denn raus finden kann, in welcher Tabellenzeile das Ereignis ausgelöst wurde...?
Bei einer Checkbox wird das Edit-Event verwendet, was wiederum über event.getTablePosition.getRow.get die Möglichkeit bietet, auf das Datenobjekt der x-ten Zeile zuzugreifen.
Blöderweise kennt das ActionEvent diese Vorgehensweise nicht. Und die ChoiceBox wird ja auch nicht editiert, daher bringt mir das Edit-Event hier nichts. Oder doch...?

Eine ganze dirty Möglichkeit wäre natürlich, im Objekt der ChoiceBox vom Typ xyz einen weiteren Parameter mitzugeben und dort die Zeilennummer zu speichern. Das halte ich allerdings für sehr unsauber und bin mir relativ sicher, dass es da einen eleganteren Weg geben muss.

Zur Veranschaulichung hier ein Screen-Shot was ich meine:
screen.png

Der Anwender hat nun in diesem Fall die erste Zeile "geändert", indem anstatt "Kopfzeile" der Eintrag "Hauptbereich" ausgewählt wurde. Jetzt möchte ich wissen, in welcher Zeile das war, um hinten die Checkbox abzuprüfen, da eine Kombination Kopfbereich und markierte Checkbox nicht zulässig sein soll.

Ich hoffe, ich habe mich verständlich ausgedrückt :)

Danke für eure Hilfe
 
P

Padde85

Spalte 2 ist uninteressant für die Betrachtung, aber wenn jemand Kopfbereich auswählt und der Haken hinten gesetzt ist, soll der Haken wieder automatisch entfernt und der Anwender darauf aufmerksam gemacht werden.

Aber ich schaue Mir deinen Link Mal an. Danke für die Info :)
 
L

lam_tr

Spalte 2 ist uninteressant für die Betrachtung, aber wenn jemand Kopfbereich auswählt und der Haken hinten gesetzt ist, soll der Haken wieder automatisch entfernt und der Anwender darauf aufmerksam gemacht werden.

Aber ich schaue Mir deinen Link Mal an. Danke für die Info :)
Ja das sollte über den CellFactory Problem losgehen. Wahrscheinlich muss du nachdem der Wert ausgelesen wird noch im CellFactory die TableView refreshed werden.
 
P

Padde85

Also ich habe mir das Mal angeschaut und verstehe nicht, wie das funktionieren soll.
In der CellFactory habe ich auch wieder nur das Datenobjekt der aktuellen Zelle im Zugriff. Das hilft mir ja an der Stelle wieder nicht weiter...
 
L

lam_tr

Da ich keinen Code von dir vor mir habe, passe ich das hier ein bisschen an
Code:
positionColumn.setCellFactory(column -> {
    return new TableCell<MeineRow , MeineRow>() {
        @Override
        protected void updateItem(MeineRow item, boolean empty) {
            super.updateItem(item, empty);

            if (item == null || empty) {
                setText(null);
                setGraphic("");
            } else {
                ChoiceBox cb = new ChoiceBox();
                cb.setItems(FXCollections.observableArrayList("Kopfzeile", "Fusszeile", "Header"));
                cb.getSelectionModel().setSelection(item.getPosition());
                cb.setOnAction(e->{
                   System.out.println(item.isTabellarisch());
                   System.out.println(item.isTabellarisch());
                });
                setGraphic(cb);
            }
        }
    };
});
Der Code ist ungetestet, aber ich denke ungefähr so könnte bei dir aussehen.
 
P

Padde85

danke für das Beispiel. Eclipse ist aber der Meinung, dass ich das so nicht darf :(

Hier mal die relevanten Coding-Strecken:

Aufbau der TableView:
Java:
 // TableView erzeugen
    public void initTableView() {
    EventHandler<TableColumn.CellEditEvent<VarUsageTypeDef, String>> handler = new EventHandler<TableColumn.CellEditEvent<VarUsageTypeDef,String>>() {
        @Override
        public void handle(CellEditEvent<VarUsageTypeDef, String> event) {
        controller.onTextInputCommit(event);
        }
    };
    
    controller.tcPosition.setCellValueFactory(new PropertyValueFactory<VarUsageTypeDef, ChoiceBox<PositionDefinition>>("cbPosition"));
    controller.tcPosition.setCellFactory(column -> {
       return new TableCell<VarUsageTypeDef, ChoiceBox<PositionDefinition>>() {

        @Override
        protected void updateItem(ChoiceBox<PositionDefinition> item, boolean empty) {
        // TODO Auto-generated method stub
        super.updateItem(item, empty);
        }
          
       };
    });
    controller.tcDescription.setCellValueFactory(new PropertyValueFactory<VarUsageTypeDef, String>("description"));
    controller.tcDescription.setCellFactory(TextFieldTableCell.forTableColumn());
    controller.tcDescription.setOnEditCommit(handler);
    controller.tcTableType.setCellValueFactory(new PropertyValueFactory<VarUsageTypeDef, CheckBox>("ckbTable"));

    controller.tvTypeDef.setItems(controller.getSettingsList());
    }
    
    // Choice-Box für Positionierungen erzeugen
    public ChoiceBox<PositionDefinition> getTableChoiceBox() {
    ChoiceBox<PositionDefinition> cBox = new ChoiceBox<PositionDefinition>();
    cBox.setMinWidth(controller.tcPosition.getWidth());
    cBox.setMaxWidth(controller.tcPosition.getWidth());
    cBox.setConverter(new StringConverter<PositionDefinition>() {
        @Override
        public String toString(PositionDefinition object) {
        return object.toString();
        }
        
        @Override
        public PositionDefinition fromString(String string) {
        return null; // Box ist nicht editierbar, daher keine Konvertierung in Object nötig
        }
    });
    return cBox;
    }
Die Klasse der Choice-Box:
Java:
/*
 * Container-Klasse für die Definition der Positionierung im Dokument (Kopf, Body, Fußzeile)
 */
public class PositionDefinition {
    private char usage;
    private String description;
    
    public PositionDefinition(char usage, String description) {
    this.description = description;
    this.usage = usage;
    }

    public int getUsage() {
    return this.usage;
    }

    public void setUsage(char usage) {
    this.usage = usage;
    }
    
    public String toString() {
    return this.description;
    }
}
Und die Klasse für die allgemeine Zeilenstruktur:
Java:
import java.util.ArrayList;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;

/*
 * Container-Klasse für die Verwendungsart-Definition
 */
public class VarUsageTypeDef {
    private int id;
    private boolean isChanged;
    private SimpleObjectProperty<ChoiceBox<PositionDefinition>> cbPosition;
    private SimpleStringProperty description;
    private SimpleObjectProperty<CheckBox> ckbTable;
    
    // Konstruktor, um Datenpaket aufzubauen mit übergebenen Daten
    public VarUsageTypeDef(int id, String description, char usage, ArrayList<PositionDefinition> posList, boolean table, ChoiceBox<PositionDefinition> box) {
    int index = 0;
    int id_selected = -1;
    
    this.setId(id);
    this.description = new SimpleStringProperty();
    setDescription(description);
    
    this.cbPosition = new SimpleObjectProperty<ChoiceBox<PositionDefinition>>();
    ObservableList<PositionDefinition> olist = null;
    for (PositionDefinition item : posList) {
        if (olist == null)
        olist = FXCollections.observableArrayList(item);
        else
        olist.add(item);
        
        if (item.getUsage() == usage)
        id_selected = index;
        index++;
    }
    
    box.setItems(olist);
    if(id_selected >= 0)
        box.getSelectionModel().select(id_selected);
    setCbPosition(box);
    
    // Checkbox erzeugen
    this.ckbTable = new SimpleObjectProperty<CheckBox>();
    CheckBox checkBox = new CheckBox();
    checkBox.setSelected(table);
    setCkbTable(checkBox);
    }

    public int getId() {
    return id;
    }

    public void setId(int id) {
    this.id = id;
    }

    public ChoiceBox<PositionDefinition> getCbPosition() {
    return this.cbPosition.get();
    }

    public void setCbPosition(ChoiceBox<PositionDefinition> cbPosition) {
    this.cbPosition.set(cbPosition);
    }

    public String getDescription() {
    return this.description.get();
    }

    public void setDescription(String description) {
    this.description.set(description);
    }

    public CheckBox getCkbTable() {
    return this.ckbTable.get();
    }

    public void setCkbTable(CheckBox ckbTable) {
    this.ckbTable.set(ckbTable);
    }
    
    public boolean getIsChanged() {
    return this.isChanged;
    }
    
    public void setIsChanged() {
    this.isChanged = true;
    }
}
Ggf. liegt auch schon im allgemeinen Vorgehen der Fehler begraben...
 
L

lam_tr

danke für das Beispiel. Eclipse ist aber der Meinung, dass ich das so nicht darf :(

Hier mal die relevanten Coding-Strecken:

Aufbau der TableView:
Java:
 // TableView erzeugen
    public void initTableView() {
    EventHandler<TableColumn.CellEditEvent<VarUsageTypeDef, String>> handler = new EventHandler<TableColumn.CellEditEvent<VarUsageTypeDef,String>>() {
        @Override
        public void handle(CellEditEvent<VarUsageTypeDef, String> event) {
        controller.onTextInputCommit(event);
        }
    };
   
    controller.tcPosition.setCellValueFactory(new PropertyValueFactory<VarUsageTypeDef, ChoiceBox<PositionDefinition>>("cbPosition"));
    controller.tcPosition.setCellFactory(column -> {
       return new TableCell<VarUsageTypeDef, ChoiceBox<PositionDefinition>>() {

        @Override
        protected void updateItem(ChoiceBox<PositionDefinition> item, boolean empty) {
        // TODO Auto-generated method stub
        super.updateItem(item, empty);
        }
         
       };
    });
    controller.tcDescription.setCellValueFactory(new PropertyValueFactory<VarUsageTypeDef, String>("description"));
    controller.tcDescription.setCellFactory(TextFieldTableCell.forTableColumn());
    controller.tcDescription.setOnEditCommit(handler);
    controller.tcTableType.setCellValueFactory(new PropertyValueFactory<VarUsageTypeDef, CheckBox>("ckbTable"));

    controller.tvTypeDef.setItems(controller.getSettingsList());
    }
   
    // Choice-Box für Positionierungen erzeugen
    public ChoiceBox<PositionDefinition> getTableChoiceBox() {
    ChoiceBox<PositionDefinition> cBox = new ChoiceBox<PositionDefinition>();
    cBox.setMinWidth(controller.tcPosition.getWidth());
    cBox.setMaxWidth(controller.tcPosition.getWidth());
    cBox.setConverter(new StringConverter<PositionDefinition>() {
        @Override
        public String toString(PositionDefinition object) {
        return object.toString();
        }
       
        @Override
        public PositionDefinition fromString(String string) {
        return null; // Box ist nicht editierbar, daher keine Konvertierung in Object nötig
        }
    });
    return cBox;
    }
Die Klasse der Choice-Box:
Java:
/*
* Container-Klasse für die Definition der Positionierung im Dokument (Kopf, Body, Fußzeile)
*/
public class PositionDefinition {
    private char usage;
    private String description;
   
    public PositionDefinition(char usage, String description) {
    this.description = description;
    this.usage = usage;
    }

    public int getUsage() {
    return this.usage;
    }

    public void setUsage(char usage) {
    this.usage = usage;
    }
   
    public String toString() {
    return this.description;
    }
}
Und die Klasse für die allgemeine Zeilenstruktur:
Java:
import java.util.ArrayList;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;

/*
* Container-Klasse für die Verwendungsart-Definition
*/
public class VarUsageTypeDef {
    private int id;
    private boolean isChanged;
    private SimpleObjectProperty<ChoiceBox<PositionDefinition>> cbPosition;
    private SimpleStringProperty description;
    private SimpleObjectProperty<CheckBox> ckbTable;
   
    // Konstruktor, um Datenpaket aufzubauen mit übergebenen Daten
    public VarUsageTypeDef(int id, String description, char usage, ArrayList<PositionDefinition> posList, boolean table, ChoiceBox<PositionDefinition> box) {
    int index = 0;
    int id_selected = -1;
   
    this.setId(id);
    this.description = new SimpleStringProperty();
    setDescription(description);
   
    this.cbPosition = new SimpleObjectProperty<ChoiceBox<PositionDefinition>>();
    ObservableList<PositionDefinition> olist = null;
    for (PositionDefinition item : posList) {
        if (olist == null)
        olist = FXCollections.observableArrayList(item);
        else
        olist.add(item);
       
        if (item.getUsage() == usage)
        id_selected = index;
        index++;
    }
   
    box.setItems(olist);
    if(id_selected >= 0)
        box.getSelectionModel().select(id_selected);
    setCbPosition(box);
   
    // Checkbox erzeugen
    this.ckbTable = new SimpleObjectProperty<CheckBox>();
    CheckBox checkBox = new CheckBox();
    checkBox.setSelected(table);
    setCkbTable(checkBox);
    }

    public int getId() {
    return id;
    }

    public void setId(int id) {
    this.id = id;
    }

    public ChoiceBox<PositionDefinition> getCbPosition() {
    return this.cbPosition.get();
    }

    public void setCbPosition(ChoiceBox<PositionDefinition> cbPosition) {
    this.cbPosition.set(cbPosition);
    }

    public String getDescription() {
    return this.description.get();
    }

    public void setDescription(String description) {
    this.description.set(description);
    }

    public CheckBox getCkbTable() {
    return this.ckbTable.get();
    }

    public void setCkbTable(CheckBox ckbTable) {
    this.ckbTable.set(ckbTable);
    }
   
    public boolean getIsChanged() {
    return this.isChanged;
    }
   
    public void setIsChanged() {
    this.isChanged = true;
    }
}
Ggf. liegt auch schon im allgemeinen Vorgehen der Fehler begraben...
Kannst du mir auch sagen an welcher Stelle Eclipse meckert?

An sich muss du mein Beispiel überall wo MeineRow steht mit deiner Datenklasse ersetzen.
 
P

Padde85

Eclipse meckert an der Stelle, wo das updateItem ist, weil er zwingend den Datentyp ChoiceBox erwartet und nicht den Datentyp der kompletten Zeile.
 
L

lam_tr

Achso das ist klar, du kannst die PropertyValueFactory so definiert, der erwartet eine ChoiceBox.

Code:
controller.tcPosition.setCellValueFactory(new PropertyValueFactory<VarUsageTypeDef, ChoiceBox<PositionDefinition>>("cbPosition"));
Du muss daraus das hier machen

Code:
controller.tcPosition.setCellValueFactory(new PropertyValueFactory<VarUsageTypeDef, PositionDefinition>("cbPosition"));
Soweit ich weiß gibt das zweite Argument den Datentyp von dem Feld den du holen willst.
 
P

Padde85

Also nach einigem Hin und Her-Probieren geht das auch nicht. Der meckert dann rum, dass er die ChoiceBox nicht in den Typ der Zeile konvertieren kann und schmiert ab.
Eine ChoiceBox lässt der einen nur dann einfügen, wenn auch der Typ der Zelle eine ChoiceBox erwartet.

Also baue ich eine Cross-Referenz der Zeile in die Choice-Box ein. Nicht schön, aber funktioniert scheinbar nicht anders...
 
Zuletzt bearbeitet:
L

lam_tr

Also nach einigem Hin und Her-Probieren geht das auch nicht. Der meckert dann rum, dass er die ChoiceBox nicht in den Typ der Zeile konvertieren kann und schmiert ab.
Eine ChoiceBox lässt der einen nur dann einfügen, wenn auch der Typ der Zelle eine ChoiceBox erwartet.

Also baue ich eine Cross-Referenz der Zeile in die Choice-Box ein. Nicht schön, aber funktioniert scheinbar nicht anders...
Okay ich habe noch einen Punkt gesehen, du hast in deiner Datenklassen die cbPosition mit ChoiceBox deklariert, das muss natürlich auch raus und nur PositionDefinition defininiert werden.

private SimpleObjectProperty<ChoiceBox<PositionDefinition>> cbPosition;
 
P

Padde85

Super, danke dir für die Unterstützung :)

Musste einiges umbauen, aber dafür funktioniert es nun sauber und ohne es hinten herum durch die Brust ins Auge zu machen :)
Und wieder was dazugelernt.
 
P

Padde85

In der Tat :)

Leider hört der Spaß schon wieder auf. Ich kann nun super Werte eintragen und verändern und es stimmt immer.
Aber folgendes Problem:

Ich lade die Daten, die angezeigt werden sollen, aus einer Datenbank. In der Datenbank steht nun logischerweise nur noch die ID, die der Anwender in der Choice-Box ausgewählt hat.
Wenn ich die Daten nun in die TableView lade, steht in dem Feld leider nichts drin :(

Wie kann ich nun erreichen, dass die Daten direkt beim Laden und Einfüllen schon in der ChoiceBox entsprechend angezeigt und korrekt selektiert sind?

Bevor ich die Anpassungen gemacht habe, konnte ich ja die Choice-Box als Objekt anpassen und dort den entsprechenden Index slektieren.

Wie geht das aber nun mit dem Ansatz von oben?
 
L

lam_tr

Das ist an sich schon implementiert oben

Code:
positionColumn.setCellFactory(column -> {
    return new TableCell<MeineRow , MeineRow>() {
        @Override
        protected void updateItem(MeineRow item, boolean empty) {
            super.updateItem(item, empty);

            if (item == null || empty) {
                setText(null);
                setGraphic("");
            } else {
                ChoiceBox cb = new ChoiceBox();
                cb.setItems(FXCollections.observableArrayList("Kopfzeile", "Fusszeile", "Header"));
                // Hier wird der Wert von dem DatenModel selektiert, warum hast du nur eine Id?
                cb.getSelectionModel().setSelection(item.getPosition());
                cb.setOnAction(e->{
                   System.out.println(item.isTabellarisch());
                   System.out.println(item.isTabellarisch());
                });
                setGraphic(cb);
            }
        }
    };
});
 
P

Padde85

ahhh danke, aktuell nutze ich in der Factory das ChoiceBoxTableCell.forColumn. Dann baue ich das auf die eigene Implementierung um :)
 
P

Padde85

ich wollte das gerade ausprobieren und leider geht das aus dem alten bekannten Grund nicht:
Die Methode updateItem hat nur einen Parameter mit Werten und das sind die vom Typ VarUsageType. Damit habe ich wieder keine Info über die Zeile, in der ich mich befinde und damit auch keinen Zugriff auf die Daten zu der Zeile.

So generiert mir das Eclipse hin:
Java:
main.tcHdType.setCellFactory(column -> {
        return new TableCell<TemplateData, VarUsageType>() {

        @Override
        protected void updateItem(VarUsageType item, boolean empty) {
            // TODO Auto-generated method stub
            super.updateItem(item, empty);
        }
        
        };
    });
Die Spalte ist jetzt mittlerweile so deiniert:
Java:
public TableColumn<TemplateData, VarUsageType> tcHdType;
und hier noch der Rest vom Code, der für diese Spalte relevant ist:
Java:
main.tcHdType.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<TemplateData,VarUsageType>, ObservableValue<VarUsageType>>() {
        @Override
        public ObservableValue<VarUsageType> call(CellDataFeatures<TemplateData, VarUsageType> param) {
        VarUsageType def = null;
        TemplateData tdata = param.getValue();
        ObservableList<VarUsageType> list = main.getUsageTypes('H');
        for (VarUsageType item : list) {
            if (item.getUsage() == tdata.getVtype()) {
            def = item;
            break;
            }
        }
        return new SimpleObjectProperty<VarUsageType>(def);
        }
    });
    main.tcHdType.setCellFactory(column -> {
        return new TableCell<TemplateData, VarUsageType>() {

        @Override
        protected void updateItem(VarUsageType item, boolean empty) {
            // TODO Auto-generated method stub
            super.updateItem(item, empty);
        }
        
        };
    });
    main.tcHdType.setOnEditCommit((CellEditEvent<TemplateData, VarUsageType> event) -> {
        TablePosition<TemplateData, VarUsageType> position = event.getTablePosition();
        VarUsageType type = event.getNewValue();
        TemplateData data = event.getTableView().getItems().get(position.getRow());
        data.setVtype(type.getId());
    });
Übersehe ich was oder stehe ich nur wieder auf dem Schlauch?
 
L

lam_tr

Was repräsentiert bei dir eine Zeile, TemplateData? Und VarUsageType ist nicht der gewünschte Anzeigewert bei tcHdType?

Woher kommt das jetzt main.getUsageTypes('H');?

Es ist etwas schwierig für mich was zu sagen, wenn wir von verschiedenen Columns reden und nur Codefragmente sehe.

Ich vermute der Part sollte so aussehen:
Code:
main.tcHdType.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<TemplateData,VarUsageType>, ObservableValue<VarUsageType>>() {
        @Override
        public ObservableValue<VarUsageType> call(CellDataFeatures<TemplateData, VarUsageType> param) {
        VarUsageType def = null;
        TemplateData tdata = param.getValue();
        return new SimpleObjectProperty<VarUsageType>(tdata.getVtype());
        }
    });
Und in der CellFactory solltest du die ComboBox hinzufügen, sonst würdest vermutlich nichts sehen.

Code:
 main.tcHdType.setCellFactory(column -> {
        return new TableCell<TemplateData, VarUsageType>() {

        @Override
        protected void updateItem(VarUsageType item, boolean empty) {
            // TODO Auto-generated method stub
            super.updateItem(item, empty);

            if (item == null || empty) {
                setText(null);
                setGraphic("");
            } else {
                ChoiceBox cb = new ChoiceBox();
                cb.setItems(FXCollections.observableArrayList(main..getUsageTypes('H')));
                // Hier wird der Wert von dem DatenModel selektiert, warum hast du nur eine Id?
                cb.getSelectionModel().setSelection(item.getVtype());
                setGraphic(cb);
            }



        }
        
        };
    });
 
Thema: 

aktuelle Tabellenzeile bei Choice-Box-Auswahl in Zelle ermitteln

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben