spring javafx_带有Spring的JavaFX 2
spring javafx
我將從一個大膽的聲明開始:我一直很喜歡Java Swing或applet。 在那里,我說了。 如果我進行一些自我分析,那么這種欽佩可能是在我接觸Java時開始的。 Swing(實際上)是我使用Java所做的第一件事,它給出了一些統計結果,并使我能夠使用該語言做一些事情。 在我年輕的時候,我們建立了一些自制的胖客戶來管理我們的3.5英寸軟盤/ CD集合(用VB編寫,然后用Basic編寫),這可能也起到了作用。
無論如何,足以說明我的個人稀缺性。 事實是,Swing幫助許多人構建了出色的應用程序,但眾所周知,Swing有其缺點。 對于初學者來說,很長一段時間以來一直沒有發展。 如果還需要很多樣板代碼
您想要創建高質量的代碼。 它帶有一些古怪的設計“缺陷”,缺少MVC等現成的模式。 樣式有點局限性,因為您必須依靠有限的L&F架構,默認情況下不會內置I18N。 可以說現在開發Swing很好,基本上可以追溯到過去。
幸運的是,Oracle幾年前通過啟動JavaFX試圖改變這一狀況。 我記得在Devoxx(或Javapolis,當時的名稱)上被引入JavaFX。 漂亮的演示程序看起來非常有前途,所以我很高興看到Swing的繼任者終于來了。 從我看到其內部結構的那一刻起,情況就發生了變化。 它的主要缺點之一是它基于一種黑暗的新語法(稱為JavaFX腳本)。 如果您從未見過JavaFX腳本; 它看起來像Java,JSON和JavaScript之間的怪異品種。 盡管已將其編譯為Java字節碼,并且可以使用其中的Java API,但與Java的集成從未真正好。
語言本身(盡管功能很強大)要求您花費大量時間來了解細節,以便最終獲得源代碼,但是這次比普通的Java代碼更難管理和支持。 事實證明,我并不是唯一的一個。 很多人都感到相同(當然也有其他原因),JavaFX從來沒有取得過成功。 但是,不久前Oracle通過引入JavaFX 2改變了潮流。
首先,他們擺脫了JavaFX腳本(不再受支持)并將其轉變為真正的本機Java SE API(JavaFX 2.2.3是Java 7 SE更新6的一部分)。 JavaFX API現在看起來更像是熟悉的Swing API,這是一件好事。 它為您提供了布局管理器的外觀,事件偵聽器以及您以前習慣的所有其他組件,但效果甚至更好。 因此,如果您希望像Swing一樣編寫JavaFX,盡管語法和改進的體系結構稍有不同。 現在也可以
將現有的Java Swing應用程序與JavaFX混合在一起 。
但是還有更多。 他們引入了一種基于XML的標記語言,使您可以描述視圖。 這具有一些優點,首先是XML編碼比Java編碼更快。 與Java相比,可以更容易地生成XML,并且用于描述視圖的語法也更加緊湊。 使用某種標記表示視圖也更加直觀,尤其是如果您曾經做過一些Web開發。 因此,可以擁有以FXML描述的視圖(即其調用方式),應用程序控制器與該視圖分離(在Java中是這樣)和在CSS中的樣式(是的,因此不再有L&F,CSS支持是標準的)。 您仍然可以直接在FXML中嵌入Java(或其他語言)。 但這可能不是您想要的(腳本反模式)。 另一個好處是對綁定的支持。 通過將fx:id屬性放在視圖組件上,并將@FXML批注放在應用程序控制器中的實例變量上,可以將視圖中的每個組件綁定到應用程序控制器。 然后將自動注入相應的元素,因此您可以在應用程序控制器內部更改其數據或行為。 事實證明,使用一些代碼行,您就可以輕松集成所選的DI框架,這不是很好嗎? 那工具呢?
好吧,首先,有一個用于Eclipse的插件(fxclipse),它將動態呈現FXML。 您可以通過Eclipse市場安裝它:
該插件將立即呈現您進行的任何調整:
請注意,至少需要JDK7u6才能使該插件正常工作。 如果您的JDK太舊,則會在Eclipse中看到一個空白窗格。 另外,如果您創建JavaFX項目,則需要將jfxrt.jar手動放入構建類路徑中。 您可以在%JAVA_HOME%/ jre / lib中找到此文件。
直到知道該插件在視覺上(通過拖放)對您沒有幫助,但那里有一個單獨的IDE:
現場建設者 。 該構建器也集成在Netbeans中,對于AFAIK,尚不支持eclipse,因此如果要使用它,則必須單獨運行它。 該構建器允許您使用拖放方式以可視方式開發FXML。 細節不錯; 場景構建器實際上是用JavaFX編寫的。 然后,您還有一個名為Scenic View的單獨的應用程序,它對正在運行的JavaFX應用程序進行自省,并顯示其構建方式。 您將獲得具有不同節點及其層次結構的圖。 對于每個節點,您可以看到其屬性等等:
好的,讓我們從一些代碼示例開始。 我要做的第一件事是在場景生成器中設計演示應用程序:
我通過將容器/控制器d&d放在視圖上以圖形方式進行了此操作。 我還提供了要綁定到我的視圖和fx:id的控件,您也可以通過場景生成器來做到這一點:
特別是對于按鈕,我還添加了onAction(單擊按鈕后應在控制器上執行的方法):
接下來,我在Eclipse的源代碼視圖中手動添加了控制器。 每個FXML只能有一個控制器,應該在頂層元素中聲明它。 我制作了兩個FXML,一個代表主屏幕,另一個代表菜單欄。 您可能希望將邏輯劃分為多個控制器,而不是在單個控制器中塞滿很多東西–在這里,單一職責是一個很好的設計指南。 第一個FXML是“ search.fxml”,代表搜索條件和結果視圖:
<?xml version="1.0" encoding="UTF-8"?><?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.control.*?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.cell.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.paint.*?><StackPane id="StackPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml" fx:controller="be.error.javafx.controller.SearchController"><children><SplitPane dividerPositions="0.39195979899497485" focusTraversable="true" orientation="VERTICAL" prefHeight="200.0" prefWidth="160.0"><items><GridPane fx:id="grid" prefHeight="91.0" prefWidth="598.0"><children><fx:include source="/menu.fxml"/><GridPane prefHeight="47.0" prefWidth="486.0" GridPane.columnIndex="1" GridPane.rowIndex="5"><children><Button fx:id="clear" cancelButton="true" mnemonicParsing="false" onAction="#clear" text="Clear" GridPane.columnIndex="1" GridPane.rowIndex="1" /><Button fx:id="search" defaultButton="true" mnemonicParsing="false" onAction="#search" text="Search" GridPane.columnIndex="2" GridPane.rowIndex="1" /></children><columnConstraints><ColumnConstraints hgrow="SOMETIMES" maxWidth="338.0" minWidth="10.0" prefWidth="338.0" /><ColumnConstraints hgrow="SOMETIMES" maxWidth="175.0" minWidth="0.0" prefWidth="67.0" /><ColumnConstraints hgrow="SOMETIMES" maxWidth="175.0" minWidth="10.0" prefWidth="81.0" /></columnConstraints><rowConstraints><RowConstraints maxHeight="110.0" minHeight="10.0" prefHeight="10.0" vgrow="SOMETIMES" /><RowConstraints maxHeight="72.0" minHeight="10.0" prefHeight="40.0" vgrow="SOMETIMES" /></rowConstraints></GridPane><Label alignment="CENTER_RIGHT" prefHeight="21.0" prefWidth="101.0" text="Product name:" GridPane.columnIndex="0" GridPane.rowIndex="1" /><TextField fx:id="productName" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1" /><Label alignment="CENTER_RIGHT" prefWidth="101.0" text="Min price:" GridPane.columnIndex="0" GridPane.rowIndex="2" /><Label alignment="CENTER_RIGHT" prefWidth="101.0" text="Max price:" GridPane.columnIndex="0" GridPane.rowIndex="3" /><TextField fx:id="minPrice" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="2" /><TextField fx:id="maxPrice" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="3" /></children><columnConstraints><ColumnConstraints hgrow="SOMETIMES" maxWidth="246.0" minWidth="10.0" prefWidth="116.0" /><ColumnConstraints fillWidth="false" hgrow="SOMETIMES" maxWidth="537.0" minWidth="10.0" prefWidth="482.0" /></columnConstraints><rowConstraints><RowConstraints maxHeight="64.0" minHeight="10.0" prefHeight="44.0" vgrow="SOMETIMES" /><RowConstraints maxHeight="68.0" minHeight="0.0" prefHeight="22.0" vgrow="SOMETIMES" /><RowConstraints maxHeight="68.0" minHeight="10.0" prefHeight="22.0" vgrow="SOMETIMES" /><RowConstraints maxHeight="68.0" minHeight="10.0" prefHeight="22.0" vgrow="SOMETIMES" /><RowConstraints maxHeight="167.0" minHeight="10.0" prefHeight="14.0" vgrow="SOMETIMES" /><RowConstraints maxHeight="167.0" minHeight="10.0" prefHeight="38.0" vgrow="SOMETIMES" /></rowConstraints></GridPane><StackPane prefHeight="196.0" prefWidth="598.0"><children><TableView fx:id="table" prefHeight="200.0" prefWidth="200.0"><columns><TableColumn prefWidth="120.0" resizable="true" text="OrderId"><cellValueFactory><PropertyValueFactory property="orderId" /></cellValueFactory></TableColumn><TableColumn prefWidth="120.0" text="CustomerId"><cellValueFactory><PropertyValueFactory property="customerId" /></cellValueFactory></TableColumn><TableColumn prefWidth="120.0" text="#products"><cellValueFactory><PropertyValueFactory property="productsCount" /></cellValueFactory></TableColumn><TableColumn prefWidth="120.0" text="Delivered"><cellValueFactory><PropertyValueFactory property="delivered" /></cellValueFactory></TableColumn><TableColumn prefWidth="120.0" text="Delivery days"><cellValueFactory><PropertyValueFactory property="deliveryDays" /></cellValueFactory></TableColumn><TableColumn prefWidth="150.0" text="Total order price"><cellValueFactory><PropertyValueFactory property="totalOrderPrice" /></cellValueFactory></TableColumn></columns></TableView></children></StackPane></items></SplitPane></children> </StackPane>在第11行上,您可以看到我配置了應與視圖一起使用的應用程序控制器類。 在第17行,您可以看到單獨的menu.fxml的導入,如下所示:
<?xml version='1.0' encoding='UTF-8'?><?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.control.MenuItem?><Pane prefHeight='465.0' prefWidth='660.0' xmlns:fx='http://javafx.com/fxml' fx:controller='be.error.javafx.controller.FileMenuController'><children><MenuBar layoutX='0.0' layoutY='0.0'><menus><Menu mnemonicParsing='false' text='File'><items><MenuItem text='Exit' onAction='#exit' /> </items></Menu></menus></MenuBar></children> </Pane>在第7行,您可以看到它使用了另一個控制器。 在Eclipse中,如果從插件打開fxclipse視圖,則將獲得與場景構建器相同的渲染視圖。 如果您想在代碼中進行少量更改以使其直接反映出來,那么它很方便:啟動應用程序的代碼非常標準:
package be.error.javafx;import javafx.application.Application; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage;public class TestApplication extends Application {private static final SpringFxmlLoader loader = new SpringFxmlLoader();@Overridepublic void start(Stage primaryStage) {Parent root = (Parent) loader.load('/search.fxml');Scene scene = new Scene(root, 768, 480);primaryStage.setScene(scene);primaryStage.setTitle('JavaFX demo');primaryStage.show();}public static void main(String[] args) {launch(args);} } 唯一需要注意的是我們從Application擴展。 這是一個樣板代碼,例如,它將確保UI的創建發生在JavaFX應用程序線程上。 您可能還記得Swing中的此類故事,其中每個UI交互都需要在事件分派器線程(EDT)上發生,JavaFX也是一樣。 當您被應用程序回調時,默認情況下您處于“右線程”狀態(例如,動作偵聽器等方法)。 但是,如果您啟動應用程序或在單獨的線程中執行長時間運行的任務,則需要確保在正確的線程上啟動UI交互。 揮桿你會用
JavaFX的SwingUtilities.invokeLater() : Platform.runLater() 。
更特別的是我們的SpringFxmlLoader:
package be.error.javafx;import java.io.IOException; import java.io.InputStream;import javafx.fxml.FXMLLoader; import javafx.util.Callback;import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class SpringFxmlLoader {private static final ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringApplicationConfig.class);public Object load(String url) {try (InputStream fxmlStream = SpringFxmlLoader.class.getResourceAsStream(url)) {System.err.println(SpringFxmlLoader.class.getResourceAsStream(url));FXMLLoader loader = new FXMLLoader();loader.setControllerFactory(new Callback<Class<?>, Object>() {@Overridepublic Object call(Class<?> clazz) {return applicationContext.getBean(clazz);}});return loader.load(fxmlStream);} catch (IOException ioException) {throw new RuntimeException(ioException);}} }高亮顯示的行顯示了自定義ControllerFactory。 無需設置此JavaFX即可簡單地實例化您在FXML中指定為控制器的類,而無需任何特殊操作。 在這種情況下,該類將不受Spring管理(除非您將使用CTW / LTW AOP)。 通過指定自定義工廠,我們可以定義控制器的實例化方式。 在這種情況下,我們從應用程序上下文中查找bean。 最后,我們有兩個控制器SearchController:
package be.error.javafx.controller;import java.math.BigDecimal; import java.net.URL; import java.util.ResourceBundle;import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.TableView; import javafx.scene.control.TextField;import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired;import be.error.javafx.model.Order; import be.error.javafx.model.OrderSearchCriteria; import be.error.javafx.model.OrderService;public class SearchController implements Initializable {@Autowiredprivate OrderService orderService;@FXMLprivate Button search;@FXMLprivate TableView<Order> table;@FXMLprivate TextField productName;@FXMLprivate TextField minPrice;@FXMLprivate TextField maxPrice;@Overridepublic void initialize(URL location, ResourceBundle resources) {table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);}public void search() {OrderSearchCriteria orderSearchCriteria = new OrderSearchCriteria();orderSearchCriteria.setProductName(productName.getText());orderSearchCriteria.setMaxPrice(StringUtils.isEmpty(minPrice.getText()) ? null:new BigDecimal(minPrice.getText()));orderSearchCriteria.setMinPrice(StringUtils.isEmpty(minPrice.getText()) ? null: new BigDecimal(minPrice.getText()));ObservableList<Order> rows = FXCollections.observableArrayList();rows.addAll(orderService.findOrders(orderSearchCriteria));table.setItems(rows);}public void clear() {table.setItems(null);productName.setText('');minPrice.setText('');maxPrice.setText('');} }高亮顯示的行按各自的順序排列:
- 由Spring自動注入,這是我們的Spring托管服務,將用于從中查找數據
- JavaFX自動注入,我們需要在控制器中進行操作或讀取的控件
- 一種特殊的init方法來初始化我們的表,以便在視圖放大時列將自動調整大小
- 按下搜索按鈕時將調用的操作偵聽器樣式回調
- 按下清除按鈕時將調用的操作偵聽器樣式回調
最后,FileMenuController除了關閉我們的應用程序外沒有其他特殊功能:
package be.error.javafx.controller;import javafx.application.Platform; import javafx.event.ActionEvent;public class FileMenuController {public void exit(ActionEvent actionEvent) {Platform.exit();} }最后(不太令人興奮)結果:
搜索后:
使視圖更寬,也拉長了列:
文件菜單允許我們退出:
在玩完JavaFX2之后,我印象深刻。 還有越來越多的控件(我相信已經有了瀏覽器控件之類)。 所以我認為我們在這里是正確的。
參考:來自Koen Serneels –技術博客博客的JCG合作伙伴 Koen Serneels提供的帶有Spring的JavaFX 2 。
翻譯自: https://www.javacodegeeks.com/2013/03/javafx-2-with-spring.html
spring javafx
總結
以上是生活随笔為你收集整理的spring javafx_带有Spring的JavaFX 2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 猝死怎么读 猝死如何读
- 下一篇: 使用WebCrypto API的电子签名