2016-04-07 35 views
1

Sadece JavaFX'i keşfettim ve gerçekten beğendim. Java varsayılan GUI'den nefret ediyorum, bu yüzden hemen penceremi kişiselleştirmeye karar verdim. Çok sayıda denemem vardı ama büyük bir kısıtlama ve büyük bir hedefim var; sınırlaması? MVC kalıbını kullanmalıyım. Amaç? Özel pencereyi tekrar kullanılabilir hale getirin. Ben App.java içeren genel bir paket uygulaması yapılanJavaFX - basit özel minimum pencere uygulaması

wstaw.org/m/2016/04/07/resoruces.png, Vasiyet:

Yani ... Bu Artık hiç sahip noktasıdır uygulamayı başlat. Sonra ihtiyacım olan tüm resoruces ile, "MinimalWindow" mantığını containin başka bir iç paket yapmak.

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(); 
     }  */ 
    } 

ve stil için CSS: In

* { 
    /* 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'); 
} 

<?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> 

Sonra denetleyici sınıfını hayata:

pencereyi gerçekleştirmek için bu FXML kodunu uyguladıktan App.java Bunu şu şekilde kullanmalıyım:

public class App { 

    public static void main(String[] args) {   
     //Initialize the minimal window 
     MinimalWindow mainWindow = new MinimalWindow(); 

     //Show the window, after all 
     mainWindow.show(); 
    } 
} 

Buradaki çözümümüzü internette yayınlamıyorum. MVC modelinde özel stil konusunda tam olarak bir şey bulunamadı (evet ... sınav projesi için yapmam gerekiyor).

Sorunlar nelerdir? Kullanımı ve tekrar kullanımı kolay olmalı. Böyle yapıcı yapmaya çalışıyorum: java.lang:

public MinimalWindow(String title, String source) { 
     this.title = title; 
     this.source = source;  
     start(mainStage); 
    } 

bana 11 satırda XAML dosyası (StackPanel tanımlayan ilk satırı) ayrıştırma, ya da bana Yarattığı bir hata" vererek hataları verir. IllegalStateException: Toolkit başlatılmamış ". İlk olarak, neyin neden olduğunu bilmiyorum. İkincisi, internet üzerindeki çözüm benim dersimi Uygulama'dan genişletmeyi ve “başlangıç” yöntemini geçersiz kılmayı önerdi, ama işe yaramadı.

Soru zaman: herhangi bir çözüm? Öneriler?

Not: Farklı tarzı ile, çalışmak olmayan bir mvc desende bu kod yapmak ve o amele büyük:

wstaw.org/m/2016/04/07/ezgif.com-crop.gif
+0

@James_D sen başarmak istediğini anlamak görünüyor:

Bu

sonucudur. % 100 emin değilim. Özel pencere süslemeleri ile ilgili ise, Undecorator'dan gelen kodu kontrol ederek, bunun nasıl yapılacağına bir göz atabilirsiniz. Belki bu yardımcı olur: [Undecorator @ Github] (https://github.com/in-sideFX/Undecorator) – dzim

+0

Undercoator çok sorunlu ve ben bunu kendi başıma yapmayı tercih ediyorum, çünkü uygulamanın aslında ne yaptığını bilmem gerekiyor. Denedim, ne yapabileceğini gördüm, ama gerçekten istediğim gibi çalışan hiçbir şey yapamam. İstediğim sonuç benzer, ancak uygulanması ve kullanılması daha kolay. O zaman kaynağı daha iyi kontrol edeceğim. – Martinocom

+1

Tamam, genel dileğini anlıyorum. Ve evet: Sadece çok çok [x kez tekrar ediyorum] yeni olduğunda Undecorator çalıştı. Sadece ona bir göz atmayı önerdim, bunu nasıl başarabilirsin. Ayrıca, bir e (fx) klip grubu Google grubundaki eski bir gönderiyi (henüz bir resmi Eclipse projesi olmadığında - JavaFX'in 2 katında) iki kez suçluyor ve içerik oluşturucudan bu konuda yardım almasını istemiştim. Bkz. [Burada] (https://groups.google.com/forum/#!topic/efxclipse/bNneRaIBNN0) - Google önbelleğinde bulunan iki GitHub sayfasının bağlantılarına hâlâ erişebilirsiniz. Kara büyü yok. Eksik olan yeniden boyutlandırmadır. – dzim

cevap

0

Tamam, sizden öğrendiklerimi takip ettim ve hemen hemen tüm işleri yapıyorum. Neyse, ben artık sahip ne o da şu: Artık

wstaw.org/m/2016/04/10/project.png, ben MinimalWindow ait FXML var:

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

<?import javafx.scene.layout.BorderPane?> 
<?import javafx.geometry.Insets?> 
<?import javafx.scene.layout.HBox?> 
<?import javafx.scene.control.Label?> 
<?import javafx.scene.layout.StackPane?> 
<?import javafx.scene.image.ImageView?> 
<?import javafx.scene.control.Label?> 
<?import javafx.scene.control.Button?> 
<?import javafx.scene.layout.Region?> 
<?import javafx.scene.layout.AnchorPane?> 
<?import javafx.scene.layout.GridPane?> 

<!-- Container that will do the "shadow" effect --> 
<fx:root xmlns:fx="http://javafx.com/fxml/1" type="BorderPane" fx:id="root" id="root" stylesheets="@MinimalWindowStyle.css" onMousePressed="#updateXY" onMouseDragged="#windowDragging" onMouseReleased="#updateStatus"> 
    <center> 
     <!-- Main content --> 
     <BorderPane fx:id="mainWindow" id="mainWindow"> 
      <!-- Padding will show the shadow effect under the window --> 
      <padding> 
       <Insets top="5" right="5" bottom="5" left="5"></Insets> 
      </padding> 

      <!-- Top bar of the window --> 
      <top> 
       <HBox id="titleBar" alignment="CENTER" spacing="5" prefHeight="30"> 
        <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> 

      <!-- Window content --> 
      <center> 
       <GridPane fx:id="contentArea" id="contentArea"></GridPane> 
      </center> 

      <!-- Footer of the window --> 
      <bottom> 
       <HBox id="footer" prefHeight="20" alignment="BOTTOM_RIGHT"> 
        <padding> 
         <Insets top="5" right="5" bottom="5" left="5"/> 
        </padding> 

        <Button fx:id="btnResize" id="btnResize" onMouseClicked="#updateXY" onMouseEntered="#setMouseCursor" onMouseExited="#resetMouseCursor" onMouseDragged="#resizeWindow" minHeight="10" minWidth="10" maxHeight="10" maxWidth="10"></Button>  
       </HBox> 
      </bottom> 

     </BorderPane> 
    </center> 
</fx:root> 
bunun için

stili:

* { 
    /* 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; 
} 

#root { 
    -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("/resources/x.png"); 
} 

#btnMax { 
    -fx-background-image: url('/resources/square.png'); 
} 

#btnMin { 
    -fx-background-image: url('/resources/line.png'); 
} 

#btnResize { 
    -fx-background-image: url('/resources/resize.png'); 
} 

bunun için kontrolör sınıfı:

Ve Main.java içinde 1.363.210 yapmam:

package application; 



import controller.MainWindowCtrl; 
import controller.minimalWindow.MinimalWindowCtrl; 
import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.stage.Stage; 
import javafx.stage.StageStyle; 
import javafx.scene.Scene; 
import javafx.scene.control.TabPane; 

public class Main extends Application { 

    final private int MINWIDTH = 750, MINHEGIHT = 500; 


    @Override 
    public void start(Stage primaryStage) { 
     try { 
      //Preparing the model 
      //TODO the interface of model 
      Object m = new Object(); 

      //Loading main content 
      FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/MainWindow.fxml")); 
      TabPane mainPane = loader.load(); 

      //Setting the model for the controller 
      ((MainWindowCtrl) loader.getController()).setModel(m); 

      //Creating the style for the custom window 
      MinimalWindowCtrl minimalWindowCtrl = new MinimalWindowCtrl(primaryStage, MINWIDTH, MINHEGIHT); 
      minimalWindowCtrl.setContent(mainPane); 

      //Making new scene 
      Scene scene = new Scene(minimalWindowCtrl, MINWIDTH, MINHEGIHT); 

      //Setting the style to the window (undecorating it) 
      primaryStage.initStyle(StageStyle.TRANSPARENT); 

      //Setting the scene on the window 
      primaryStage.setScene(scene); 

      //Showing the window 
      primaryStage.show(); 

     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

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

    public static void close() {   
     System.exit(0); 
    } 
} 

O, gölge hala adamcağız "düğmeler için simgeler gösterdi değil neden bilmiyorum" gibi bazı özellikler yok, ama genellikle çalışır.

enter image description here

+0

DOĞRU: simgeleri göstermek için sadece CSS'yi değiştirmek için: "/resources/x.png" den "/view/minimalWindow/resources/x.png" ye – Martinocom

+0

Tüm proje buradan yüklenebilir: https://drive.google. com/open? id = 0B1rvaQED_VuvOGJLcGxnMkJRWXc. – Martinocom

2

Application sınıfı tüm uygulamayı temsil eder. Bir pencereyi temsil etmez. JavaFX'deki Windows, Stage sınıfı tarafından temsil edilir. Application.start() yöntemi, bir JavaFX uygulaması için giriş noktasıdır (başlangıç): "normal" bir Java uygulamasında main'un yerini almayı düşünmelisiniz. Application alt sınıf örneği, FX araç setini de başlatan başlatma işleminin bir parçası olarak sizin için oluşturulur. Oracle JDK'da, başlatma işlemi, Java çalışma zamanını çağırmak suretiyle başlatılabilir (ör. java komut satırından çağrılabilir) ve yürütme sınıfı olarak bir Application alt sınıfını belirtebilir. JavaFX uygulamalarının doğrudan başlatılmasını desteklemeyen ortamlar için, Application.launch(args)'u çağırtan bir main yöntemini eklemeniz gerekir;(Temelde de, uygulamayı başlatmak, hiçbir şey ama gereken)

public class MyApp extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     // create objects and set up GUI, etc 
    } 

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

Sonuç

  1. Application alt sınıf doğal olarak yeniden kullanılabilir değildir ve mümkün olduğunca az start(...) yöntemi tutmalı.
  2. Sen sadece hiç (2), Yani

you should never use the Application class as the controller class yapmaya çalışıyorsun ne yapmak bir sonucu olarak herhangi bir JVM

  • da Application alt sınıfının bir örneğini olmalı, ben öyle istiyorum düşünüyorum Application alt sınıfı olmayan ayrı bir MinimalWindow sınıfı oluşturun. FXML belgelerinde açıklanan Custom Component modelini kendi FXML'sini yüklemesini ve kendini denetleyici sınıfı olarak ayarlamasını sağlayın. Daha sonra, start yönteminin oluşturduğu ve MinimalWindow numarasını gösteren Application uzantısını uzatarak, minimal bir ana sınıf oluşturabilirsiniz.

  • +0

    "Pencere" mantığını özel bir denetimde yalıtma olasılığını tamamen unutuyorum. Şimdi, "MinimalWindow" ı yarattığımı varsayalım. Gerçek içeriği sarmak için onu FXML'de kullanacağım, örneğin bir Tab Pane'i gibi: . MinimalWindow'un bazı denetimleri, ana elektrik şebekesine doğrudan bir referansa sahip olduğundan, denetleyiciye pencereyi yeniden boyutlandırma/taşıma işleminin ne olduğunu söylemem gerekir. App.Java (App.getStage()) veya doğrudan denetleyicide (MinimalWindow {... public void setStage (Stage s)} ...) bir statik alıcı yapmalıyım?)? Desen daha "MVC" nedir? – Martinocom