Möchte Android-ähnlich programmieren

top_chief

Mitglied
Hallo,
gerade stellen sich mir wieder ein paar Fragen, wäre super wenn ihr mir weiterhelfen könntet.
Dadurch, dass ich schon mehr oder weniger Erfahrung mit Android habe, ist mir der Einstieg in JavaFx nicht ganz so schwer gefallen (wobei ich dazu sagen muss, dass es wirklich um den "Einstieg" handelt und nicht um "sich auskennen"). Egal..
Gerade stellen sich mir folgende Fragen:

-Wie lassen sich Einstellungen implementieren? Dabei geht es mir mehr um die UI, als um die Speicherung (oder das Konzept dahinter) als solches. In Android gibt es wie eine Art vorgefertigtes Layout-Muster (kennt wahrscheinlich schon fast jeder), das die UI so formt, dass der Nutzer ein immer konsistentes Einstellungsmenü vor sich hat. Gibt es sowas in JavaFx auch, oder muss ich die Einstellung, wie das restliche Programm, "eigenhändig" mit dem SceneBuilder bauen?

-Wie stellt ihr "Toasts" (diese kleinen Pop-Ups mit kurzen Text-Infos zB "Daten übernommen") dar? Jedes Mal einen Dialog anzuzeigen fände ich ein bisschen umständlich, da der Nutzer das dann immer quittieren muss "OK", oder? Den über eine Runnable laufen zu lassen empfinde ich auch nicht unbedingt als das gelbe vom Ei. Laut dieser Aussage gibt es wohl eine Drittanbieter Lib dazu, aber keine JavaFx-Bordmittel, stimmt das?

-Da ich im Hintergrund Daten laden möchte, würde ich gerne wie eine Art Progress-Bar anzeigen, die den aktuellen Status anzeigt und die Anwendung im Hintergrund sperrt. Habt ihr hierzu einen Tipp, wie man das möglichst hübsch lösen kann?

Mehr fällt mir gerade nicht ein - generell fände ich eine Art Übersicht "Android vs. JavaFx - Codegegenüberstellung" interessant und auch wahrscheinlich auch hilfreich. Wäre doch mal eine Idee für eine App :D Was meint ihr? Ist das überhaupt umsetzbar? Aktuell erkenne ich schon einige Konzepte wieder, aber bin auch teilweise doch über die Unterschiede verwundert, deswegen bin ich mir nicht wirklich schlüssig wie sinnvoll eine solche Gegenüberstellung ist. Was haltet ihr vor der Idee generell? Aus dem Bauch heraus würde ich sagen, dass ich nicht der einzige bin, den eine solche Übersicht / Gegenüberstellung interessiert..

Danke vorab und beste Grüße
Martin
 

dzim

Top Contributor
Nun ja. Entweder du nimmst eine Bibliothek, wie die im Link (ControlsFX ist dabei schon ziemlich ausgereift), oder du implementierst es selbst. Kannst ja mit StackPane arbeiten, bei denen du einfach einen kleinen Container von unten hochanimierst, oder den Alpha-Wert animierst.
(Struktur z.B. StackPane als Parent, dann full-width/-height und zentrierten Hauptinhalt und bei Bedarf eine weitere Toast VBox oder so, deren Anker Bottom ist... In etwa klar, was ich meine?)

Beispiel FXML.
HTML:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 
	Do not edit this file it is generated by e(fx)clipse from ../src/ch/cnlab/performanceapplet/fx/ui/layout/Toast.fxgraph
-->

<?import java.lang.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>

<BorderPane xmlns:fx="http://javafx.com/fxml" style="-fx-background-color: lightblue;">

	<top>
		<ToolBar> 
			<Button text="option1"/> 
		</ToolBar>
	</top>
	<center>
		<StackPane> 
			<ScrollPane style="-fx-border-color: green;" StackPane.alignment="CENTER"> 
				<maxWidth><Double fx:constant="MAX_VALUE" /></maxWidth>
				<maxHeight><Double fx:constant="MAX_VALUE" /></maxHeight>
				<content>
					<VBox spacing="10"> 
						<Button text="test1"/> 
						<Button text="test2"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
						<Button text="test3"/> 
					</VBox>
				</content>
			</ScrollPane>
			<BorderPane fx:id="optionsPane" style="-fx-border-color: red;" maxHeight="25" maxWidth="250" StackPane.alignment="BOTTOM_CENTER"> 
				<bottom>
					<VBox alignment="BOTTOM_CENTER"> 
						<Label text="TOAST"/> 
					</VBox>
				</bottom>
				<StackPane.margin>
					<Insets bottom="10"/> 
				</StackPane.margin>
			</BorderPane>
		</StackPane>
	</center>
</BorderPane>

Ich selbst habe so in einem - hüstel - Applet auch schon Dialoge oder einen NavigationDrawer (siehe Android) gefakt... Geht alles. JavaFX bietet einem da viele Freiheiten.
 

top_chief

Mitglied
Wow, das sieht richtig gut aus. Vielen lieben Dank für das kleine Beispiel, es hat mir unglaublich weiter geholfen, da mir der "StackPane-Mechanismus" (also das Scrollen bei "fixem" Toast im BorderPane-Bottom) nicht wirklich klar war. Super nett von dir :)
 

dzim

Top Contributor
Ach so noch eine Anmerkung. Während es beim "translaten" (also dem verschieben der Box z.B. in den nicht sichtbaren Bereich ausserhalb des Fensters) keine Probleme geben sollte, wird ein herausgefadetes Element immer noch im Layout berücksichtigt (nur weil du es nicht sehen kannst, heisst es nicht, dass es nicht da ist... Fast wie mit Dunkler Materie :) ). Du musst in dem Fall entweder visible und managed am Ende der Animation auf false setzen, oder per #toBack im Layout nach hinten schieben (ich beziehe beide Aussagen auf BorderPane).

#edit: Und vergiss nicht, die maxWidth und maxHeight zu setzen (evtl. dynamisch, abhängig vom Content der BorderPane), sonst sieht es am Ende wieder unschön aus.
 
Zuletzt bearbeitet:

Tom299

Bekanntes Mitglied
Ich verstehe nicht, wo das Problem liegen soll, einen Dialog anzuzeigen. Was soll denn ein Toast sonst sein? Bei Android wurde der Dialog halt schon mitgegeben und man kann ihn einfach nutzen. Gegen selbst entwickeln spricht doch nix, das sind wir doch bei Java gewohnt ;-)

Mit einem Runnable kann man den Dialog auch problemlos schließen lassen, da spricht auch nix dagegen. Habs grad mal ausprobiert (btn1 ist der OK-Button auf meinem Dialog):
Code:
	@Override
	public void initialize(URL location, ResourceBundle resources) {
		txtMessage.setText("Message-Text");
		
		Runnable autoClose = new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(3000);
					btn1.fire();
				}
				catch (InterruptedException iex) {
					
				}
				
			}
		};
		
		Platform.runLater(autoClose);
	}

Eine Animation sieht natürlich schicker aus. Ich überlege derzeit auch, meine Status-Bar-Anzeige gegen ein Toast zu tauschen. Ich hab aber auch Probleme mit dem fade-out und fade-in und daß immer der richtige Text da steht. Aber wenn man mal gemerkt hat, daß die Zeitangaben immer absolut und nicht relativ zur Zeit davor sind, wirds verständlicher :D

Mir würde es auch gefallen, wenn z.B. der ganze Screen der Anwendung so eine verschwommene Glasfront bekäme, bis die Daten geladen sind und falls ein Fehler auftaucht gibts nen Riß in der Scheibe oder so :D Muß mal bischen rumprobieren, ob ich da was hinbekomme.
 

dzim

Top Contributor
Ein Toast ist halt kein Dialog. Android verfolgt seit 5.0 da zwar keine so ganz eindeutige Strategie mehr (genauso wie Material Design von jedem App-Team anscheinend auch anders interpretiert wied *würg*), aber vom ursprünglichen Toast ausgehend, erlaubt dieser eigentlich keine Interaktion. Er zeigt eine Meldung und veschwindet unabhäng von dem, was der Nutzer tut, nach einer gewissen Zeit wieder.
(Wie gesagt: diese komischen "Toasts" die z.B. beim Löschen von Mails kommen - "Rückgangig machen" - zähle ich nicht mehr zu echten Toast...)

Egal. Dein Wunsch mit einem "Milchglass"-Hintergrund ist nicht sooo schwer, aber schon etwas frickelig.
Ich hab das mal in einer Test-Anwendung so hier gemacht:

FXML
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 
	Do not edit this file it is generated by e(fx)clipse from ../src/main/resources/eu/dzim/broetli/res/layout/Edit.fxgraph
-->

<?import java.lang.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.effect.BoxBlur?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?scenebuilder-stylesheet ../application.css?>

<StackPane xmlns:fx="http://javafx.com/fxml" fx:controller="eu.dzim.broetli.ui.EditController">

	<StackPane fx:id="background"> 
		<ImageView fx:id="imageViewBackground"> 
			<effect>
				<BoxBlur width="5" height="5" iterations="3"/> 
			</effect>
		</ImageView>
	</StackPane>
	<VBox fx:id="content" maxHeight="100" alignment="TOP_CENTER" StackPane.alignment="TOP_CENTER"> 
		<Region VBox.vgrow="ALWAYS"/> 
		<styleClass>
			<String fx:value="dialog-content" />
		</styleClass>
		<StackPane.margin>
			<Insets top="15" left="15" right="15"/> 
		</StackPane.margin>
	</VBox>
</StackPane>
(lösche am Besten die CSS wieder raus... brauchst du erst mal nicht.)

Controller
Java:
	@FXML
	private StackPane background;
	@FXML
	private ImageView imageViewBackground;
	@FXML
	private VBox content;
	// ...
	
	// ...
		if (imageViewBackground != null) {
			// parentContainer ist derjenige, von dem du den Snapshot brauchst
			// der Glass-Effekt kommt durch das in FXML festgelegte BoxBlur (kannst auch andere nehmen, ich fand den aber gut)
			SnapshotParameters params = new SnapshotParameters();
			WritableImage img = parentContainer.snapshot(params, null);
			imageViewBackground.setImage(img);
		}
	// ...

Den "Bruch" im Glass würde ich an deiner Stelle mit einem zweiten, gleich grossen ImageView machen, in dem du ein SVG mit dem Effekt und ansonsten reiner Transparenz ringsherum darüber legst...
 
Zuletzt bearbeitet:

Tom299

Bekanntes Mitglied
Ich hab da gestern auch was hinbekommen, das mit dem Riß im Glas oder so hab ich aber weg gelassen, ist zu viel Spielerei. Hab meinen normalen Layouts als Parent noch ne Stackpane verpaßt, damit kann ich über das normale Layout dann einfach eine Pane mit grauen Background und Opacity 0.5 - 0.6 drüberlegen und dann darüber z.b. ein kleines BorderLayout mit ProgressIndicator + Label.

So kann ich die GUI für den Benutzer sichtlich "sperren", bis z.B. die Datenbankabfrage gemacht und die Listen gefüllt wurden. Gefällt mir eigentlich ganz gut.

Ich überlege nun, ob ich die StackPane, die ich quasi für alle Layouts als Parent brauche, vielleicht im Code erzeuge, sodaß man in den normalen FXML-Layouts mit den "Standard-Panes" beginnt und nicht immer die StackPane als Parent nehmen muß. Das muß ich aber noch austesten.

Trotzdem danke für die Code-Beispiele, meine sind sicher ähnlich und vielleicht kanns auch jemand brauchen:

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

<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<StackPane id="ctrlSplash" fx:id="ctrlSplash" minHeight="60.0" minWidth="80.0" onMousePressed="#MousePressed" stylesheets="@styles/splash.css" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.test..DialogSplashController">
   <children>
      <BorderPane id="ctrlLockScreen" fx:id="ctrlLockScreen">
      </BorderPane>
      <BorderPane id="ctrlProgressScreen" fx:id="ctrlProgressScreen" maxHeight="124.0" maxWidth="170.0" minHeight="124.0" minWidth="170.0" prefHeight="124.0" prefWidth="170.0">
         <center>
            <VBox fx:id="vbox" alignment="CENTER" maxHeight="114.0" maxWidth="160.0" minHeight="114.0" minWidth="160.0" prefHeight="114.0" prefWidth="160.0" BorderPane.alignment="CENTER">
               <children>
                  <ProgressIndicator maxHeight="56.0" maxWidth="160.0" minHeight="56.0" minWidth="160.0" prefHeight="56.0" prefWidth="160.0" />
                  <Label id="lblMessage" fx:id="lblMessage" text="Bitte warten ...">
                     <font>
                        <Font name="System Bold" size="14.0" />
                     </font>
                     <VBox.margin>
                        <Insets top="10.0" />
                     </VBox.margin>
                  </Label>
               </children>
            </VBox>
         </center>
      </BorderPane>      
   </children>
</StackPane>

CSS:
Code:
.root {
	-fx-background-color: transparent;
}

#ctrlLockScreen {
	-fx-background-color: #c6c4c4;
	-fx-opacity: 0.5;
}

#ctrlProgressScreen {
	-fx-background-color: #c6c4c4;
	-fx-opacity: 1.0;
}

Achja, ich hatte das ganze zuerst mit einem Dialog sprich eigener Stage gemacht und dann den Dialog genau über die App gelegt. Ist etwas umständlich, deswegen hab ich dann die StackPane für mein Test-Layout eingeführt, da kann ich dann meinen LockScreen und den ProgressScreen einfach drüberlegen ohne einen Dialog/Stage zu erzeugen und zu öffnen. Das ist praktischer und man spart auch das ganze resize und setX setY usw. ... :)
 

top_chief

Mitglied
Ihr seid echt klasse, jetzt habe ich heute Abend einiges zu tun und auszuprobieren UND wieder eine Reihe neuer Ideen. Vielen Dank dafür :) Ergebnisse poste ich sobald ich etwas Ansehnliches hinbekommen habe.

Beste Grüße
Martin
 

Ähnliche Java Themen

Neue Themen


Oben