2016-12-16 11 views
0

Ich habe eine VBox, die Pane s enthält. Über die VBox möchte ich ein anderes Element zeigen (derzeit verwende ich eine Pane). Dieses Element muss mehrere Pane s im VBox überlagern, also setze ich dieses Element zusammen mit dem VBox innerhalb eines AnchorPane. Die vollständige Struktur sieht wie folgt aus:JavaFX Autoresize & Auto-Position

HBox 
    VBox 
    Label <--- "Friday" 
    AnchorPane 
     VBox <--- the VBox with Panes 
     Pane 
     ... 
     Pane <--- the Pane over the VBox (red in images) 

Das Problem ist, dass, wenn ich die Größe des Fensters, wird der rote Pane nicht die Größe noch seine Position ändern.

Normale Größe:

normal

Kleine Größe:

small

Ich möchte die rote Pane auf der gleichen Linie (3.) starten und sein von der gleich relativ Größe.

ich versuchte, die Pane ‚s prefWidthProperty und prefHeightProperty an ihre Mutter Bindung (AnchorPane). Dies funktioniert für die automatische Größenanpassung.

Für die automatische Positionierung habe ich versucht, die layoutX|Y Eigenschaften zu binden, die nicht funktioniert haben, weil diese vom System gesetzt sind und ich bekomme die Ausnahme "Bound Wert kann nicht eingestellt werden". Also habe ich versucht, die Pane unmanaged zu machen, was wiederum die automatische Größenänderung durchbrach, da Änderungen in bevorzugten Eigenschaften in nicht verwalteten Knoten keine Auswirkung haben. Ich habe daran gedacht, widthProperty und heightProperty an die Eigenschaften der Eltern zu binden, aber diese sind schreibgeschützt.

+0

Sie die Logik der erforderlichen Versatz implementieren mit Bindungen, um die Dinge synchron zu halten. – Mordechai

+0

Welche Bindungen? Wo setze ich sie ein? – kyrill

+0

Ich habe Ihre Änderung nicht gesehen, als ich sie eingegeben habe. Siehe meine Antwort. – Mordechai

Antwort

3

Verwenden Sie eine GridPane für solche Funktionalität. Sie können der gleichen Zelle (n) im Raster mehrere Knoten hinzufügen (die zuletzt hinzugefügten werden oben in Z-Reihenfolge angezeigt). A GridPane ermöglicht maximale Flexibilität für das Layout. Hier ein Beispiel: Beachten Sie, dass es hier eine Menge Styling gibt, die ich aus Platzgründen kurz hart programmiert habe, aber in einer echten App sollten Sie diese in ein externes Stylesheet verschieben (Sie können dasselbe mit den Maximalgrößen tun):

import java.time.DayOfWeek; 
import java.time.Duration; 
import java.time.LocalTime; 
import java.time.format.DateTimeFormatter; 

import javafx.application.Application; 
import javafx.geometry.Insets; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.Label; 
import javafx.scene.layout.ColumnConstraints; 
import javafx.scene.layout.GridPane; 
import javafx.scene.layout.Region; 
import javafx.scene.layout.RowConstraints; 
import javafx.stage.Stage; 

public class CalendarExample extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     GridPane calendar = new GridPane(); 

     // headers: 
     for (DayOfWeek dayOfWeek = DayOfWeek.MONDAY ; dayOfWeek.getValue() <= DayOfWeek.FRIDAY.getValue(); 
       dayOfWeek = DayOfWeek.of(dayOfWeek.getValue() + 1)) { 

      Label label = new Label(dayOfWeek.toString()); 
      label.setAlignment(Pos.CENTER); 
      label.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); 
      label.setStyle("-fx-background-color: black, darkgray; -fx-background-insets: 0, 0 0 1 1 ;"); 
      calendar.add(label, dayOfWeek.getValue(), 0); 
     } 

     DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm"); 

     int rowCount = 0 ; 

     for (LocalTime time = LocalTime.of(8, 0); time.isBefore(LocalTime.of(17, 0)); time=time.plusMinutes(30)) { 
      rowCount++ ; 
      Label label = new Label(timeFormatter.format(time)); 
      label.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); 
      label.setAlignment(Pos.CENTER); 
      String color = rowCount % 2 == 0 ? "darkgray" : "lightgray" ; 
      label.setStyle("-fx-background-color: black, "+color+"; -fx-background-insets: 0, 0 0 1 1;");   
      calendar.add(label, 0, rowCount); 
     } 

     // cells: 

     for (int x = 1 ; x <= 5; x++) { 
      for (int y = 1 ; y <= rowCount; y++) { 
       Region region = new Region(); 
       String color = y % 2 == 0 ? "darkgray" : "lightgray" ; 
       region.setStyle("-fx-background-color: black, "+color+"; -fx-background-insets: 0, 0 0 1 1 ;"); 
       calendar.add(region, x, y); 
      } 
     } 

     // Column constraints: 
     for (int x = 0 ; x <= 5 ; x++) { 
      ColumnConstraints cc = new ColumnConstraints(); 
      cc.setPercentWidth(100.0/6); 
      cc.setFillWidth(true); 
      calendar.getColumnConstraints().add(cc); 
     } 

     // row constraints: 
     for (int y = 0 ; y <= rowCount; y++) { 
      RowConstraints rc = new RowConstraints(); 
      rc.setPercentHeight(100.0/(rowCount+1)); 
      rc.setFillHeight(true); 
      calendar.getRowConstraints().add(rc); 
     } 

     // Example appointment block: 

     DayOfWeek appointmentDay = DayOfWeek.FRIDAY ; 
     LocalTime startTime = LocalTime.of(10, 0); 
     LocalTime endTime = LocalTime.of(13, 0); 

     String appointmentText = "Fridays need really long coffee breaks"; 
     Label appointment = new Label(appointmentText); 
     appointment.setTooltip(new Tooltip(appointmentText)); 
     appointment.setWrapText(true); 
     appointment.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); 

     appointment.setStyle("-fx-background: red; -fx-background-color: -fx-background; "); 
     GridPane.setMargin(appointment, new Insets(2, 5, 2, 2)); 


     Scene scene = new Scene(calendar, 600, 600); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

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

enter image description here

Dies verhält sich auch je nach Bedarf, wenn die Fenstergröße verändert wird:

enter image description here

+0

Danke, das habe ich gebraucht! Eine andere Frage, auf die Sie vielleicht die Antwort wissen sollten: Ist es möglich, Stunden in der ersten Spalte durch die Spalte (":") zu rechtfertigen? – kyrill

+0

@kyrill Ich kann mir keinen einfachen Weg vorstellen. Eine Idee, die mir in den Sinn kommt, ist die Verwendung eines 'GridPane' in jeder Zelle in dieser Spalte mit einer einzelnen Zeile und drei Spalten. Verwenden Sie Spaltenbeschränkungen, damit die erste und letzte Spalte 'hgrow' auf' IMMER' und die mittlere Spalte auf 'NEVER' gesetzt wird; Setzen Sie die 'halignment' für die ersten Spalten auf' RIGHT' und für die dritte Spalte auf 'LEFT'. Dann lege in jede Zelle ein Etikett: Stunden, dann '': '', dann Minuten. Das würde es tun, aber es ist ein wenig verworren. –

+0

@kyrill Markieren Sie die Antwort bitte als korrekt, wenn sie das Problem löst: Sie erleichtert anderen Benutzern die Suche. (Ich habe bemerkt, dass Sie noch keine Antworten als richtig markiert haben ...). –

0

Wenn Sie nur ein rotes Rechteck benötigen, rate ich Ihnen, anstelle von Scheiben die Form Rectangle zu verwenden. Dies ermöglicht Ihnen, seine Breiten und Höhen explizit zu binden.

+0

Eigentlich bin ich nicht ganz sicher, ob ich ein 'Rectangle' verwenden kann, da in der' Pane' ein Text (ein 'Label' oder etwas) enthalten sein wird. Ich löste es mit Zuhörern auf dem Elternteil. Danke trotzdem. – kyrill

+0

@kyrill Wenn Sie Listener zum Verwalten des Layouts verwenden, gibt es mit ziemlicher Sicherheit einen besseren Weg. Verwenden Sie ein Layoutfenster, das dies für Sie erledigt. –

+0

Von welcher Art? Ich bin ziemlich neu in JavaFX, daher würde ich mich über Hilfe freuen. Vielen Dank. – kyrill

1

width und height Eigenschaften nur lesbar sein können, aber man kann Weisen Sie die gewünschten Größen zu und verwenden Sie autosize.

Beispiel

Der folgende Code macht die Auflage auf 50% Höhe beginnen und eine Höhe von 1/3 der VBox Höhe hat:

@Override 
public void start(Stage primaryStage) { 
    Region region1 = new Region(); 
    VBox.setVgrow(region1, Priority.ALWAYS); 
    region1.setStyle("-fx-background-color: blue;"); 

    Region region2 = new Region(); 
    VBox.setVgrow(region2, Priority.ALWAYS); 
    region2.setStyle("-fx-background-color: lime;"); 

    Region regionOverlay = new Region(); 
    regionOverlay.setStyle("-fx-background-color: red;"); 
    regionOverlay.setManaged(false); 

    VBox root = new VBox(region1, region2, regionOverlay); 
    root.layoutBoundsProperty().addListener((observable, oldValue, newValue) -> { 
     regionOverlay.setPrefSize(newValue.getWidth() - 20, newValue.getHeight()/3); 
     regionOverlay.setLayoutX(10); 
     regionOverlay.setLayoutY(newValue.getHeight()/2); 
     regionOverlay.autosize(); 
    }); 

    root.setPrefSize(400, 400); 

    Scene scene = new Scene(root); 

    primaryStage.setScene(scene); 
    primaryStage.show(); 
}