JavaFX Tableview mit fxml ohne Aktualiserung trotz Thread

keinGuru67

Mitglied
Hallo!

Habe hier ein fxml JAVAFX Applikation die in einem Thread die Daten aktualisieren soll. Tatsächlich macht er gar nichts, nur wenn man auf Aufwärts Sort oder Abwärts Sort klickt erscheinen die Daten.
Ein ähnliches Bsp. ohne fxml funktioniert - was mache ich falsch?
Danke für Antworten.:shock:

Java:
package com.moho.lohnzettel.gui;

import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class StartMainFX extends Application {
	private Stage primaryStage;
	private Scene scene;

	public Stage getPrimaryStage() {
		return primaryStage;
	}

	public Scene getScene() {
		return scene;
	}

	private BorderPane rootLayout;

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

	// @Override
	public void start(Stage primaryStage) throws Exception {
		this.primaryStage = primaryStage;
		this.primaryStage.setTitle("Lohnzettel PDF");

		try {
			// Load the root layout from the fxml file
			FXMLLoader loader = new FXMLLoader(MenuController.class.getResource("view/TestFX.fxml"));
			rootLayout = (BorderPane) loader.load();
			scene = new Scene(rootLayout);
			primaryStage.setScene(scene);
			primaryStage.show();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	  
}

package com.moho.lohnzettel.gui;

import java.net.URL;
import java.util.ResourceBundle;

import javafx.beans.property.SimpleStringProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;

import javafx.fxml.Initializable;

import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;

public class TestFX implements Initializable {
	@FXML
	private TableView<Data> pdfTable;
	@FXML
	private TableColumn<Data, String> fileNameColumn;

	@Override
	public void initialize(URL location, ResourceBundle resources) {
		fileNameColumn.setCellValueFactory(new PropertyValueFactory<Data, String>("fileName"));
		start();
	}

	@FXML
	public void start() {
		for (int i = 0; i < 10; i++) {
			Data data = new Data();
			data.setFileName(i + " Before");
			pdfTable.getItems().add(data);
		}

		Thread threadAction1 = new Thread() {
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
				ObservableList<Data> items = pdfTable.getItems();
				for (int i = 0; i < items.size(); i++) {
					try {
						Thread.sleep(1000);
						Data d = items.get(i);
						System.out.println("test");
						d.setFileName("After " + i);

					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		};
		threadAction1.start();
	}

	public class Data {
		private SimpleStringProperty fileName;

		public String getFileName() {
			return fileName.get();
		}

		public Data() {
			super();
			this.fileName = new SimpleStringProperty();
		}

		public void setFileName(String fileName) {
			this.fileName.set(fileName);
		}

	}
}

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>

<BorderPane prefHeight="265.0000999999975" prefWidth="282.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="com.moho.lohnzettel.gui.TestFX">
<center>
<TableView fx:id="pdfTable" prefHeight="200.0" prefWidth="200.0">
<columns>
<TableColumn editable="false" minWidth="100.0" prefWidth="200.0" text="Filename" fx:id="fileNameColumn" />
</columns>
</TableView>
</center>
</BorderPane>
 

dzim

Top Contributor
Ich schau mir das morgen damit dem Code von Arbeit an...da hab ich was ähnliches auch gemacht und es geht.
 

dzim

Top Contributor
Ok, erste Frage: Du hast nur eine Spalte? Soll das so bleiben? Wenn ja, dann schwenke auf eine Liste um, das ist etwas leichter.
Wenn nein, dann geht's jetzt weiter.

Zum Vergleich mein FXML-Abschnitt:
[XML]
<TableView fx:id="tableResults" id="transparent-bg">
<minWidth><TableView fx:constant="USE_PREF_SIZE" /></minWidth>
<columns>
<TableColumn fx:id="tableColumnId" text="%root.table.column.seriesTest" prefWidth="110"/>
<TableColumn fx:id="tableColumnDate" text="%root.table.column.date" prefWidth="125"/>
<TableColumn fx:id="tableColumnDown" text="%root.table.column.down" prefWidth="100"/>
<TableColumn fx:id="tableColumnUp" text="%root.table.column.up" prefWidth="100"/>
<TableColumn fx:id="tableColumnRtt" text="%root.table.column.rtt" prefWidth="50"/>
</columns>
</TableView>
[/XML]
Ich lasse die Pref*-Sachen weg, aber das tut nichts zur Sache.

Ich habe gerade die Vermutung - da deine Daten ja schon da zu sein scheinen, dass dein erster Start über die initialize vielleicht zu früh ist. Bei mir kommen die Daten irgendwann zur Tabelle und erscheinen sofort, du machst es aber schon vom Start weg. Versuche das mal zu triggern, nachdem die UI auch angezeigt wird.

Irgendwie á la
Code:
((TestFX) loader.getController).start();
nachdem du
Code:
primaryStage.show();
ausgelöst hast.

Wenn das nicht hilft, dann mache auf jeden Fall folgendes:
Java:
				Platform.runLater(new Runnable() {
					@Override
					public void run() {
						// tableResults.getItems().add(details);
					}
				});
wann auch immer du etwas auslöst, dass die UI verändert, und du bist gerade nicht auf dem UI-Thread (sondern z.B. in deinem Thread, der aus "Before" ein "After" macht - kann man aus der Vorderansicht eine Rückansicht machen??? ;-) ), dann nutze diese Methode. Bläht den Code vielleicht auf, aber sischer ist sischer!

Sag mal bescheid, ob's klappt...
 

keinGuru67

Mitglied
Hi!

Danke für die schnelle Antwort.
Das ist nur ein Beispiel Programm eines viel komplexeren Programms - ich brauche in der Tabelle 17 Spalten. Ich habe das Bsp--Programm umgebaut und das ganze mal mit Buttons umgestaltet - ein Button zum laden der Daten - einen zweiten Button um die Daten dann im Thread zu aktualisieren - allerdings macht er nur dann ein UPDATE von den neuen Daten wenn ich Abwärts und dann AUfwärts sortiere klicke. Ich habe auch deine Änderung implementiert mit den new Runnable allerdings - immer noch kein Update. Allerdings wenn das Fenster kleiner ist als die angezeigten Daten - und mann zieht dann das Fenster auf volle Grösse auf sieht man zumindest die Daten wurden verändert die ganze unten standen. Die Oberen sind weiterhin die alten.
Ich dachte, wenn man die ObservableList verwendet und in der Klasse auch die Simple....Property verwendet, muss die tableview das mitbekommen.

Keine Ahnung wo ich da einen Fehler habe - und wie vorher gesagt ohne fxml geht es ja.

lg mike


Java:
package com.moho.lohnzettel.gui;

import java.net.URL;
import java.util.ResourceBundle;

import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;

public class TestFX implements Initializable {
	@FXML
	private TableView<Data> pdfTable;
	@FXML
	private TableColumn<Data, String> fileNameColumn;
	@FXML
	private TableColumn<Data, String> fileNameColumn2;

	@Override
	public void initialize(URL location, ResourceBundle resources) {
		fileNameColumn.setCellValueFactory(new PropertyValueFactory<Data, String>("fileName"));
		fileNameColumn2.setCellValueFactory(new PropertyValueFactory<Data, String>("fileName2"));
	}

	@FXML
	public void load() {
		for (int i = 0; i < 10; i++) {
			Data data = new Data();
			data.setFileName(i + " Before");
			data.setFileName2(i + " Before2");
			pdfTable.getItems().add(data);
		}
	}

	@FXML
	public void update2() {

		Thread threadAction1 = new Thread() {
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
				ObservableList<Data> items = pdfTable.getItems();
				for (int i = 0; i < items.size(); i++) {
					try {
						Thread.sleep(500);
						Data d = items.get(i);
						d.setFileName("After " + i);
						d.setFileName2("After2 " + i);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				System.out.println("Fertig");
			}
		};
		threadAction1.start();
	}
	
	
	@FXML
	public void update() {
		
		Platform.runLater(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
				ObservableList<Data> items = pdfTable.getItems();
				for (int i = 0; i < items.size(); i++) {
					try {
						Thread.sleep(500);
						Data d = items.get(i);
						d.setFileName("After " + i);
						d.setFileName2("After2 " + i);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				System.out.println("Fertig");

			}
		});

		
	}


	public class Data {
		private SimpleStringProperty fileName;
		private SimpleStringProperty fileName2;

		public String getFileName() {
			return fileName.get();
		}

		public String getFileName2() {
			return fileName2.get();
		}

		public Data() {
			super();
			this.fileName = new SimpleStringProperty();
			this.fileName2 = new SimpleStringProperty();
		}

		public void setFileName(String fileName) {
			this.fileName.set(fileName);
		}

		public void setFileName2(String fileName) {
			this.fileName2.set(fileName);
		}

	}
}

Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>

<BorderPane prefHeight="265.0000999999975" prefWidth="282.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="com.moho.lohnzettel.gui.TestFX">
  <center>
    <TableView fx:id="pdfTable" prefHeight="200.0" prefWidth="200.0">
      <columns>
        <TableColumn editable="false" minWidth="100.0" prefWidth="200.0" text="Filename" fx:id="fileNameColumn" />
        <TableColumn prefWidth="75.0" text="Filename2" fx:id="fileNameColumn2" />
      </columns>
    </TableView>
  </center>
  <top>
    <Pane prefHeight="57.0" prefWidth="282.0">
      <children>
        <Button layoutX="44.0" layoutY="15.0" mnemonicParsing="false" onAction="#load" text="Load" />
        <Button layoutX="168.0" layoutY="19.0" mnemonicParsing="false" onAction="#update" text="Update" />
      </children>
    </Pane>
  </top>
</BorderPane>
 

dzim

Top Contributor
Also ein Erfahrungsbericht:
Das mit dem
Code:
Platform#runlater
hast du falsch rum verstanden. Wenn du aus einem nicht-UI-Thread, also z.B. deinem Thread zum updaten die UI anpassen möchtest, kapselst du genau diese Calls in
Code:
Platform#runlater
.
Also:
Java:
	@FXML
	public void update() {
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
		ObservableList<Data> items = pdfTable.getItems();
		for (int i = 0; i < items.size(); i++) {
			try {
				Thread.sleep(500);
			} catch (Exception e) {
				e.printStackTrace();
			}
			final int index = i;
			final Data d = items.get(i);
			Platform.runLater(new Runnable() {
				@Override
				public void run() {
					d.setFileName("After " + index);
					d.setFileName2("After2 " + index);
				}
			});
		}
		System.out.println("Fertig");
		
	}

Das Laden der Daten klappt bei mir - ich weiß jetzt nicht, ob das schon ein Problem bei dir war...

Das spricht jedenfalls dafür, das die ObservableList arbeitet, wie sie soll: Die Tabelle bwekommt mit, wenn neue Daten da sind und zeigt sie entsprechend an.

Dein Problem ist also rein das Update.

Ich habe es einmal mit dem Ansatz versucht, den ich verfolge, bin aber auch nicht weiter gekommen:
Java:
	@FXML
	private TableView<Data> pdfTable;
	@FXML
	private TableColumn<Data, Data> fileNameColumn;
	@FXML
	private TableColumn<Data, Data> fileNameColumn2;
	
	@Override
	public void initialize(URL location, ResourceBundle resources) {
		
		Callback<TableColumn.CellDataFeatures<Data, Data>, ObservableValue<Data>> contentCallback = new Callback<TableColumn.CellDataFeatures<Data, Data>, ObservableValue<Data>>() {
			@Override
			public ObservableValue<Data> call(CellDataFeatures<Data, Data> param) {
				return new SimpleObjectProperty<Data>(param.getValue());
			}
		};
		fileNameColumn.setCellValueFactory(contentCallback);
		fileNameColumn.setCellFactory(new Callback<TableColumn<Data, Data>, TableCell<Data, Data>>() {
			@Override
			public TableCell<Data, Data> call(TableColumn<Data, Data> param) {
				return new DataTableCell(0);
			}
		});
		fileNameColumn2.setCellValueFactory(contentCallback);
		fileNameColumn2.setCellFactory(new Callback<TableColumn<Data, Data>, TableCell<Data, Data>>() {
			@Override
			public TableCell<Data, Data> call(TableColumn<Data, Data> param) {
				return new DataTableCell(1);
			}
		});
	}
	
	public class DataTableCell extends TableCell<Data, Data> {
		
		private final int type;
		
		public DataTableCell(final int type) {
			this.type = type;
		}
		
		@Override
		protected void updateItem(Data item, boolean empty) {
			
			super.updateItem(item, empty);
			
			if (empty) {
				setText(null);
			} else {
				setTextOverrun(OverrunStyle.ELLIPSIS);
				String text = "";
				switch (type) {
				case 0:
					text = item.getFileName();
					break;
				case 1:
					text = item.getFileName2();
					break;
				}
				setText(text);
			}
		}
	}
Ich bin mir also immerhin nun sicher, dass es nichts mit den CellFactory's zu tun hat.

Bleibt das Binding übrig: Ich würde auch erwarten, dass die PropertyValueFactory gleich ein ordentliches Binding macht. Scheint aber nicht so.

Also hier meine Lösung: Die oben beschriebene DataTableCell habe ich leicht modifiziert, so dass folgende Lösung heraus kam.
Java:
	public class DataTableCell extends TableCell<Data, Data> {
		
		private final int type;
		
		public DataTableCell(final int type) {
			this.type = type;
		}
		
		@Override
		protected void updateItem(Data item, boolean empty) {
			
			super.updateItem(item, empty);
			
			if (empty) {
				textProperty().unbind();
				setText(null);
			} else {
				setTextOverrun(OverrunStyle.ELLIPSIS);
				switch (type) {
				case 0:
					textProperty().bind(item.fileName);
					break;
				case 1:
					textProperty().bind(item.fileName2);
					break;
				}
			}
		}
	}

Noch ein letztes: Du machst ein
Code:
Thread#sleep
in der Update-Methode. Das legt deinen UI-Thread schlafen und du erhälst eine Oberfläche, von der Windoof im schlimmsten Fall sagt: "Keine Rückmeldung!". Doof. also modifizieren wir diese Methode noch ein wenig:
Java:
	@FXML
	public void update() {
		
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException ex) {}
				ObservableList<Data> items = pdfTable.getItems();
				for (int i = 0; i < items.size(); i++) {
					try {
						Thread.sleep(500);
					} catch (Exception e) {}
					final int index = i;
					final Data d = items.get(i);
					Platform.runLater(new Runnable() {
						@Override
						public void run() {
							d.setFileName("After " + index);
							d.setFileName2("After2 " + index);
						}
					});
				}
				System.out.println("Fertig");
			}
		});
		t.start();
	}
(wir mir gerade auffällt, hast du ja nie auf einem anderen als dem UI-Thread gearbeitet - upps. Damit war in deiner Version das
Code:
Platform#runlater
eigentlich sinnlos. Bei meiner Variante ist es das aber nicht ;-) )

So. Und nun wieder frisch, fromm, fröhlich, frei ans Werk. Ich geh jetzt in den Feierabend! :)
 

keinGuru67

Mitglied
Ich meinte schon, dass ich deine Version versuche - verstehe allerdings nicht - warum es einen unterschied macht zwischen fxml (also auslagern) oder alles in der klasse deklarieren mit der tableview usw. - das Beispiel mit dem Update mit einem Longtask hatte ich aus dem Internet - und das funktioniert - nur sobald ich es aus dem fxml starte - geht es nicht - ist das eventuell noch ein Bug?

Ich werden das morgen austesten - und melde mich dann - trotzdem herzlichst danke aus dem grünen (noch nicht verschneiten) Tirol - für deine Mühen.
Mike
 

keinGuru67

Mitglied
Hallo!

Vielen Dank! Es wird jetzt aktualisiert - allerdings erst nach dem alles fertig ist - und nicht sofort wenn sich der Wert ändert -
hier ein Sample das funktioniert, aber ohne fxml
Java:
package com.moho.lohnzettel.gui;

import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;


import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.StackPaneBuilder;
import javafx.stage.Stage;

public class UpdateTableView extends Application implements Initializable {

	private TableView<Person> personTable = new TableView<>();
	private TableColumn<Person, String> colName = new TableColumn<Person, String>("name");
	private TableColumn colProgressBar = new TableColumn("Progress Bar");

	@Override
	public void start(Stage primaryStage) {
		showDialog(primaryStage);

		colName.setCellValueFactory(new PropertyValueFactory<Person, String>("name"));
		//colProgressBar.setCellValueFactory(new PropertyValueFactory("progressBar")); 
		//colProgressBar.setCellFactory(ProgressBarTableCell.forTableColumn());
		//personTable.getColumns().addAll(colName, colProgressBar);
		personTable.getColumns().addAll(colName);

		for (int i = 0; i < 10; i++) {
			Person person = new Person();
			person.setProgressBar(-1.0);
			person.setName("Before" + i);
			personTable.getItems().add(person);
		}

		Thread threadAction1 = new Thread() {
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException ex) {
					Logger.getLogger(UpdateTableView.class.getName()).log(Level.SEVERE, null, ex);
				}
				ObservableList<Person> items = personTable.getItems();
				for (int i = 0; i < items.size(); i++) {
					try {
						Thread.sleep(1000);
						Person person = items.get(i);
						person.setName("After" + i);
						//person.setProgressBar(0.0);

					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		};
		threadAction1.start();
	}

	public void showDialog(Stage primaryStage) {
		try {
			StackPane root = StackPaneBuilder.create().children(personTable).build();
			primaryStage.setScene(new Scene(root, 300, 250));
			primaryStage.show();
		} catch (Exception ex) {
			System.out.println("Exception caught while showing dialog" + ex.getMessage());
		}
	}

	public static class Person {

		private StringProperty name;
		private DoubleProperty progressBar;

		private Person() {
			name = new SimpleStringProperty();
			progressBar = new SimpleDoubleProperty();
		}

		public Person(String name, double surname) {
			this.name = new SimpleStringProperty(name);
			this.progressBar = new SimpleDoubleProperty(surname);
		}

		public void setName(String name) {
			this.name.set(name);
		}

		public double getProgressBar() {
			return progressBar.get();
		}

		public void setProgressBar(double surname) {
			this.progressBar.set(surname);
		}

		public String getName() {
			return name.get();
		}

		public StringProperty nameProperty() {
			return name;
		}

		public DoubleProperty progressBarProperty() {
			return progressBar;
		}
	}

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

	@Override
	public void initialize(URL arg0, ResourceBundle arg1) {
		// TODO Auto-generated method stub
		
	}
	

}

Ich glaube es liegt am fxml - ich werden das ganze ohne dem fxml machen - trotzdem wäre es interessant - wo der Unterschied zwischen den zweien Arten der Programmierung liegt.
Danke für die Mühe
lg mike
 

dzim

Top Contributor
Ich glaube der einzig wahre Unterschied ist, dass bei FXML, die Columns schon der Tabelle zugeordnet sind, bevor du die PropertyCellFactory ran hängst. Im Code dagegen machst du es anders herum.
Eine "Zwischenlösung" wäre, im FXML noch keine Columns zuzuordnen, sondern dass erst in der initialize-Methode zu machen (quasi genau so, wie du es bereits tust).

Ein Hinweis noch zur initialize-Methode:
Soweit ich weiss, ist das Interace Initializable "so gut wie deprecated" (siehe hier: Initializable (JavaFX 2.2) ). Du musst es also nicht verwenden, weil der FXMLLoader versucht die (anotierte?) Methode selbst zu finden. Ich verwende das Interface jedenfalls nicht mehr und annotiere nur eine initialize-Methode:
Code:
@FXML public void initialize() {...}
. Das klappt wunderbar.

Hast du eigentlich deine ProgressBar schon in deine Tabelle integriert? Ist mit der von mir geposteten Lösung eigentlich gar nicht schwer. Du musst da ja nur in etwa so etwas hier machen (falls du es nicht schon wusstest):
Java:
	private final class DeviceCellFactory implements Callback<ListView<Device>, ListCell<Device>> {
		@Override
		public ListCell<Device> call(ListView<Device> param) {
			final ListCell<Device> cell = new ListCell<Device>() {
				@Override
				protected void updateItem(Device item, boolean empty) {
					super.updateItem(item, empty);
					if (empty) {
						textProperty().unbind();
						setText(null);
						graphicProperty().unbind();
						setGraphic(null);
					} else {
						setTextOverrun(OverrunStyle.ELLIPSIS);
						// setText(getItem().getName());
						// textProperty().bind(item.name());
						textProperty().bind(new DeviceNameBinding(item));
						graphicProperty().bind(new DeviceDetectedBinding(item));
					}
				}
			};
			return cell;
		}
	}
	
	private final class DeviceNameBinding extends StringBinding {
		
		private final Device device;
		
		public DeviceNameBinding(Device device) {
			this.device = device;
			super.bind(device.name());
			super.bind(device.detected());
			super.bind(device.dataBytes());
			super.bind(device.interval());
		}
		
		@Override
		protected String computeValue() {
			String name = device.getName();
			String interval = device.isDetected() && device.getInterval() > 0 ? (device.getInterval() == 200 ? bundle
					.getString("configuration.confiurationUpdate.fiveHz") : device.getInterval() == 1000 ? bundle
					.getString("configuration.confiurationUpdate.oneHz") : "") : "";
			String dataUsage = device.isDetected() && device.getDataBytes() > 0 ? (device.getDataBytes() / InternalPreferences.DEVICE_SIZE_MIB) * 100 + "%"
					: "";
			return name + (device.isDetected() ? " (" + interval + ", " + dataUsage + ")" : "");
		}
	}
	
	private final class DeviceDetectedBinding extends ObjectBinding<Node> {
		
		private final Device device;
		
		public DeviceDetectedBinding(Device device) {
			this.device = device;
			super.bind(device.detected());
		}
		
		@Override
		protected Node computeValue() {
			ImageView iv = null;
			if (device.isDetected()) {
				iv = ImageResource.getImageView("fugue/tick-circle.png");
			} else {
				iv = ImageResource.getImageView("fugue/cross-circle.png");
			}
			return iv;
		}
	}
Der Unterschied ist: Ich habe es für einen ListView verwendet, daher sieht die erste Klasse etwas anders aus und ich kombiniere alles in einer "Zelle". Du kannst bei dir einfach den Text der Zelle unbinden und auf null setzen, danach im else-Zweig noch ein
Code:
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
einfügen, das überhaupt kein Text angezeigt wird. Und im Binding ganz unten gibst du statt eines ImageViews halt eine ProgressBar zurück. Fertig.

Lustig wird es dann, wenn du in deine Zellen "komplexere" Editoren integrierst. Ich brauchte mal einen inline-Editor für die oben verwendeten Devices, um ein Label zu ändern. Das sollte aber erst passieren, nachdem man per Ok-Button das bestätigt und ich wollte keinen separaten Dialog basteln. Das vorgehen dann ist
Code:
deviceTable.setEditable(true);
das selbe für die Column machen, die einen Editor haben soll und dann irgend etwas á la:
Java:
	public class EditDeviceIntervalTableCell extends TableCell<Device, Device> {
		
		private final ObservableMap<String, Long> comboBoxContent;
		
		private HBox hBox;
		private ComboBox<String> comboBox;
		private Button button;
		
		public EditDeviceIntervalTableCell() {
			Map<String, Long> content = new TreeMap<>();
			content.put(bundle.getString("configuration.confiurationUpdate.oneHz"), 1000L);
			content.put(bundle.getString("configuration.confiurationUpdate.fiveHz"), 200L);
			comboBoxContent = FXCollections.observableMap(content);
		}
		
		@Override
		public void startEdit() {
			super.startEdit();
			// if (isEmpty())
			if (isEmpty() || !getItem().isDetected())
				return;
			if (hBox == null) {
				createHBox();
			}
			comboBox.getSelectionModel().select(getText());
			button.setDisable(true);
			setGraphic(hBox);
			setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
			comboBox.requestFocus();
		}
		
		@Override
		public void cancelEdit() {
			super.cancelEdit();
			setContentDisplay(ContentDisplay.TEXT_ONLY);
		}
		
		@Override
		public void updateItem(Device item, boolean empty) {
			super.updateItem(item, empty);
			if (!isEmpty()) {
				textProperty().bind(new DeviceIntervalBinding(item, comboBoxContent));
				if (hBox != null) {
					comboBox.getSelectionModel().select(getText());
					button.setDisable(true);
				}
			} else {
				textProperty().unbind();
				setText(null);
				setGraphic(null);
			}
		}
		
		private void createHBox() {
			
			hBox = new HBox(5.0);
			comboBox = new ComboBox<>(FXCollections.observableArrayList(comboBoxContent.keySet()));
			button = new Button(bundle.getString("configuration.confiurationUpdate.button.ok"));
			button.setDisable(true);
			
			comboBox.setMaxWidth(Double.MAX_VALUE);
			HBox.setHgrow(comboBox, Priority.ALWAYS);
			HBox.setHgrow(button, Priority.NEVER);
			
			hBox.getChildren().add(comboBox);
			hBox.getChildren().add(button);
			
			comboBox.setOnAction(new EventHandler<ActionEvent>() {
				@Override
				public void handle(ActionEvent event) {
					if (!comboBox.getSelectionModel().getSelectedItem().equals(getText())) {
						button.setDisable(false);
					}
				}
			});
			button.setOnAction(new EventHandler<ActionEvent>() {
				@Override
				public void handle(ActionEvent event) {
					getItem().setInterval(comboBoxContent.get(comboBox.getSelectionModel().getSelectedItem()));
					
					ConfigureGPSDeviceTask task = new ConfigureGPSDeviceTask(broker, context.get(Stage.class), bundle, getItem());
					task.setCancelable(false);
					task.setTitleAsInitialStatus(true);
					UIEvent uiEvent = new UIEvent(UIBaseEvents.PROGRESS_ADD_TASK, task);
					broker.send(uiEvent.getName(), uiEvent);
					
					cancelEdit();
				}
			});
		}
	}
	
	private final class DeviceIntervalBinding extends StringBinding {
		
		private final ObservableMap<String, Long> comboBoxContent;
		
		private final Device device;
		
		public DeviceIntervalBinding(Device device, ObservableMap<String, Long> comboBoxContent) {
			super.bind(device.detected());
			super.bind(device.interval());
			this.device = device;
			this.comboBoxContent = comboBoxContent;
		}
		
		@Override
		protected String computeValue() {
			String interval = "";
			for (String key : comboBoxContent.keySet()) {
				if (comboBoxContent.get(key) == device.getInterval()) {
					interval = key;
					break;
				}
			}
			return device.isDetected() ? interval : "";
		}
	}
Zusammenfassend sieht man im Normalzustand nur einen Text (hier etwas wie 5Hz oder 1Hz), klickt man in die Zelle, schaltet sie auf "Graphic Only" und eine ComboBox und ein Button erscheint. Ändert man die Auswahl in der ComboBox, wird der Button aktiviert, klickt man OK, wird es übernommen, klickt man aber einfach woanders hin (ausserhalb der Zelle), wird wieder auf nur Text geschaltet und alles bleibt beim alten... Fand ich recht nett und hat mich inkl. Google und StackOverflow etwa eine halbe bin eine Stunde gekostet.
 

keinGuru67

Mitglied
Hi!

Habe weiter probiert und bin heute auf die Lösung gestossen.
Mann muss in der Klasse unbedingt die set und getter haben plus die getter Methoden auf den Properties.

Java:
class Person{
SimpleString name;
String getName(){....}
setName(String name ){name.set(name)};
StringProperty nameProperty(){return name}

}

Nach dieser Umstellung hat es funktioniert!:idea:
lg mike
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
H Java FX List<AlbumsBean> in FXML TableView AWT, Swing, JavaFX & SWT 37
Juelin setzen background color für selected Row im Tableview AWT, Swing, JavaFX & SWT 21
M JavaFX TableView nur erste Zeile editable machen und gelb markieren AWT, Swing, JavaFX & SWT 0
Encera TableView Zeilen als Spalten im SceneBuilder AWT, Swing, JavaFX & SWT 0
T TableView Button onAction AWT, Swing, JavaFX & SWT 3
mrbody234 ArrayList<Message> in eine TableView visualisieren AWT, Swing, JavaFX & SWT 2
izoards JavaFX TableView mit Array Inhalt füllen AWT, Swing, JavaFX & SWT 1
A Mit JavaFX einzelne Zeilen in TableView farbig markieren AWT, Swing, JavaFX & SWT 5
I JavaFX Zellen in Tableview editieren AWT, Swing, JavaFX & SWT 0
A TableView updatet sich nicht AWT, Swing, JavaFX & SWT 3
missy72 JavaFX TableView Spalte zwischen den Zeilen AWT, Swing, JavaFX & SWT 5
W TableView füllen AWT, Swing, JavaFX & SWT 18
missy72 JavaFX TableView / IconView mit MousEvent AWT, Swing, JavaFX & SWT 7
missy72 JavaFX Performance / ImageView in TableView über TimeLine AWT, Swing, JavaFX & SWT 1
T TableView aktualisieren AWT, Swing, JavaFX & SWT 1
N JavaFX Tableview nach Löschen von Element falscher Index AWT, Swing, JavaFX & SWT 4
T TableView Zeilen einfärben AWT, Swing, JavaFX & SWT 13
T TableView über Methode befüllen AWT, Swing, JavaFX & SWT 10
missy72 JavaFX TableView / TableColumn / ObservableList / zwei Werte in einer Zelle AWT, Swing, JavaFX & SWT 2
W JavaFX TableView aktualisieren AWT, Swing, JavaFX & SWT 1
S JavaFX - mit Listener Veränderungen in einer TableView abhören AWT, Swing, JavaFX & SWT 3
B JavaFX TableView-Zellen sollen automatisch so groß wie der größte Inhalt sein AWT, Swing, JavaFX & SWT 6
D JavaFX Nullpointerexception wegen TableView AWT, Swing, JavaFX & SWT 2
S Alternative JavaFX TableView AWT, Swing, JavaFX & SWT 1
L JavaFX Tableview row callback AWT, Swing, JavaFX & SWT 0
G Bekomme ResultSet mittels ObservableList nicht ins TableView AWT, Swing, JavaFX & SWT 25
S JavaFX JavaFX TableView scrollen färbt falsche Zeilen AWT, Swing, JavaFX & SWT 1
A checkbox in einer TableView abhängig von einem anderen Celleninhalt disablen AWT, Swing, JavaFX & SWT 1
J JavaFx TableView mit CheckBox AWT, Swing, JavaFX & SWT 4
P JavaFX TableView Zelle markieren AWT, Swing, JavaFX & SWT 3
L JavaFX Tableview Datamodel AWT, Swing, JavaFX & SWT 2
M TableView Zeile hinzufügen AWT, Swing, JavaFX & SWT 5
Bluedaishi TableView mit Combox wert wird nicht in die TableView gesetzt AWT, Swing, JavaFX & SWT 38
J TableView Update/Refresh CPU AWT, Swing, JavaFX & SWT 2
B Text im Tetfeld in einer TableView darstellen AWT, Swing, JavaFX & SWT 20
J Tableview - kann man mit Enter die Zellen wechseln AWT, Swing, JavaFX & SWT 1
ralfb1105 JavaFX Dynamisch TableView Spalten erstellen AWT, Swing, JavaFX & SWT 4
M TableView + Datenbank Aktualisierung AWT, Swing, JavaFX & SWT 4
B TableView als PDF speichern AWT, Swing, JavaFX & SWT 8
B JavaFX TableView eine Zeile markieren AWT, Swing, JavaFX & SWT 5
B JavaFX JavaFX TableView PropertyValueFactory für Werte aus HashMap AWT, Swing, JavaFX & SWT 2
L JavaFX TableView Column Sortierung AWT, Swing, JavaFX & SWT 1
L Java FX Keine Anzeige Im Tableview AWT, Swing, JavaFX & SWT 4
L JavaFX TableView kein content text ändern AWT, Swing, JavaFX & SWT 2
L JavaFX TableView mit Aktionenbuttons AWT, Swing, JavaFX & SWT 1
C JavaFX Edit TableView in Verbindung mit SceneBuilder AWT, Swing, JavaFX & SWT 1
C JavaFX ProGuard -> TableView kein Inhalt AWT, Swing, JavaFX & SWT 7
J SceneBuilder TableView Checkbox AWT, Swing, JavaFX & SWT 1
J JavaFX Elemente werden nicht zu TableView hinzugefügt AWT, Swing, JavaFX & SWT 3
F JavaFX (Tree)TableView korrekt drucken AWT, Swing, JavaFX & SWT 1
robinab JavaFX TableView column resize nach setItems() AWT, Swing, JavaFX & SWT 0
G JavaFX TableView Wert in Spalte ändern AWT, Swing, JavaFX & SWT 0
S JavaFx - ausgewählte Rows in Arraylist (Tableview) AWT, Swing, JavaFX & SWT 4
S JavaFX - Populate TableView AWT, Swing, JavaFX & SWT 2
N JavaFX TableView aus Map AWT, Swing, JavaFX & SWT 2
J TableView Daten werden nicht ausgegeben AWT, Swing, JavaFX & SWT 9
B JavaFX TableView aus Collection befüllen AWT, Swing, JavaFX & SWT 1
S JavaFX TableView einzelne Zelle Layout zuweisen AWT, Swing, JavaFX & SWT 3
zhermann TableView die zweite AWT, Swing, JavaFX & SWT 7
E JavaFX TableView mit Zeilenumbruch in Zellen AWT, Swing, JavaFX & SWT 5
zhermann TableView wird nicht gefüllt AWT, Swing, JavaFX & SWT 14
M JavaFX JavaFX ResultSet in TableView ausgeben AWT, Swing, JavaFX & SWT 2
W JavaFX Mehrere Klassen in ein TableView AWT, Swing, JavaFX & SWT 6
MaxG. JavaFX Inhalt in Tableview wird nicht angezeigt AWT, Swing, JavaFX & SWT 11
M JavaFX berechneten Wert in TableView schreiben AWT, Swing, JavaFX & SWT 1
K JavaFX Message in TableView AWT, Swing, JavaFX & SWT 2
H TableView mit variabler Anzahl Spalten AWT, Swing, JavaFX & SWT 2
L JavaFX List oder TableView Größe dynamisch anpassen? AWT, Swing, JavaFX & SWT 4
L JavaFX TableView mit Excelfunktion AWT, Swing, JavaFX & SWT 1
D JavaFX TableView AWT, Swing, JavaFX & SWT 2
L JavaFX TableView mit XYChart verbinden AWT, Swing, JavaFX & SWT 3
blazingblade JavaFX Tableview Clock Column update AWT, Swing, JavaFX & SWT 5
P JavaFX, TableView und Datenbank AWT, Swing, JavaFX & SWT 4
K TableView: 'Komplexes' Object AWT, Swing, JavaFX & SWT 11
L JavaFX TableView background transparent machen AWT, Swing, JavaFX & SWT 7
F TableCell aus TableView holen AWT, Swing, JavaFX & SWT 8
K JavaFX TableView mit Rectangle AWT, Swing, JavaFX & SWT 3
M Befüllung der einzelnen Zeilen des TableView AWT, Swing, JavaFX & SWT 3
J JavaFX Tableview Daten hinzufügen aus anderer Klasse AWT, Swing, JavaFX & SWT 7
J Tableview Daten hinzufügen und aktualisieren AWT, Swing, JavaFX & SWT 5
N JavaFX TableView füllt nicht das gesamte ScrollPanle aus AWT, Swing, JavaFX & SWT 2
M JavaFX TableView & CSS, Rand um Tabellenkopf entfernen AWT, Swing, JavaFX & SWT 3
L JavaFX ListView oder TableView Style überschreiben? AWT, Swing, JavaFX & SWT 6
G Event Handling TableView daten in ein neues Fenster herauslesen? AWT, Swing, JavaFX & SWT 3
thet1983 JavaFX TableView Objekt Daten anzeige AWT, Swing, JavaFX & SWT 2
J JavaFX TableView - Höhe der Zeilen AWT, Swing, JavaFX & SWT 3
L JavaFX TableView mit Attributs der Modellreferenzerierung für die Spalte AWT, Swing, JavaFX & SWT 3
I JavaFX Buttons und TableView AWT, Swing, JavaFX & SWT 2
J JavaFX Bestimmte Zellen im TableView ändern (Farbe und Text) AWT, Swing, JavaFX & SWT 1
B Java FX TableView Zeilen mit verschiedenen Typen AWT, Swing, JavaFX & SWT 15
Z JavaFX TableView cellValueFactory für Arrays AWT, Swing, JavaFX & SWT 2
E JavaFX TableView mit Rechtsklick Zelle auswählen AWT, Swing, JavaFX & SWT 8
C (JavaFX 8) SQLite Datenbank in einem TableView darstellen AWT, Swing, JavaFX & SWT 2
D JavaFX TableView bleibt leer. AWT, Swing, JavaFX & SWT 8
M JavaFX TableView nach Spalte sortieren AWT, Swing, JavaFX & SWT 1
P JavaFX Dynamische TableView AWT, Swing, JavaFX & SWT 14
V Java FX POJO aus Datenbank in FX TableView / Best Practice AWT, Swing, JavaFX & SWT 0
P JavaFX TableView Item hinzufügen AWT, Swing, JavaFX & SWT 20
W JavaFX TableView frage AWT, Swing, JavaFX & SWT 5
M JavaFX Tutorial zu Tableview AWT, Swing, JavaFX & SWT 5

Ähnliche Java Themen

Neue Themen


Oben