spring javafx_带有Spring的JavaFX 2
spring javafx
我將從一個(gè)大膽的聲明開始:我一直很喜歡Java Swing或applet。 在那里,我說了。 如果我進(jìn)行一些自我分析,那么這種欽佩可能是在我接觸Java時(shí)開始的。 Swing(實(shí)際上)是我使用Java所做的第一件事,它給出了一些統(tǒng)計(jì)結(jié)果,并使我能夠使用該語言做一些事情。 在我年輕的時(shí)候,我們建立了一些自制的胖客戶來管理我們的3.5英寸軟盤/ CD集合(用VB編寫,然后用Basic編寫),這可能也起到了作用。
無論如何,足以說明我的個(gè)人稀缺性。 事實(shí)是,Swing幫助許多人構(gòu)建了出色的應(yīng)用程序,但眾所周知,Swing有其缺點(diǎn)。 對于初學(xué)者來說,很長一段時(shí)間以來一直沒有發(fā)展。 如果還需要很多樣板代碼
您想要?jiǎng)?chuàng)建高質(zhì)量的代碼。 它帶有一些古怪的設(shè)計(jì)“缺陷”,缺少M(fèi)VC等現(xiàn)成的模式。 樣式有點(diǎn)局限性,因?yàn)槟仨氁揽坑邢薜腖&F架構(gòu),默認(rèn)情況下不會(huì)內(nèi)置I18N。 可以說現(xiàn)在開發(fā)Swing很好,基本上可以追溯到過去。
幸運(yùn)的是,Oracle幾年前通過啟動(dòng)JavaFX試圖改變這一狀況。 我記得在Devoxx(或Javapolis,當(dāng)時(shí)的名稱)上被引入JavaFX。 漂亮的演示程序看起來非常有前途,所以我很高興看到Swing的繼任者終于來了。 從我看到其內(nèi)部結(jié)構(gòu)的那一刻起,情況就發(fā)生了變化。 它的主要缺點(diǎn)之一是它基于一種黑暗的新語法(稱為JavaFX腳本)。 如果您從未見過JavaFX腳本; 它看起來像Java,JSON和JavaScript之間的怪異品種。 盡管已將其編譯為Java字節(jié)碼,并且可以使用其中的Java API,但與Java的集成從未真正好。
語言本身(盡管功能很強(qiáng)大)要求您花費(fèi)大量時(shí)間來了解細(xì)節(jié),以便最終獲得源代碼,但是這次比普通的Java代碼更難管理和支持。 事實(shí)證明,我并不是唯一的一個(gè)。 很多人都感到相同(當(dāng)然也有其他原因),JavaFX從來沒有取得過成功。 但是,不久前Oracle通過引入JavaFX 2改變了潮流。
首先,他們擺脫了JavaFX腳本(不再受支持)并將其轉(zhuǎn)變?yōu)檎嬲谋緳C(jī)Java SE API(JavaFX 2.2.3是Java 7 SE更新6的一部分)。 JavaFX API現(xiàn)在看起來更像是熟悉的Swing API,這是一件好事。 它為您提供了布局管理器的外觀,事件偵聽器以及您以前習(xí)慣的所有其他組件,但效果甚至更好。 因此,如果您希望像Swing一樣編寫JavaFX,盡管語法和改進(jìn)的體系結(jié)構(gòu)稍有不同。 現(xiàn)在也可以
將現(xiàn)有的Java Swing應(yīng)用程序與JavaFX混合在一起 。
但是還有更多。 他們引入了一種基于XML的標(biāo)記語言,使您可以描述視圖。 這具有一些優(yōu)點(diǎn),首先是XML編碼比Java編碼更快。 與Java相比,可以更容易地生成XML,并且用于描述視圖的語法也更加緊湊。 使用某種標(biāo)記表示視圖也更加直觀,尤其是如果您曾經(jīng)做過一些Web開發(fā)。 因此,可以擁有以FXML描述的視圖(即其調(diào)用方式),應(yīng)用程序控制器與該視圖分離(在Java中是這樣)和在CSS中的樣式(是的,因此不再有L&F,CSS支持是標(biāo)準(zhǔn)的)。 您仍然可以直接在FXML中嵌入Java(或其他語言)。 但這可能不是您想要的(腳本反模式)。 另一個(gè)好處是對綁定的支持。 通過將fx:id屬性放在視圖組件上,并將@FXML批注放在應(yīng)用程序控制器中的實(shí)例變量上,可以將視圖中的每個(gè)組件綁定到應(yīng)用程序控制器。 然后將自動(dòng)注入相應(yīng)的元素,因此您可以在應(yīng)用程序控制器內(nèi)部更改其數(shù)據(jù)或行為。 事實(shí)證明,使用一些代碼行,您就可以輕松集成所選的DI框架,這不是很好嗎? 那工具呢?
好吧,首先,有一個(gè)用于Eclipse的插件(fxclipse),它將動(dòng)態(tài)呈現(xiàn)FXML。 您可以通過Eclipse市場安裝它:
該插件將立即呈現(xiàn)您進(jìn)行的任何調(diào)整:
請注意,至少需要JDK7u6才能使該插件正常工作。 如果您的JDK太舊,則會(huì)在Eclipse中看到一個(gè)空白窗格。 另外,如果您創(chuàng)建JavaFX項(xiàng)目,則需要將jfxrt.jar手動(dòng)放入構(gòu)建類路徑中。 您可以在%JAVA_HOME%/ jre / lib中找到此文件。
直到知道該插件在視覺上(通過拖放)對您沒有幫助,但那里有一個(gè)單獨(dú)的IDE:
現(xiàn)場建設(shè)者 。 該構(gòu)建器也集成在Netbeans中,對于AFAIK,尚不支持eclipse,因此如果要使用它,則必須單獨(dú)運(yùn)行它。 該構(gòu)建器允許您使用拖放方式以可視方式開發(fā)FXML。 細(xì)節(jié)不錯(cuò); 場景構(gòu)建器實(shí)際上是用JavaFX編寫的。 然后,您還有一個(gè)名為Scenic View的單獨(dú)的應(yīng)用程序,它對正在運(yùn)行的JavaFX應(yīng)用程序進(jìn)行自省,并顯示其構(gòu)建方式。 您將獲得具有不同節(jié)點(diǎn)及其層次結(jié)構(gòu)的圖。 對于每個(gè)節(jié)點(diǎn),您可以看到其屬性等等:
好的,讓我們從一些代碼示例開始。 我要做的第一件事是在場景生成器中設(shè)計(jì)演示應(yīng)用程序:
我通過將容器/控制器d&d放在視圖上以圖形方式進(jìn)行了此操作。 我還提供了要綁定到我的視圖和fx:id的控件,您也可以通過場景生成器來做到這一點(diǎn):
特別是對于按鈕,我還添加了onAction(單擊按鈕后應(yīng)在控制器上執(zhí)行的方法):
接下來,我在Eclipse的源代碼視圖中手動(dòng)添加了控制器。 每個(gè)FXML只能有一個(gè)控制器,應(yīng)該在頂層元素中聲明它。 我制作了兩個(gè)FXML,一個(gè)代表主屏幕,另一個(gè)代表菜單欄。 您可能希望將邏輯劃分為多個(gè)控制器,而不是在單個(gè)控制器中塞滿很多東西–在這里,單一職責(zé)是一個(gè)很好的設(shè)計(jì)指南。 第一個(gè)FXML是“ search.fxml”,代表搜索條件和結(jié)果視圖:
<?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行上,您可以看到我配置了應(yīng)與視圖一起使用的應(yīng)用程序控制器類。 在第17行,您可以看到單獨(dú)的menu.fxml的導(dǎo)入,如下所示:
<?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行,您可以看到它使用了另一個(gè)控制器。 在Eclipse中,如果從插件打開fxclipse視圖,則將獲得與場景構(gòu)建器相同的渲染視圖。 如果您想在代碼中進(jìn)行少量更改以使其直接反映出來,那么它很方便:啟動(dòng)應(yīng)用程序的代碼非常標(biāo)準(zhǔn):
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擴(kuò)展。 這是一個(gè)樣板代碼,例如,它將確保UI的創(chuàng)建發(fā)生在JavaFX應(yīng)用程序線程上。 您可能還記得Swing中的此類故事,其中每個(gè)UI交互都需要在事件分派器線程(EDT)上發(fā)生,JavaFX也是一樣。 當(dāng)您被應(yīng)用程序回調(diào)時(shí),默認(rèn)情況下您處于“右線程”狀態(tài)(例如,動(dòng)作偵聽器等方法)。 但是,如果您啟動(dòng)應(yīng)用程序或在單獨(dú)的線程中執(zhí)行長時(shí)間運(yùn)行的任務(wù),則需要確保在正確的線程上啟動(dòng)UI交互。 揮桿你會(huì)用
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。 無需設(shè)置此JavaFX即可簡單地實(shí)例化您在FXML中指定為控制器的類,而無需任何特殊操作。 在這種情況下,該類將不受Spring管理(除非您將使用CTW / LTW AOP)。 通過指定自定義工廠,我們可以定義控制器的實(shí)例化方式。 在這種情況下,我們從應(yīng)用程序上下文中查找bean。 最后,我們有兩個(gè)控制器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自動(dòng)注入,這是我們的Spring托管服務(wù),將用于從中查找數(shù)據(jù)
- JavaFX自動(dòng)注入,我們需要在控制器中進(jìn)行操作或讀取的控件
- 一種特殊的init方法來初始化我們的表,以便在視圖放大時(shí)列將自動(dòng)調(diào)整大小
- 按下搜索按鈕時(shí)將調(diào)用的操作偵聽器樣式回調(diào)
- 按下清除按鈕時(shí)將調(diào)用的操作偵聽器樣式回調(diào)
最后,FileMenuController除了關(guān)閉我們的應(yīng)用程序外沒有其他特殊功能:
package be.error.javafx.controller;import javafx.application.Platform; import javafx.event.ActionEvent;public class FileMenuController {public void exit(ActionEvent actionEvent) {Platform.exit();} }最后(不太令人興奮)結(jié)果:
搜索后:
使視圖更寬,也拉長了列:
文件菜單允許我們退出:
在玩完JavaFX2之后,我印象深刻。 還有越來越多的控件(我相信已經(jīng)有了瀏覽器控件之類)。 所以我認(rèn)為我們在這里是正確的。
參考:來自Koen Serneels –技術(shù)博客博客的JCG合作伙伴 Koen Serneels提供的帶有Spring的JavaFX 2 。
翻譯自: https://www.javacodegeeks.com/2013/03/javafx-2-with-spring.html
spring javafx
總結(jié)
以上是生活随笔為你收集整理的spring javafx_带有Spring的JavaFX 2的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 猝死怎么读 猝死如何读
- 下一篇: java.util接口_函数接口– Ja