2013-07-16 23 views
5

Znalazłem ten przykład Wewnętrznego FramesRamki wewnętrzne w JavaFX

http://docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html

Czy to możliwe, aby te same ramek wewnętrznych w JavaFX?

+0

Spójrz na http://jfxtras.org/ mają wewnętrzny okno wdrożenie dość dobre. Mają demo, w którym możesz je przetestować. –

+0

Próbowałem otworzyć aplikację demo, ale bez powodzenia. Wydaje się, że JVM 7_25 64 nie może uruchomić tych przykładów. –

+0

Mam ochotę powiedzieć "oczywiście, że nie" do "nie można uruchomić ...", ponieważ dotyczy to JavaFX i najprawdopodobniej jest kompatybilny tylko z JavaFX 8 (tj. Częścią Java 8, w tym poleganiem na lambdas et al.) –

Odpowiedz

10

W opcji JFXtras znajduje się kontrolka okna, w której można dodawać zawartość i obsługiwać zachowanie okna wewnętrznego.

Najpierw musisz umieścić w swojej klasie bibliotekę jfxtras. Mają instrukcje, gdzie można dostać bibliotekę. Jeśli używasz maven, po prostu musisz dodać:

<dependency> 
    <groupId>org.jfxtras</groupId> 
    <artifactId>jfxtras-labs</artifactId> 
    <version>2.2-r5</version> 
</dependency> 

Lub pobierz bibliotekę i umieść ją w swojej ścieżce klas projektu, cokolwiek.

Teraz umieszczam próbkę demonstracji okna z niewielką różnicą, umożliwiając wygenerowanie kilku okien.

import javafx.application.Application; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.stage.Stage; 
import jfxtras.labs.scene.control.window.CloseIcon; 
import jfxtras.labs.scene.control.window.MinimizeIcon; 
    import jfxtras.labs.scene.control.window.Window; 


public class WindowTests extends Application { 
private static int counter = 1; 

private void init(Stage primaryStage) { 
    final Group root = new Group(); 

    Button button = new Button("Add more windows");  

    root.getChildren().addAll(button); 
    primaryStage.setResizable(false); 
    primaryStage.setScene(new Scene(root, 600, 500)); 

    button.setOnAction(new EventHandler<ActionEvent>() {    
     @Override 
     public void handle(ActionEvent arg0) { 
      // create a window with title "My Window" 
      Window w = new Window("My Window#"+counter); 
      // set the window position to 10,10 (coordinates inside canvas) 
      w.setLayoutX(10); 
      w.setLayoutY(10); 
      // define the initial window size 
      w.setPrefSize(300, 200); 
      // either to the left 
      w.getLeftIcons().add(new CloseIcon(w)); 
      // .. or to the right 
      w.getRightIcons().add(new MinimizeIcon(w)); 
      // add some content 
      w.getContentPane().getChildren().add(new Label("Content... \nof the window#"+counter++)); 
      // add the window to the canvas 
      root.getChildren().add(w); 
     } 
    }); 
} 

public double getSampleWidth() {return 600;} 
public double getSampleHeight() {return 500;} 

@Override 
public void start(Stage primaryStage) throws Exception { 
    init(primaryStage); 
    primaryStage.show(); 


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

W oryginalnym demo kod zdarzenia był w metodzie init i nie został dołączony żaden przycisk. Dodaję przycisk, aby tworzyć dynamicznie okna i dodawać je do ekranu.

Oto zrzut wyniku zastosowania:

snapshot

I całkowicie polecam wypróbować demo jfxtras. Mają naprawdę świetne rzeczy. Mam nadzieję, że to pomoże.

+0

Dziękuję za odpowiedź! Z której wersji JVM korzystasz? –

+0

Używam jdk7u10. Ale w przypadku zainstalowania więcej niż jednej wersji java, nie jestem pewien, która wersja zostanie wykonana. Inną opcją jest czekanie, aż jfxtras otrzyma wersję demonstracyjną, która działa poprawnie z najnowszą wersją java. –

9

Możesz samodzielnie zaimplementować proste okno wewnętrzne. Główny pomysł, że klasa InternalWindow po prostu szkielet, który ma funkcjonalność wewnętrznej ramki. Możesz zastosować do niego dowolną treść.

1) stwierdzenie klasa

public class InternalWindow extends Region 

2) powinien być w stanie ustawić zawartość w oknie

public void setRoot(Node node) { 
     getChildren().add(node); 
} 

3) powinien być w stanie przynieść okno do przodu, jeśli wielu okno istnieć

public void makeFocusable() {  
     this.setOnMouseClicked(mouseEvent -> { 
      toFront(); 
     });  
} 

4) Teraz potrzebujemy funkcji przeciągania

//just for encapsulation 
private static class Delta { 
    double x, y; 
} 

//we can select nodes that react drag event 
public void makeDragable(Node what) { 
    final Delta dragDelta = new Delta(); 
    what.setOnMousePressed(mouseEvent -> { 
     dragDelta.x = getLayoutX() - mouseEvent.getScreenX(); 
     dragDelta.y = getLayoutY() - mouseEvent.getScreenY(); 
     //also bring to front when moving 
     toFront(); 
    }); 
    what.setOnMouseDragged(mouseEvent -> { 
     setLayoutX(mouseEvent.getScreenX() + dragDelta.x); 
     setLayoutY(mouseEvent.getScreenY() + dragDelta.y); 
    }); 
} 

5) Również chcemy stanie rozmiar okna (pokażę tylko prosty prawy dolny zmiana rozmiaru)

//current state 
private boolean RESIZE_BOTTOM; 
private boolean RESIZE_RIGHT; 

public void makeResizable(double mouseBorderWidth) { 
    this.setOnMouseMoved(mouseEvent -> { 
     //local window's coordiantes 
     double mouseX = mouseEvent.getX(); 
     double mouseY = mouseEvent.getY(); 
     //window size 
     double width = this.boundsInLocalProperty().get().getWidth(); 
     double height = this.boundsInLocalProperty().get().getHeight(); 
     //if we on the edge, change state and cursor 
     if (Math.abs(mouseX - width) < mouseBorderWidth 
       && Math.abs(mouseY - height) < mouseBorderWidth) { 
      RESIZE_RIGHT = true; 
      RESIZE_BOTTOM = true; 
      this.setCursor(Cursor.NW_RESIZE); 
     } else { 
      RESIZE_BOTTOM = false; 
      RESIZE_RIGHT = false; 
      this.setCursor(Cursor.DEFAULT); 
     } 

    }); 
    this.setOnMouseDragged(mouseEvent -> { 
     //resize root 
     Region region = (Region) getChildren().get(0); 
     //resize logic depends on state 
     if (RESIZE_BOTTOM && RESIZE_RIGHT) { 
      region.setPrefSize(mouseEvent.getX(), mouseEvent.getY()); 
     } else if (RESIZE_RIGHT) { 
      region.setPrefWidth(mouseEvent.getX()); 
     } else if (RESIZE_BOTTOM) { 
      region.setPrefHeight(mouseEvent.getY()); 
     } 
    }); 
} 

6) Wykorzystanie. Najpierw konstruujemy cały układ. Następnie zastosuj go do InternalWindow.

private InternalWindow constructWindow() { 
    // content 
    ImageView imageView = new ImageView("https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Cheetah4.jpg/250px-Cheetah4.jpg"); 
    // title bar 
    BorderPane titleBar = new BorderPane(); 
    titleBar.setStyle("-fx-background-color: green; -fx-padding: 3"); 
    Label label = new Label("header"); 
    titleBar.setLeft(label); 
    Button closeButton = new Button("x"); 
    titleBar.setRight(closeButton); 
    // title bat + content 
    BorderPane windowPane = new BorderPane(); 
    windowPane.setStyle("-fx-border-width: 1; -fx-border-color: black"); 
    windowPane.setTop(titleBar); 
    windowPane.setCenter(imageView); 

    //apply layout to InternalWindow 
    InternalWindow interalWindow = new InternalWindow(); 
    interalWindow.setRoot(windowPane); 
    //drag only by title 
    interalWindow.makeDragable(titleBar); 
    interalWindow.makeDragable(label); 
    interalWindow.makeResizable(20); 
    interalWindow.makeFocusable(); 
    return interalWindow; 
} 

7) A jak dodać do okna Layout

@Override 
public void start(Stage primaryStage) throws Exception { 
    Pane root = new Pane(); 
    root.getChildren().add(constructWindow()); 
    root.getChildren().add(constructWindow()); 
    primaryStage.setScene(new Scene(root, 300, 275)); 
    primaryStage.show(); 
} 

Wynik

enter image description here

pełny kod: gist

Up d o ścisłej przycisku:

Możesz dodać metodę InternalWindow

public void setCloseButton(Button btn) { 
    btn.setOnAction(event -> ((Pane) getParent()).getChildren().remove(this)); 
} 

i kiedy konstrukt:

interalWindow.setCloseButton(closeButton); 
+0

Zauważyłem, że przycisk X nie ma żadnej akcji z nim związanej - w jaki sposób można by usunąć wewnętrzne okno ze sceny po naciśnięciu przycisku? –

+1

@RishiPochiraju Zaktualizowałem odpowiedź – zella