JavaFX学习之样例一
JavaFX学习之样例1
代码老外的,学习学习
该代码主要功能是通过JavaFX的concurrent实现异步的数据库操作。
代码里是通过java的多线程执行task,并不是通过javafx的service。代码很简单通过二个task,一个初始化数据库,一个查询数据库。结果返回显示。
没想到过task.getValue()既是call的返回值,学习到了。
代码老外的,学习学习
该代码主要功能是通过JavaFX的concurrent实现异步的数据库操作。
package h2app; import java.sql.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.*; import javafx.application.Application; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.*; import javafx.concurrent.Task; import javafx.concurrent.WorkerStateEvent; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.layout.*; import javafx.stage.Stage; public class H2Tasks extends Application { private static final Logger logger = Logger.getLogger(H2Tasks.class .getName()); private static final String[] SAMPLE_NAME_DATA = { "John", "Jill", "Jack", "Jerry" }; public static void main(String[] args) { launch(args); } // executes database operations concurrent to JavaFX operations. private ExecutorService databaseExecutor; // the future's data will be available once the database setup has been // complete. private Future databaseSetupFuture; // initialize the program. // setting the database executor thread pool size to 1 ensures // only one database command is executed at any one time. @Override public void init() throws Exception { databaseExecutor = Executors.newFixedThreadPool(1, new DatabaseThreadFactory()); // run the database setup in parallel to the JavaFX application setup. DBSetupTask setup = new DBSetupTask(); databaseSetupFuture = databaseExecutor.submit(setup); } // shutdown the program. @Override public void stop() throws Exception { databaseExecutor.shutdown(); if (!databaseExecutor.awaitTermination(3, TimeUnit.SECONDS)) { logger.info("Database execution thread timed out after 3 seconds rather than shutting down cleanly."); } } // start showing the UI. @Override public void start(Stage stage) throws InterruptedException, ExecutionException { // wait for the database setup to complete cleanly before showing any // UI. // a real app might use a preloader or show a splash screen if this // was to take a long time rather than just pausing the JavaFX // application thread. databaseSetupFuture.get(); final ListView<String> nameView = new ListView(); final ProgressIndicator databaseActivityIndicator = new ProgressIndicator(); databaseActivityIndicator.setVisible(false); final Button fetchNames = new Button("Fetch names from the database"); fetchNames.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { fetchNamesFromDatabaseToListView(fetchNames, databaseActivityIndicator, nameView); } }); final Button clearNameList = new Button("Clear the name list"); clearNameList.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { nameView.getItems().clear(); } }); VBox layout = new VBox(10); layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 15;"); layout.getChildren().setAll( HBoxBuilder .create() .spacing(10) .children(fetchNames, clearNameList, databaseActivityIndicator).build(), nameView); layout.setPrefHeight(200); stage.setScene(new Scene(layout)); stage.show(); } private void fetchNamesFromDatabaseToListView(final Button triggerButton, final ProgressIndicator databaseActivityIndicator, final ListView listView) { final FetchNamesTask fetchNamesTask = new FetchNamesTask(); triggerButton.setDisable(true); databaseActivityIndicator.setVisible(true); databaseActivityIndicator.progressProperty().bind( fetchNamesTask.progressProperty()); //进度条绑定任务 fetchNamesTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() { //task的成功执行事件 @Override public void handle(WorkerStateEvent t) { listView.setItems(fetchNamesTask.getValue()); //task.getValue()获取task.call()方法返回的值 } }); fetchNamesTask.runningProperty().addListener( new ChangeListener<Boolean>() { @Override public void changed( ObservableValue<? extends Boolean> observable, Boolean wasRunning, Boolean isRunning) { if (!isRunning) { triggerButton.setDisable(false); databaseActivityIndicator.setVisible(false); } }; }); databaseExecutor.submit(fetchNamesTask); } abstract class DBTask<T> extends Task<T> { DBTask() { setOnFailed(new EventHandler<WorkerStateEvent>() { @Override public void handle(WorkerStateEvent t) { logger.log(Level.SEVERE, null, getException()); } }); } } class FetchNamesTask extends DBTask<ObservableList<String>> { @Override protected ObservableList<String> call() throws Exception { // artificially pause for a while to simulate a long running // database connection. Thread.sleep(1000); Connection con = getConnection(); return fetchNames(con); } private ObservableList<String> fetchNames(Connection con) throws SQLException { logger.info("Fetching names from database"); ObservableList<String> names = FXCollections.observableArrayList(); Statement st = con.createStatement(); ResultSet rs = st.executeQuery("select name from employee"); while (rs.next()) { names.add(rs.getString("name")); } logger.info("Found " + names.size() + " names"); return names; } } class DBSetupTask<Void> extends DBTask { @Override protected Void call() throws Exception { Connection con = getConnection(); if (!schemaExists(con)) { createSchema(con); populateDatabase(con); } return null; } private boolean schemaExists(Connection con) { logger.info("Checking for Schema existence"); try { Statement st = con.createStatement(); st.executeQuery("select count(*) from employee"); logger.info("Schema exists"); } catch (SQLException ex) { logger.info("Existing DB not found will create a new one"); return false; } return true; } private void createSchema(Connection con) throws SQLException { logger.info("Creating schema"); Statement st = con.createStatement(); String table = "create table employee(id integer, name varchar(64))"; st.executeUpdate(table); logger.info("Created schema"); } private void populateDatabase(Connection con) throws SQLException { logger.info("Populating database"); Statement st = con.createStatement(); for (String name : SAMPLE_NAME_DATA) { st.executeUpdate("insert into employee values(1,'" + name + "')"); } logger.info("Populated database"); } } private Connection getConnection() throws ClassNotFoundException, SQLException { logger.info("Getting a database connection"); Class.forName("com.mysql.jdbc.Driver"); return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&noAccessToProcedureBodies=true", "root", "root"); } static class DatabaseThreadFactory implements ThreadFactory { static final AtomicInteger poolNumber = new AtomicInteger(1); @Override public Thread newThread(Runnable runnable) { Thread thread = new Thread(runnable, "Database-Connection-" + poolNumber.getAndIncrement() + "-thread"); thread.setDaemon(true); return thread; } } }
代码里是通过java的多线程执行task,并不是通过javafx的service。代码很简单通过二个task,一个初始化数据库,一个查询数据库。结果返回显示。
fetchNamesTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() { //task的成功执行事件 @Override public void handle(WorkerStateEvent t) { listView.setItems(fetchNamesTask.getValue()); //task.getValue()获取task.call()方法返回的值 } });
没想到过task.getValue()既是call的返回值,学习到了。