Ich entdeckte gerade JavaFX und ich mochte es wirklich. Ich hasse Java-Standard-GUI, also habe ich sofort entschieden, mein Fenster zu personalisieren. Ich hatte zahlreiche Versuche, aber ich habe eine große Einschränkung und ein großes Ziel; Einschränkung? Ich muss MVC-Muster verwenden. Zielsetzung? Machen Sie das benutzerdefinierte Fenster wiederverwendbar.JavaFX - einfache benutzerdefinierte minimale Fensterimplementierung
So ... Dies ist der Punkt, den ich jetzt habe: wstaw.org/m/2016/04/07/resoruces.png
ich einen allgemeines Paket Antrag gestellt, die App.java enthält, dass Wille Starten Sie die App. Dann mache ich ein weiteres internes Paket, das die "MinimalWindow" -Logik enthält, mit allen Resorucen, die ich brauche.
implementiert ich diesen FXML Code aus dem Fenster auszuführen:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.control.Label?>
<StackPane fx:id="minimalWindowShadowContainer" id="minimalWindowShadowContainer" stylesheets="@style.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" onMousePressed="#updateXY" onMouseDragged="#windowDragging" onMouseReleased="#updateStatus" >
<BorderPane fx:id="minimalWindowContainer" id="minimalWindowContainer">
<!-- This padding will create the dropshadow effect for the window behind -->
<padding>
<Insets top="5" right="5" bottom="5" left="5"/>
</padding>
<!-- "Title Bar" -->
<top>
<HBox id="titleBar" alignment="CENTER" spacing="5" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="30.0" prefWidth="600.0">
<padding>
<Insets top="5" right="5" bottom="5" left="5"/>
</padding>
<ImageView fx:id="logo" fitWidth="20" fitHeight="20"></ImageView>
<Label fx:id="lblTitle" id="title" text="MinimalWindow"></Label>
<Region HBox.hgrow="ALWAYS" prefHeight="30.0" prefWidth="200.0"></Region>
<HBox alignment="CENTER_RIGHT">
<Button id="btnMin" onMouseClicked="#minimizeApp" minHeight="20" minWidth="20" maxHeight="20" maxWidth="20"></Button>
<Button fx:id="btnMax" id="btnMax" onMouseClicked="#maximizeApp" minHeight="20" minWidth="20" maxHeight="20" maxWidth="20"></Button>
<Button id="btnCls" onMouseClicked="#closeApp" minHeight="20" minWidth="20" maxHeight="20" maxWidth="20"></Button>
</HBox>
</HBox>
</top>
<!-- The content of the window will go here -->
<center>
<StackPane fx:id="contentArea" id="contentArea"></StackPane>
</center>
<!-- Footer -->
<bottom>
<HBox id="footer">
<padding>
<Insets top="5" right="5" bottom="5" left="5"/>
</padding>
<Button fx:id="btnResize" id="btnResize" alignment="BOTTOM_RIGHT" onMouseClicked="#updateXY" onMouseEntered="#setMouseCursor" onMouseExited="#resetMouseCursor" onMouseDragged="#resizeWindow" minHeight="10" minWidth="10" maxHeight="10" maxWidth="10"></Button>
</HBox>
</bottom>
</BorderPane>
</StackPane>
ich dann die Controller-Klasse implementiert:
package application.minimalWindow;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class MinimalWindow extends Application {
@FXML
Label lblTitle;
@FXML
Button btnMax, btnResize;
@FXML
StackPane minimalWindowShadowContainer, minimalWindowContainer,contentArea;
@FXML
Double SHADOW_SPACE;
final private static int MIN_WIDTH = 730, MIN_HEIGHT = 500;
private double actualX, actualY;
private boolean isMovable;
private String source, title;
private Stage mainStage;
//
// Public logic of the class
//
public MinimalWindow() {
//TODO must work...
}
//Show the window
public void show() {
mainStage.show();
}
//
// MIMIZIE | MAXIMIZE | CLOSE
//
//When pressed, will minimize the window to tray
@FXML
private void minimizeApp(MouseEvent e) {
mainStage.setIconified(true);
}
//When pressed, check if it must maximize or restore the window
@FXML
private void maximizeApp(MouseEvent e) {
if (mainStage.isMaximized()) {
setMin();
isMovable = true;
}
else {
setMax();
isMovable = false;
}
}
//When pressed, will kill the window
@FXML
private void closeApp(MouseEvent e) {
mainStage.close();
System.exit(0);
}
//
// WINDOW MOVING
//
//When i must update the XY of the click
@FXML
private void updateXY(MouseEvent e){
actualX = e.getScreenX() - mainStage.getX();
actualY = e.getScreenY() - mainStage.getY();
}
//When pressing and dragging the mouse it will move the window
@FXML
private void windowDragging(MouseEvent e) {
if (isMovable) {
mainStage.setX(e.getScreenX() - actualX);
mainStage.setY(e.getScreenY() - actualY);
}
else {
//setMin();
mainStage.setX(e.getScreenX());
mainStage.setY(e.getScreenY());
}
}
//Update the status of the window from not movable to movable, after "normalize" effect
//from the dragging it when it's maximized
@FXML
private void updateStatus(MouseEvent e) {
if (mainStage.isMaximized() == false) {
isMovable = true;
}
}
//
// WINDOW RESIZING
//
/*onMouseEntered="#setMouseCursor" onMouseExited="#resetMouseCursor" onMouseDragged="#resizeWindow"*/
@FXML
private void setMouseCursor (MouseEvent e) {
minimalWindowContainer.setCursor(Cursor.CROSSHAIR);
}
@FXML
private void resetMouseCursor (MouseEvent e) {
minimalWindowContainer.setCursor(Cursor.DEFAULT);
}
@FXML
private void resizeWindow (MouseEvent e) {
actualX = e.getScreenX() - mainStage.getX() + 13;
actualY = e.getScreenY() - mainStage.getY() + 10;
if (actualX % 5 == 0 || actualY % 5 == 0) {
if (actualX > MIN_WIDTH) {
mainStage.setWidth(actualX);
} else {
mainStage.setWidth(MIN_WIDTH);
}
if (actualY > MIN_HEIGHT) {
mainStage.setHeight(actualY);
} else {
mainStage.setHeight(MIN_HEIGHT);
}
}
}
//
// Internal methods
//
//Will set the window to MAXIMIZE size
private void setMax() {
mainStage.setMaximized(true);
btnResize.setVisible(false);
btnMax.setStyle("-fx-background-image: url('/res/dSquare.png');");
minimalWindowContainer.setPadding(new Insets(0, 0, 0, 0));
}
//Will set the window to NORMAL size
private void setMin() {
mainStage.setMaximized(false);
btnResize.setVisible(true);
btnMax.setStyle("-fx-background-image: url('/res/square.png');");
minimalWindowContainer.setPadding(new Insets(SHADOW_SPACE, SHADOW_SPACE, SHADOW_SPACE, SHADOW_SPACE));
}
@Override
public void start(Stage primaryStage) {
/* //NOT SURE IF DOING RIGHT YA'
try {
//Prepare the resource with the FXML file
FXMLLoader loader = new FXMLLoader(getClass().getResource("/application/minimalWindow/MainWindow.fxml"));
//Load the main stackpane
Parent root = loader.load();
loader.setController(this);
//Prepare the content of the window, with a minWidth/Height
Scene scene = new Scene(root, MIN_WIDTH, MIN_HEIGHT);
//Making the scene transparent
scene.setFill(Color.TRANSPARENT);
//Undecorate the window due its persolalisation
primaryStage.initStyle(StageStyle.TRANSPARENT);
//Set the content of the window
primaryStage.setScene(scene); *
}
catch (Exception e) {
e.printStackTrace();
} */
}
und die CSS-Styling:
* {
/* Some general colors */
primaryColor: #f9f9f9;
secondaryColor: derive(primaryColor, -75%);
textColor: white;
closeBtnColor: red;
}
#titleBar, #footer {
-fx-background-color: secondaryColor;
}
#title {
-fx-text-fill: textColor;
}
#contentArea {
-fx-background-color: primaryColor;
}
#minimalWindowShadowContainer {
-fx-background-color: transparent;
-fx-effect: dropshadow(gaussian , black , 5,0,0,0);
-fx-background-insets: 5;
}
#btnCls, #btnMax, #btnMin, #btnResize {
-fx-background-color: transparent;
-fx-background-radius: 0;
-fx-border-color: transparent;
-fx-border-width: 0;
-fx-background-position: center;
-fx-background-repeat: stretch;
}
#btnMax:hover, #btnMin:hover {
-fx-background-color: derive(secondaryColor, 20%);
}
#btnCls:hover {
-fx-background-color: derive(red, 45%);
}
#btnCls {
-fx-background-image: url('/res/x.png');
}
#btnMax {
-fx-background-image: url('/res/square.png');
}
#btnMin {
-fx-background-image: url('/res/line.png');
}
#btnResize {
-fx-background-image: url('/res/resize.png');
}
In der App.java sollte ich so verwenden:
Ich poste dies meine Lösung hier becouse im Internet fand ich genau NICHTS über benutzerdefinierte Styling in MVC Muster (ja ... Ich muss es für das Prüfungsprojekt tun).
Was sind die Probleme? Es muss einfach zu verwenden und wiederverwendbar sein. Der Versuch, den Konstruktor wie folgt zu machen:
public MinimalWindow(String title, String source) {
this.title = title;
this.source = source;
start(mainStage);
}
es gibt mir Fehler in XAML-Datei in der 11 Reihe Parsen (die erste Zeile, die die Stackpanel definieren), oder geben Sie mir einen Fehler „Verursacht durch: java.lang. IllegalStateException: Toolkit nicht initialisiert ". Zum ersten, ich weiß nicht, was es verursacht. Für die zweite schlägt die Lösung im Internet vor, meine Klasse von Application zu erweitern und dann die "Start" -Methode zu überschreiben, aber es hat nicht funktioniert.
Fragestunde: irgendeine Lösung? Vorschläge?
PS: Ich mache Arbeit dieses Code in einem nicht-MVC-Muster, mit einem anderen Stil, und es funktionierte großartig: wstaw.org/m/2016/04/07/ezgif.com-crop.gif
@James_D scheint zu verstehen, was Sie achive wollen. Ich bin mir nicht 100% sicher. Wenn es um benutzerdefinierte Fensterdekorationen geht, können Sie sich einen Blick darauf werfen, indem Sie den Code von Undecorator überprüfen - eine Lib, die es schon seit einiger Zeit gibt. Vielleicht hilft das: [Undecorator @ Github] (https://github.com/in-sideFX/Undecorator) – dzim
Undercoator ist sehr problematisch, und ich bevorzuge es für mich selbst zu tun, weil ich wissen muss, was die App tatsächlich macht. Ich habe es versucht, ich habe gesehen, was er kann, aber ich kann nichts tun, was so funktioniert, wie ich es wirklich wollte. Das Ergebnis, das ich möchte, ist ähnlich, aber einfacher zu implementieren und zu verwenden. Ich überprüfe dann besser, ob es die Quelle ist. – Martinocom
Ok, ich verstehe deinen allgemeinen Wunsch. Und ja: Ich habe nur Undecorator ausprobiert, als es sehr sehr war [wiederhole das x mal] neu. Ich habe nur vorgeschlagen, einen Blick darauf zu werfen, wie Sie das erreichen können. Ich stolpere auch über einen alten Post von mir auf einer e (fx) clipse Google-Gruppe (als es noch kein offizielles Eclipse-Projekt war - im frühen JavaFX 2 mal) und fragte seinen Schöpfer nach Hilfe zu diesem Thema. Siehe [hier] (https://groups.google.com/forum/#!topic/efxclipse/bNneRaIBNN0) - Sie können weiterhin auf die Links für zwei GitHub-Seiten im Google-Cache zugreifen. Keine schwarze Magie. Was fehlt, ist die Größenänderung. – dzim