# Layout von Panes in JFX2



## dzim (6. Jun 2012)

Hallo zusammen,

ich habe mich vor kurzen daran gemacht, ein kleines Spaß-Projekt von mir (Passwort Manager) von seiner bestehenden SWT-Implementieren auf JavaFX umzustellen.
Mittels e(fx)clipse möchte ich das gerne in meine Eclipse 3.x basierte Plugin-Platform integrieren (also neben anderen z.B. SWT-Komponenten). Dank e(fx)clipse funktioniert das auch Prinzipiell, aber ich möchte die Anwendung erst einmal rein in JFX schreiben, bevor ich mich daran wage. Ich möchte das Framework erst mal "kennen lernen"...

Mein Problem so weit ist (von einigen kleinen Unbequemlichkeiten wie kein TreeTable-Widget), dass ich mit dem Layout echt Probleme hab.

Parent ist eine VBox, auf die ein Menü und eine Toolbar gelegt werden. Das dritte Element der VBox soll dann das Bearbeitungsfenster werden.
Das Problem ist, das ein TreeView, der im Hauptbereich zu sehen ist, nicht skaliert. Er wird zwar kleiner, wenn das Fenster kleiner als seine Ursprungsgröße wird, aber nie größer als die Ursprungsgröße, skaliert also niemals auf die größe des Fensters (bzw. die Höhe ist es, die mich interessiert)

Ich seh' das Layout vor lauter Panes nicht mehr...

Anbei der Quellcode der bisher drei UI-Klassen. Seht ihr vielleicht, wo da das Problem liegt???

Vielen Dank im Voraus!!!
Daniel

Die Application-Klasse:

```
public class PWMJFXApplication extends Application {

	@Override
	public void start(Stage primaryStage) {

		primaryStage.setTitle("PWM - The Password Manager");

		VBox root = new VBox(0);

		PWMMainWindow window = new PWMMainWindow(root);
		window.setCreateMenu(true);
		window.createContent();

		Scene scene = new Scene(root, 1024, 800);
		primaryStage.setScene(scene);
		primaryStage.show();
	}

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

Hier wird der Inhalt des Menüs und der Toolbar erstellt:

```
public class PWMMainWindow {

	private final Pane root;

	private boolean createMenu = true;
	private boolean createToolbar = true;

	public PWMMainWindow(Pane root) {
		this.root = root;
	}

	public void setCreateMenu(boolean createMenu) {
		this.createMenu = createMenu;
	}

	public boolean isCreateMenu() {
		return createMenu;
	}

	public void setCreateToolbar(boolean createToolbar) {
		this.createToolbar = createToolbar;
	}

	public boolean isCreateToolbar() {
		return createToolbar;
	}

	public void createContent() {

		if (createMenu) {
			MenuBar menubar = new MenuBar();
			menubar.setUseSystemMenuBar(true);
			createMenuBar(menubar);
			root.getChildren().add(menubar);
		}

		if (createToolbar) {
			ToolBar toolbar = new ToolBar();
			createToolbar(toolbar);
			root.getChildren().add(toolbar);
		}

		PWMEditorWindow editor = new PWMEditorWindow();
		root.getChildren().add(editor.createContent());
	}

	private void createMenuBar(MenuBar menubar) {

		// file menu

		Menu file = new Menu("_File");

		MenuItem fileOpenItem = new MenuItem("_Open",
				PWMImageResource.getImageView(PWMImageResourceType.OPEN));
		MenuItem fileSaveItem = new MenuItem("_Save",
				PWMImageResource.getImageView(PWMImageResourceType.SAVE));
		MenuItem fileSaveAsItem = new MenuItem("Save As...",
				PWMImageResource.getImageView(PWMImageResourceType.SAVE_AS));
		MenuItem fileExitItem = new MenuItem("E_xit",
				PWMImageResource.getImageView(PWMImageResourceType.EXIT));

		fileOpenItem.setAccelerator(KeyCombination.valueOf("Ctrl+O"));
		fileSaveItem.setAccelerator(KeyCombination.valueOf("Ctrl+S"));
		fileExitItem.setAccelerator(KeyCombination.valueOf("Ctrl+X"));

		fileExitItem.setOnAction(new PWMEventHandler(PWMEventHandlerType.EXIT));

		file.getItems().addAll(fileOpenItem, new SeparatorMenuItem(),
				fileSaveItem, fileSaveAsItem, new SeparatorMenuItem(),
				fileExitItem);

		[...]

		// build global menu

		menubar.getMenus().addAll(file);
	}

	private void createToolbar(ToolBar toolbar) {

		Button openButton = new Button(
				PWMImageResource.getImage(PWMImageResourceType.OPEN) == null ? "Open"
						: "",
				PWMImageResource.getImageView(PWMImageResourceType.OPEN));

		Button saveButton = new Button(
				PWMImageResource.getImage(PWMImageResourceType.OPEN) == null ? "Save"
						: "",
				PWMImageResource.getImageView(PWMImageResourceType.SAVE));
		Button saveAsButton = new Button(
				PWMImageResource.getImage(PWMImageResourceType.OPEN) == null ? "Save As..."
						: "",
				PWMImageResource.getImageView(PWMImageResourceType.SAVE_AS));

		[...]

		toolbar.getItems().addAll(openButton, new Separator(), saveButton,
				saveAsButton, new Separator());
	}
```

Hier die Klasse, die für das Hauptfenster zuständig ist. Problem, wie beschrieben: der TreeView skaliert nicht auf die Größe des Fensters.

```
public class PWMEditorWindow {

	public PWMEditorWindow() {
	}

	public Pane createContent() {

		BorderPane grid = new BorderPane();
		grid.setMaxSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);
		grid.setPrefWidth(250);
		grid.setPadding(new Insets(10, 10, 10, 10));

		grid.setLeft(createGroupPart());
		grid.setRight(createContentPart());

		return grid;
	}

	private Pane createGroupPart() {

		// GridPane grid = new GridPane();
		VBox vbox = new VBox(5);

		Label label = new Label("Groups");

		PWMContainer container = null;
		try {
			container = PWMJFXUtils
					.loadPWMContainer(new File(
							"/home/dzimmermann/temp/workspace-basicplatform/pwm/Test.pwm"));
		} catch (Exception e) {
			e.printStackTrace();
		}

		TreeView<PWMContainerGroup> groupTreeView = new TreeView<PWMContainerGroup>(
				createNode(container));
		groupTreeView.setShowRoot(false);
		groupTreeView.setCellFactory(new PWMContainerGroupCallback());

		// grid.add(label, 0, 0);
		// grid.add(groupTreeView, 0, 1);
		vbox.getChildren().addAll(label, groupTreeView);

		return vbox;
	}

	private Pane createContentPart() {

		VBox vbox = new VBox();

		return vbox;
	}

	private TreeItem<PWMContainerGroup> createNode(PWMContainer container) {
		return createNode(new PWMContainerGroupRoot(container));
	}

	private TreeItem<PWMContainerGroup> createNode(PWMContainerGroup group) {
		return new PWMContainerGroupTreeItem(group);
	}

	private ObservableList<TreeItem<PWMContainerGroup>> buildChildren(
			TreeItem<PWMContainerGroup> treeItem) {
		PWMContainerGroup group = treeItem.getValue();
		if (group != null && !group.getGroups().isEmpty()) {
			ObservableList<TreeItem<PWMContainerGroup>> children = FXCollections
					.observableArrayList();
			for (PWMContainerGroup childGroup : group.getGroups())
				children.add(createNode(childGroup));
			return children;
		}

		return FXCollections.emptyObservableList();
	}

	/**
	 * Custom TreeItem for group entries.
	 * 
	 * @author dzimmermann
	 */
	private final class PWMContainerGroupTreeItem extends
			TreeItem<PWMContainerGroup> {

		private boolean isLeaf;
		private boolean isFirstTimeChildren = true;
		private boolean isFirstTimeLeaf = true;

		public PWMContainerGroupTreeItem(PWMContainerGroup group) {
			super(group);
		}

		@Override
		public ObservableList<TreeItem<PWMContainerGroup>> getChildren() {
			if (isFirstTimeChildren) {
				super.getChildren().setAll(buildChildren(this));
				isFirstTimeChildren = false;
			}
			return super.getChildren();
		}

		@Override
		public boolean isLeaf() {
			if (isFirstTimeLeaf) {
				PWMContainerGroup g = (PWMContainerGroup) getValue();
				isLeaf = g.getGroups().isEmpty();
				isFirstTimeLeaf = false;
			}
			return isLeaf;
		}
	}

	/**
	 * A fake root for the Tree.
	 * 
	 * @author dzimmermann
	 */
	private static final class PWMContainerGroupRoot extends PWMContainerGroup {

		public PWMContainerGroupRoot(PWMContainer container) {
			setName("PWM Groups");
			setId(getName());
			getGroups().addAll(container.getGroups());
		}
	}

	/**
	 * Custom callback handler for printing the TreeItems label.
	 * 
	 * @author dzimmermann
	 */
	private static final class PWMContainerGroupCallback implements
			Callback<TreeView<PWMContainerGroup>, TreeCell<PWMContainerGroup>> {

		@Override
		public TreeCell<PWMContainerGroup> call(
				TreeView<PWMContainerGroup> param) {
			return new TreeCell<PWMContainerGroup>() {
				@Override
				protected void updateItem(PWMContainerGroup item, boolean empty) {
					super.updateItem(item, empty);
					if (item != null)
						setText(item.getName());
				}
			};
		}
	}
```


----------



## Paddelpirat (6. Jun 2012)

Du könntest es mal mit 
	
	
	
	





```
VBox.setVgrow(groupTreeView, Priority.ALWAYS);
```
 versuchen.

Siehe dazu Beispiel 1-4 hier: Working With Layouts in JavaFX: Using Built-in Layout Panes | JavaFX 2 Tutorials and Documentation


----------



## dzim (6. Jun 2012)

Den Einfall hatte ich auch schon, wenn auch auf der Basis des Editor-Contents (Klasse "PWMMainWindow").
Ich habe es groupTreeView eben auch probiert, aber leider hat es nicht geholfen...


----------



## dzim (6. Jun 2012)

Hm. Also das Layout-Management  finde ich derzeit noch - gelinde gesagt - bescheiden.

Ich habe es jetzt primär auf GridPane umgestellt (kann ich mir besser vorstellen). Wichtig scheint zu sein, dass bei Nodes, die den gesamten Verfügbaren Raum die Hgro oder Vgrow Anweisung an allen notwendigen Stellen auch gesetzt wird.

Hier der modifizierte Code:

In der Application-Klasse aus der VBox ein GridPane gemacht.

In *PWMMainWindow* die _createContent_-Methode angepasst:

```
public void createContent() {

		VBox menubarToolbarBox = new VBox(0);

		if (createMenu) {
			MenuBar menubar = new MenuBar();
			menubar.setUseSystemMenuBar(false);
			createMenuBar(menubar);
			menubarToolbarBox.getChildren().add(menubar);
		}

		if (createToolbar) {
			ToolBar toolbar = new ToolBar();
			createToolbar(toolbar);
			menubarToolbarBox.getChildren().add(toolbar);
		}

		if (menubarToolbarBox.getChildren().size() > 0) {
			if (root instanceof GridPane)
				((GridPane) root).add(menubarToolbarBox, 0, 0);
			else
				root.getChildren().add(menubarToolbarBox);
		}

		PWMEditorWindow editor = new PWMEditorWindow();
		Pane editorPane = editor.createContent();
		if (root instanceof GridPane) {
			((GridPane) root).add(editorPane, 0, 1);
			GridPane.setHgrow(editorPane, Priority.ALWAYS);
			GridPane.setVgrow(editorPane, Priority.ALWAYS);
		} else
			root.getChildren().add(editorPane);
	}
```

In *PWMEditorWindow* wurden die drei folgenden Methoden verändert:

```
public Pane createContent() {

		GridPane grid = new GridPane();
		grid.setHgap(10);
		grid.setPadding(new Insets(5, 5, 5, 5));

		Pane groupPane = createGroupPane();
		Pane contentPane = createContentPane();

		grid.add(groupPane, 0, 0);
		grid.add(contentPane, 1, 0);

		// GridPane.setHgrow(groupPane, Priority.ALWAYS);
		GridPane.setVgrow(groupPane, Priority.ALWAYS);
		GridPane.setHgrow(contentPane, Priority.ALWAYS);
		GridPane.setVgrow(contentPane, Priority.ALWAYS);

		return grid;
	}

	private Pane createGroupPane() {

		GridPane grid = new GridPane();
		grid.setVgap(5);

		Label label = new Label("Groups");

		PWMContainer container = null;
		try {
			container = PWMJFXUtils
					.loadPWMContainer(new File(
							"/home/dzimmermann/temp/workspace-basicplatform/pwm/Test.pwm"));
		} catch (Exception e) {
			e.printStackTrace();
		}

		TreeView<PWMContainerGroup> groupTreeView = new TreeView<PWMContainerGroup>(
				createNode(container));
		groupTreeView.setShowRoot(false);
		groupTreeView.setCellFactory(new PWMContainerGroupCallback());
		groupTreeView.setMinWidth(100);

		grid.add(label, 0, 0);
		grid.add(groupTreeView, 0, 1);
		GridPane.setHgrow(groupTreeView, Priority.ALWAYS);
		GridPane.setVgrow(groupTreeView, Priority.ALWAYS);

		return grid;
	}

	private Pane createContentPane() {

		VBox vbox = new VBox(5);

		GridPane grid = new GridPane();
		grid.setVgap(5);

		Label label = new Label("Entries");

		TreeView<PWMGroupEntry> contentTreeView = new TreeView<PWMGroupEntry>(
				null);
		contentTreeView.setShowRoot(false);

		grid.add(label, 0, 0);
		grid.add(contentTreeView, 0, 1);
		GridPane.setHgrow(contentTreeView, Priority.ALWAYS);
		GridPane.setVgrow(contentTreeView, Priority.ALWAYS);

		vbox.getChildren().add(grid);
		VBox.setVgrow(grid, Priority.ALWAYS);

		return vbox;
	}
```

Ich will nicht behaupten, das die Oberfläche schon wirklich "schön" wäre, aber es ist ein Anfang!

Daniel


----------



## Paddelpirat (6. Jun 2012)

Bin gerade in der Uni, ich schau es mir später nochmal an.


----------



## dzim (7. Jun 2012)

Ok, ich muss das Thema noch einmal neu öffnen, da ich gerade etwas verwirrt ob des JavaFX TableViews bin:

ich habe den Quellcode oben soweit abgeändert, dass das Label obsolet wird, indem ich die Trees/Tabellen in ein TitledPane gepackt hab.
Nach einigem Hin und Her habe ich sowohl das Layout dieser Komponenten, als auch - mit CSS - die normale Auswahlfahrbe beseitigt, da dass in diesem Kontext eher bescheiden aus sah.
Ich hab danach begonnen die Tabelle mit Spalten zu füllen und sie dann in der Größe verändert - allerdings Breiter als das TitledPane. Erwartet habe ich Scrollbalken, bekommen habe ich eine zum Teil nicht sichtbare Tabelle und keine Möglichkeit, außer das Fenster zu vergrößern, an die Spalten zu kommen.

Ich dachte mir dann: Ok, ab in ein ScrollPane. Aber jetzt nutzt die Tabelle nicht mehr die volle Höhe und wenn ich das Fenster breiter mache als die Tabelle, dann wird sie auch nicht vergrößert, sondern abgeschnitten...

Allmählich frag ich mich, was Oracle sich dabei gedacht hat... 

Könnt ihr mir hier irgendiwe helfen?

Grüße,
Daniel


----------



## Paddelpirat (7. Jun 2012)

Kannst du mal den Code zeigen?


----------



## dzim (7. Jun 2012)

Ich warne schon mal vor: Der ist noch sehr - ähm - experimentell... Und unschön...

Ist aus dem Code von weiter oben entstanden:

```
private Pane createContentPane() {

		VBox vbox = new VBox(5);

		// content table section

		ScrollPane scrollPane = new ScrollPane();
		scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
		scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);

		GridPane grid = new GridPane();
		grid.setVgap(5);

		contentTableView = new TableView<PWMGroupEntry>(null);
		contentTableView.getSelectionModel().setSelectionMode(
				SelectionMode.SINGLE);

		TableColumn<PWMGroupEntry, String> tcTitle = new TableColumn<PWMGroupEntry, String>("Title");
		tcTitle.setMinWidth(200);
		tcTitle.setCellValueFactory(new PropertyValueFactory<PWMGroupEntry, String>("name"));
		TableColumn<PWMGroupEntry, String> tcUser = new TableColumn<PWMGroupEntry, String>("Username");
		tcUser.setMinWidth(200);
		tcUser.setCellValueFactory(new PropertyValueFactory<PWMGroupEntry, String>("username"));
		TableColumn<PWMGroupEntry, String> tcURL = new TableColumn<PWMGroupEntry, String>("URL");
		tcURL.setMinWidth(250);
		tcURL.setCellValueFactory(new PropertyValueFactory<PWMGroupEntry, String>("url"));
		tcURL.setCellFactory(new Callback<TableColumn<PWMGroupEntry, String>, TableCell<PWMGroupEntry, String>>() {
			@Override
			public TableCell<PWMGroupEntry, String> call(
					TableColumn<PWMGroupEntry, String> param) {
				return new PWMGroupEntryHyperlinkCell();
			}
		});
		TableColumn<PWMGroupEntry, String> tcDateAdd = new TableColumn<PWMGroupEntry, String>("Date Added");
		tcDateAdd.setMinWidth(150);
		tcDateAdd.setCellValueFactory(new PropertyValueFactory<PWMGroupEntry, String>("dateAdded"));
		TableColumn<PWMGroupEntry, String> tcDateMod = new TableColumn<PWMGroupEntry, String>("Date Modified");
		tcDateMod.setMinWidth(150);
		tcDateMod.setCellValueFactory(new PropertyValueFactory<PWMGroupEntry, String>("dateModified"));

		contentTableView.getColumns().add(tcTitle);
		contentTableView.getColumns().add(tcUser);
		contentTableView.getColumns().add(tcURL);
		contentTableView.getColumns().add(tcDateAdd);
		contentTableView.getColumns().add(tcDateMod);

		grid.add(contentTableView, 0, 0);

		GridPane.setHgrow(contentTableView, Priority.ALWAYS);
		GridPane.setVgrow(contentTableView, Priority.ALWAYS);

		scrollPane.setContent(grid);

		TitledPane contentPane = new TitledPane();
		contentPane.setText("Entries");
		contentPane.setCollapsible(false);
		contentPane.setExpanded(true);
		contentPane.setMaxHeight(Double.MAX_VALUE);
		contentPane.setMinWidth(300);
		contentPane.setMinHeight(300);
		// contentPane.setContent(grid);
		contentPane.setContent(scrollPane);

		// content overview section

		GridPane grid2 = new GridPane();
		grid2.setPadding(new Insets(5, 5, 0, 5));
		grid2.setHgap(5);
		grid2.setVgap(5);

		Label lTitle = new Label("Title:");
		lTitle.setTextAlignment(TextAlignment.RIGHT);
		lTitle.getStyleClass().add("label");
		Label lUser = new Label("Username:");
		lUser.setTextAlignment(TextAlignment.RIGHT);
		Label lPass = new Label("Password:");
		lPass.setTextAlignment(TextAlignment.RIGHT);
		Label lURL = new Label("URL:");
		lURL.setTextAlignment(TextAlignment.RIGHT);
		Label lDateAdd = new Label("Date Added:");
		lDateAdd.setTextAlignment(TextAlignment.RIGHT);
		Label lDateMod = new Label("Date Modified:");
		lDateMod.setTextAlignment(TextAlignment.RIGHT);
		Label lDateExp = new Label("Expiration Date:");
		lDateExp.setTextAlignment(TextAlignment.RIGHT);
		Label lDesc = new Label("Description:");
		lDesc.setTextAlignment(TextAlignment.RIGHT);

		tTitle = new Text();
		tUser = new Text();
		tPass = new Text();
		hURL = new Hyperlink();
		tDateAdd = new Text();
		tDateMod = new Text();
		tDateExp = new Text();
		taDesc = new TextArea();
		taDesc.setId("ta-description");
		taDesc.setMinHeight(50);
		taDesc.setMaxHeight(50);

		grid2.addColumn(0, lTitle, lUser, lPass, lURL, lDesc);
		grid2.addColumn(1, tTitle, tUser, tPass, hURL, taDesc);
		grid2.addColumn(2, lDateAdd, lDateMod, lDateExp);
		grid2.addColumn(3, tDateAdd, tDateMod, tDateExp);

		GridPane.setHgrow(tTitle, Priority.ALWAYS);
		GridPane.setHgrow(tUser, Priority.ALWAYS);
		GridPane.setHgrow(tPass, Priority.ALWAYS);
		GridPane.setHgrow(hURL, Priority.ALWAYS);
		GridPane.setHgrow(taDesc, Priority.ALWAYS);
		GridPane.setHgrow(tDateAdd, Priority.ALWAYS);
		GridPane.setHgrow(tDateMod, Priority.ALWAYS);
		GridPane.setHgrow(tDateExp, Priority.ALWAYS);
		// GridPane.setVgrow(tfDesc, Priority.ALWAYS);
		GridPane.setColumnSpan(taDesc, 3);

		TitledPane contentOverviewPane = new TitledPane();
		contentOverviewPane.setText("Entry Overview");
		contentOverviewPane.setCollapsible(false);
		contentOverviewPane.setExpanded(true);
		contentOverviewPane.setContent(grid2);
		contentOverviewPane.setMinHeight(175);

		// add to vbox

		vbox.getChildren().add(contentPane);
		vbox.getChildren().add(contentOverviewPane);

		VBox.setVgrow(contentPane, Priority.ALWAYS);

		return vbox;
	}
```

BTW: Danke ;-)


----------



## Paddelpirat (7. Jun 2012)

Was ich gerade noch bei meiner eigenen Anwendung gesehen habe, damit sich die Komponenten (die keine Panes sind) der Größe des Fensters anpassen, ist die Einstellung.


```
javafxcomponent.setMaxWidth(Double.MAX_VALUE);
```
 und 
	
	
	
	





```
javafxcomponent.setMaxHeight(Double.MAX_VALUE);
```
.

bringt das etwas?

In deinem Fall müsstest du das wohl für die contentTableView aufrufen.

Edit: Das mit dem experimentellen Code kenne ich *g*. Habe auch gerade erst mal etwas gebraucht bis eine ProgressBar das getan hat was ich wollte.


----------



## dzim (7. Jun 2012)

Ich hab's gerade sowohl an der Table als auch am Grid angehängt und es ändert leider nichts :-(

edit:
hier mal ein Testprogramm (selbes bescheidenes Verhalten) - damit kann man es besser nachstellen...


```
public class Test extends Application {

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

	@Override
	public void start(Stage primaryStage) {

		primaryStage.setTitle("");

		StackPane root = new StackPane();

		root.getChildren().add(createContentPane());

		Scene scene = new Scene(root, 1024, 800);
		primaryStage.setScene(scene);
		primaryStage.show();
	}
	
	private Pane createContentPane() {

		VBox vbox = new VBox(5);

		// content table section

		// ScrollPane scrollPane = new ScrollPane();
		// scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
		// scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);

		GridPane grid = new GridPane();
		grid.setVgap(5);
		grid.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);

		TableView<PWMGroupEntry> contentTableView = new TableView<PWMGroupEntry>(null);
		contentTableView.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
		contentTableView.getSelectionModel().setSelectionMode(
				SelectionMode.SINGLE);

		TableColumn<PWMGroupEntry, String> tcTitle = new TableColumn<PWMGroupEntry, String>(
				"Title");
		tcTitle.setPrefWidth(200);
		tcTitle.setCellValueFactory(new PropertyValueFactory<PWMGroupEntry, String>(
				"name"));
		TableColumn<PWMGroupEntry, String> tcUser = new TableColumn<PWMGroupEntry, String>(
				"Username");
		tcUser.setPrefWidth(200);
		tcUser.setCellValueFactory(new PropertyValueFactory<PWMGroupEntry, String>(
				"username"));
		TableColumn<PWMGroupEntry, String> tcURL = new TableColumn<PWMGroupEntry, String>(
				"URL");
		tcURL.setPrefWidth(250);
		tcURL.setCellValueFactory(new PropertyValueFactory<PWMGroupEntry, String>(
				"url"));
		TableColumn<PWMGroupEntry, String> tcDateAdd = new TableColumn<PWMGroupEntry, String>(
				"Date Added");
		tcDateAdd.setPrefWidth(150);
		tcDateAdd
				.setCellValueFactory(new PropertyValueFactory<PWMGroupEntry, String>(
						"dateAdded"));
		TableColumn<PWMGroupEntry, String> tcDateMod = new TableColumn<PWMGroupEntry, String>(
				"Date Modified");
		tcDateMod.setPrefWidth(150);
		tcDateMod
				.setCellValueFactory(new PropertyValueFactory<PWMGroupEntry, String>(
						"dateModified"));

		contentTableView.getColumns().add(tcTitle);
		contentTableView.getColumns().add(tcUser);
		contentTableView.getColumns().add(tcURL);
		contentTableView.getColumns().add(tcDateAdd);
		contentTableView.getColumns().add(tcDateMod);

		grid.add(contentTableView, 0, 0);

		GridPane.setHgrow(contentTableView, Priority.ALWAYS);
		GridPane.setVgrow(contentTableView, Priority.ALWAYS);

		// scrollPane.setContent(grid);

		TitledPane contentPane = new TitledPane();
		contentPane.setText("Entries");
		contentPane.setCollapsible(false);
		contentPane.setExpanded(true);
		contentPane.setMaxHeight(Double.MAX_VALUE);
		contentPane.setMinWidth(300);
		contentPane.setMinHeight(300);
		contentPane.setContent(grid);
		// contentPane.setContent(scrollPane);

		// content overview section

		GridPane grid2 = new GridPane();
		grid2.setPadding(new Insets(5, 5, 0, 5));
		grid2.setHgap(5);
		grid2.setVgap(5);

		Label lTitle = new Label("Title:");
		lTitle.setTextAlignment(TextAlignment.RIGHT);
		lTitle.getStyleClass().add("label");
		Label lUser = new Label("Username:");
		lUser.setTextAlignment(TextAlignment.RIGHT);
		Label lPass = new Label("Password:");
		lPass.setTextAlignment(TextAlignment.RIGHT);
		Label lURL = new Label("URL:");
		lURL.setTextAlignment(TextAlignment.RIGHT);
		Label lDateAdd = new Label("Date Added:");
		lDateAdd.setTextAlignment(TextAlignment.RIGHT);
		Label lDateMod = new Label("Date Modified:");
		lDateMod.setTextAlignment(TextAlignment.RIGHT);
		Label lDateExp = new Label("Expiration Date:");
		lDateExp.setTextAlignment(TextAlignment.RIGHT);
		Label lDesc = new Label("Description:");
		lDesc.setTextAlignment(TextAlignment.RIGHT);

		Text tTitle = new Text();
		Text tUser = new Text();
		Text tPass = new Text();
		Hyperlink hURL = new Hyperlink();
		Text tDateAdd = new Text();
		Text tDateMod = new Text();
		Text tDateExp = new Text();
		TextArea taDesc = new TextArea();
		taDesc.setId("ta-description");
		taDesc.setMinHeight(50);
		taDesc.setMaxHeight(50);

		grid2.addColumn(0, lTitle, lUser, lPass, lURL, lDesc);
		grid2.addColumn(1, tTitle, tUser, tPass, hURL, taDesc);
		grid2.addColumn(2, lDateAdd, lDateMod, lDateExp);
		grid2.addColumn(3, tDateAdd, tDateMod, tDateExp);

		GridPane.setHgrow(tTitle, Priority.ALWAYS);
		GridPane.setHgrow(tUser, Priority.ALWAYS);
		GridPane.setHgrow(tPass, Priority.ALWAYS);
		GridPane.setHgrow(hURL, Priority.ALWAYS);
		GridPane.setHgrow(taDesc, Priority.ALWAYS);
		GridPane.setHgrow(tDateAdd, Priority.ALWAYS);
		GridPane.setHgrow(tDateMod, Priority.ALWAYS);
		GridPane.setHgrow(tDateExp, Priority.ALWAYS);
		// GridPane.setVgrow(tfDesc, Priority.ALWAYS);
		GridPane.setColumnSpan(taDesc, 3);

		TitledPane contentOverviewPane = new TitledPane();
		contentOverviewPane.setText("Entry Overview");
		contentOverviewPane.setCollapsible(false);
		contentOverviewPane.setExpanded(true);
		contentOverviewPane.setContent(grid2);
		contentOverviewPane.setMinHeight(175);

		// add to vbox

		vbox.getChildren().add(contentPane);
		vbox.getChildren().add(contentOverviewPane);

		VBox.setVgrow(contentPane, Priority.ALWAYS);

		return vbox;
	}
}
```

edit2:
Nein. Am TableView bringt's nichts...


----------



## Paddelpirat (7. Jun 2012)

Zum Ausprobieren fehlt noch PWMGroupEntry...


----------



## dzim (7. Jun 2012)

Argh...

Entweder Suchen-und-Ersetzen durch String, oder:


```
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "entry", propOrder = { "username", "password", "url",
		"description" })
public class PWMGroupEntry {

	@XmlAttribute(name = "id", required = true)
	protected String id;
	@XmlAttribute(name = "name", required = true)
	protected String name;
	@XmlAttribute(name = "date-added", required = true)
	protected Calendar dateAdded;
	@XmlAttribute(name = "date-modified", required = true)
	protected Calendar dateModified;
	@XmlAttribute(name = "date-expiration", required = false)
	protected Calendar dateExpiration;

	@XmlElement(name = "username", required = true)
	protected String username;
	@XmlElement(name = "password", required = false)
	protected String password;
	@XmlElement(name = "url", required = false)
	protected String url;
	@XmlElement(name = "description", required = false)
	protected String description;

	public String getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

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

	public Calendar getDateAdded() {
		return dateAdded;
	}

	public void setDateAdded(Calendar dateAdded) {
		this.dateAdded = dateAdded;
	}

	public Calendar getDateModified() {
		return dateModified;
	}

	public void setDateModified(Calendar dateModified) {
		this.dateModified = dateModified;
	}

	public Calendar getDateExpiration() {
		return dateExpiration;
	}

	public void setDateExpiration(Calendar dateExpiration) {
		this.dateExpiration = dateExpiration;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getDescription() {
		return description;
	}

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


----------



## Paddelpirat (7. Jun 2012)

Hi,

habe mal ein bisschen was ausprobiert. Ist zwar noch nicht perfekt, aber ich hoffe es ist nun einigermaßen brauchbar:


```
public class Test extends Application {
 
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage primaryStage) {
 
        primaryStage.setTitle("");
 
        StackPane root = new StackPane();
 
        root.getChildren().add(createContentPane());
 
        Scene scene = new Scene(root, 1024, 800);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private Pane createContentPane() {
 
        VBox vbox = new VBox(5);
 
        // content table section
 
         ScrollPane scrollPane = new ScrollPane();
         scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
         scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
         scrollPane.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
 
 
        
        TableView<Integer> contentTableView = new TableView<Integer>(null);
        contentTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); //Neu
        
        contentTableView.getSelectionModel().setSelectionMode(
                SelectionMode.SINGLE);
 
        TableColumn<Integer, String> tcTitle = new TableColumn<Integer, String>(
                "Title");
        tcTitle.setPrefWidth(200);
        tcTitle.setCellValueFactory(new PropertyValueFactory<Integer, String>(
                "name"));
        TableColumn<Integer, String> tcUser = new TableColumn<Integer, String>(
                "Username");
        tcUser.setPrefWidth(200);
        tcUser.setCellValueFactory(new PropertyValueFactory<Integer, String>(
                "username"));
        TableColumn<Integer, String> tcURL = new TableColumn<Integer, String>(
                "URL");
        tcURL.setPrefWidth(250);
        tcURL.setCellValueFactory(new PropertyValueFactory<Integer, String>(
                "url"));
        TableColumn<Integer, String> tcDateAdd = new TableColumn<Integer, String>(
                "Date Added");
        tcDateAdd.setPrefWidth(150);
        tcDateAdd
                .setCellValueFactory(new PropertyValueFactory<Integer, String>(
                        "dateAdded"));
        TableColumn<Integer, String> tcDateMod = new TableColumn<Integer, String>(
                "Date Modified");
        tcDateMod.setPrefWidth(150);
        tcDateMod
                .setCellValueFactory(new PropertyValueFactory<Integer, String>(
                        "dateModified"));
 
        contentTableView.getColumns().add(tcTitle);
        contentTableView.getColumns().add(tcUser);
        contentTableView.getColumns().add(tcURL);
        contentTableView.getColumns().add(tcDateAdd);
        contentTableView.getColumns().add(tcDateMod);
        
        contentTableView.setMinSize(TableView.USE_PREF_SIZE, TableView.USE_PREF_SIZE); //Neu
        
 
        scrollPane.setContent(contentTableView);
        scrollPane.setFitToWidth(true); //Neu
        scrollPane.setFitToHeight(true); //Neu
 
        TitledPane contentPane = new TitledPane();
        contentPane.setText("Entries");
        contentPane.setCollapsible(false);
        contentPane.setExpanded(true);
        contentPane.setMaxHeight(Double.MAX_VALUE);
        contentPane.setMaxWidth(Double.MAX_VALUE);
        contentPane.setMinWidth(300);
        contentPane.setMinHeight(300);
        contentPane.setContent(scrollPane);
 
        // content overview section
 
        GridPane grid2 = new GridPane();
        grid2.setPadding(new Insets(5, 5, 0, 5));
        grid2.setHgap(5);
        grid2.setVgap(5);
 
        Label lTitle = new Label("Title:");
        lTitle.setTextAlignment(TextAlignment.RIGHT);
        lTitle.getStyleClass().add("label");
        Label lUser = new Label("Username:");
        lUser.setTextAlignment(TextAlignment.RIGHT);
        Label lPass = new Label("Password:");
        lPass.setTextAlignment(TextAlignment.RIGHT);
        Label lURL = new Label("URL:");
        lURL.setTextAlignment(TextAlignment.RIGHT);
        Label lDateAdd = new Label("Date Added:");
        lDateAdd.setTextAlignment(TextAlignment.RIGHT);
        Label lDateMod = new Label("Date Modified:");
        lDateMod.setTextAlignment(TextAlignment.RIGHT);
        Label lDateExp = new Label("Expiration Date:");
        lDateExp.setTextAlignment(TextAlignment.RIGHT);
        Label lDesc = new Label("Description:");
        lDesc.setTextAlignment(TextAlignment.RIGHT);
 
        Text tTitle = new Text();
        Text tUser = new Text();
        Text tPass = new Text();
        Hyperlink hURL = new Hyperlink();
        Text tDateAdd = new Text();
        Text tDateMod = new Text();
        Text tDateExp = new Text();
        TextArea taDesc = new TextArea();
        taDesc.setId("ta-description");
        taDesc.setMinHeight(50);
        taDesc.setMaxHeight(50);
 
        grid2.addColumn(0, lTitle, lUser, lPass, lURL, lDesc);
        grid2.addColumn(1, tTitle, tUser, tPass, hURL, taDesc);
        grid2.addColumn(2, lDateAdd, lDateMod, lDateExp);
        grid2.addColumn(3, tDateAdd, tDateMod, tDateExp);
 
        GridPane.setHgrow(tTitle, Priority.ALWAYS);
        GridPane.setHgrow(tUser, Priority.ALWAYS);
        GridPane.setHgrow(tPass, Priority.ALWAYS);
        GridPane.setHgrow(hURL, Priority.ALWAYS);
        GridPane.setHgrow(taDesc, Priority.ALWAYS);
        GridPane.setHgrow(tDateAdd, Priority.ALWAYS);
        GridPane.setHgrow(tDateMod, Priority.ALWAYS);
        GridPane.setHgrow(tDateExp, Priority.ALWAYS);
        // GridPane.setVgrow(tfDesc, Priority.ALWAYS);
        GridPane.setColumnSpan(taDesc, 3);
 
        TitledPane contentOverviewPane = new TitledPane();
        contentOverviewPane.setText("Entry Overview");
        contentOverviewPane.setCollapsible(false);
        contentOverviewPane.setExpanded(true);
        contentOverviewPane.setContent(grid2);
        contentOverviewPane.setMinHeight(175);
 
        // add to vbox
 
        vbox.getChildren().add(contentPane);
        vbox.getChildren().add(contentOverviewPane);
 
        VBox.setVgrow(contentPane, Priority.ALWAYS);
 
        return vbox;
    }
}
```


----------



## dzim (8. Jun 2012)

Sieht doch gar nicht so schlecht aus!
Einzig die Performace auf Linux scheint noch etwas unterirdisch zu sein :-/ Das Scollen zieht mitunter ganz schön hinterher...

Danke aber für die Hilfe!!!


----------



## Paddelpirat (8. Jun 2012)

Eventuell mal Grafikkartentreiber aktualisieren? Habe aber selbst noch nicht JavaFX 2 unter Linux ausprobiert. Teste nur immer schön auf meinem Notebook mit zwei Grafikchips. Auf dem Onboard-Chip ruckelt es gerne mal auf der dedizierten Grafikkarte ist alles flüssig. Wobei mein Programm an dem ich da werkel immer gleich ein paar tausend Objekte zeichnet und ich da so Funktionen wie Zoomen und Verschieben benutze. Dass eine einfache Tabelle ruckelt wundert mich schon etwas.


----------



## dzim (12. Jun 2012)

ich hab nen L520 von Arbeit, auf dem ich herumspielen darf  Der hat nur nen Intel-Chip - also Performance darf man hier nicht unbedingt erwarten, aber normalerweise reicht es. Da der Treiber für Intel-GraKa im Kernel ist und ich Ubuntu 12.04 verwende, sollte der neu genug sein.

Aber ich denke tatsächlich, das die Entwicklung von JavaFX auf Linux Windows noch mächtig hinterher hinkt. Aber auch Mac... Leider :-/


----------



## Paddelpirat (12. Jun 2012)

Hatte gerade nochmal eine Idee wie man das Ergebnis für die Table verbessern könnte. Das Resultat gefällt mir eigentlich, allerdings gefällt mir die Art und Weise "wie" ich das erreicht habe noch nicht ganz. Aber vielleicht hast du da noch eine bessere Lösung für. Die Hauptänderung ist die Benutzung eines MapChangeListener und natürlich der default ColumnResizePolicy.


```
public class Test extends Application {
 
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage primaryStage) {
 
        primaryStage.setTitle("");
 
        StackPane root = new StackPane();
 
        root.getChildren().add(createContentPane());
 
        Scene scene = new Scene(root, 1024, 800);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private Pane createContentPane() {
 
        VBox vbox = new VBox(5);
 
        // content table section
 
         ScrollPane scrollPane = new ScrollPane();
         scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
         scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
         scrollPane.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
 
 
        
        final TableView<Integer> contentTableView = new TableView<Integer>(null);
        
        //contentTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); //Neu
        
        contentTableView.getSelectionModel().setSelectionMode(
                SelectionMode.SINGLE);
 
        final TableColumn<Integer, String> tcTitle = new TableColumn<Integer, String>(
                "Title");
        tcTitle.setPrefWidth(200);
        tcTitle.setCellValueFactory(new PropertyValueFactory<Integer, String>(
                "name"));
        TableColumn<Integer, String> tcUser = new TableColumn<Integer, String>(
                "Username");
        tcUser.setPrefWidth(200);
        tcUser.setCellValueFactory(new PropertyValueFactory<Integer, String>(
                "username"));
        TableColumn<Integer, String> tcURL = new TableColumn<Integer, String>(
                "URL");
        tcURL.setPrefWidth(250);
        tcURL.setCellValueFactory(new PropertyValueFactory<Integer, String>(
                "url"));
        final TableColumn<Integer, String> tcDateAdd = new TableColumn<Integer, String>(
                "Date Added");
        tcDateAdd.setPrefWidth(150);
        tcDateAdd
                .setCellValueFactory(new PropertyValueFactory<Integer, String>(
                        "dateAdded"));
        TableColumn<Integer, String> tcDateMod = new TableColumn<Integer, String>(
                "Date Modified");
        tcDateMod.setPrefWidth(150);
        tcDateMod
                .setCellValueFactory(new PropertyValueFactory<Integer, String>(
                        "dateModified"));

        contentTableView.getProperties().addListener(new MapChangeListener() {

            @Override
            public void onChanged(Change arg0) {
                double width = 0;
                for(int i=0; i<contentTableView.getColumns().size(); i++) {
                    width += ((TableColumn)contentTableView.getColumns().get(i)).getWidth();
                }
                
                contentTableView.setPrefWidth(width);
                //System.out.println(width);
            }
            
        });
 
        contentTableView.getColumns().add(tcTitle);
        contentTableView.getColumns().add(tcUser);
        contentTableView.getColumns().add(tcURL);
        contentTableView.getColumns().add(tcDateAdd);
        contentTableView.getColumns().add(tcDateMod);
        
        contentTableView.setMinSize(TableView.USE_PREF_SIZE, TableView.USE_PREF_SIZE); //Neu
        
 
        scrollPane.setContent(contentTableView);
        scrollPane.setFitToWidth(true); //Neu
        scrollPane.setFitToHeight(true); //Neu
 
        TitledPane contentPane = new TitledPane();
        contentPane.setText("Entries");
        contentPane.setCollapsible(false);
        contentPane.setExpanded(true);
        contentPane.setMaxHeight(Double.MAX_VALUE);
        contentPane.setMaxWidth(Double.MAX_VALUE);
        contentPane.setMinWidth(300);
        contentPane.setMinHeight(300);
        contentPane.setContent(scrollPane);
 
        // content overview section
 
        GridPane grid2 = new GridPane();
        grid2.setPadding(new Insets(5, 5, 0, 5));
        grid2.setHgap(5);
        grid2.setVgap(5);
 
        Label lTitle = new Label("Title:");
        lTitle.setTextAlignment(TextAlignment.RIGHT);
        lTitle.getStyleClass().add("label");
        Label lUser = new Label("Username:");
        lUser.setTextAlignment(TextAlignment.RIGHT);
        Label lPass = new Label("Password:");
        lPass.setTextAlignment(TextAlignment.RIGHT);
        Label lURL = new Label("URL:");
        lURL.setTextAlignment(TextAlignment.RIGHT);
        Label lDateAdd = new Label("Date Added:");
        lDateAdd.setTextAlignment(TextAlignment.RIGHT);
        Label lDateMod = new Label("Date Modified:");
        lDateMod.setTextAlignment(TextAlignment.RIGHT);
        Label lDateExp = new Label("Expiration Date:");
        lDateExp.setTextAlignment(TextAlignment.RIGHT);
        Label lDesc = new Label("Description:");
        lDesc.setTextAlignment(TextAlignment.RIGHT);
 
        Text tTitle = new Text();
        Text tUser = new Text();
        Text tPass = new Text();
        Hyperlink hURL = new Hyperlink();
        Text tDateAdd = new Text();
        Text tDateMod = new Text();
        Text tDateExp = new Text();
        TextArea taDesc = new TextArea();
        taDesc.setId("ta-description");
        taDesc.setMinHeight(50);
        taDesc.setMaxHeight(50);
 
        grid2.addColumn(0, lTitle, lUser, lPass, lURL, lDesc);
        grid2.addColumn(1, tTitle, tUser, tPass, hURL, taDesc);
        grid2.addColumn(2, lDateAdd, lDateMod, lDateExp);
        grid2.addColumn(3, tDateAdd, tDateMod, tDateExp);
 
        GridPane.setHgrow(tTitle, Priority.ALWAYS);
        GridPane.setHgrow(tUser, Priority.ALWAYS);
        GridPane.setHgrow(tPass, Priority.ALWAYS);
        GridPane.setHgrow(hURL, Priority.ALWAYS);
        GridPane.setHgrow(taDesc, Priority.ALWAYS);
        GridPane.setHgrow(tDateAdd, Priority.ALWAYS);
        GridPane.setHgrow(tDateMod, Priority.ALWAYS);
        GridPane.setHgrow(tDateExp, Priority.ALWAYS);
        // GridPane.setVgrow(tfDesc, Priority.ALWAYS);
        GridPane.setColumnSpan(taDesc, 3);
 
        TitledPane contentOverviewPane = new TitledPane();
        contentOverviewPane.setText("Entry Overview");
        contentOverviewPane.setCollapsible(false);
        contentOverviewPane.setExpanded(true);
        contentOverviewPane.setContent(grid2);
        contentOverviewPane.setMinHeight(175);
 
        // add to vbox
 
        vbox.getChildren().add(contentPane);
        vbox.getChildren().add(contentOverviewPane);
 
        VBox.setVgrow(contentPane, Priority.ALWAYS);
 
        return vbox;
    }
}
```


----------



## dzim (13. Jun 2012)

Hehe, ist doch cool! ;-)

Ich bin selbst noch nie auf den Gedanken gekommen, das per Listener zu machen, hab aber mal vor kurzem ne Implementierung einer Auto-Resize-Funktion für TableColumns in nem Blog gesehen. Da war das auch so gelöst.
Wenn's funktioniert, hat es doch seine Daseinsberechtigung, oder? :-D

Prinzipiell aber bin ich soweit erst einmal zufrieden. Ich werde vermutlich nur irgendwann das ganze auf FXML umstellen, da ich den deklarativen Ansatz etwas cleverer finde.


----------

