【发布时间】:2016-09-14 01:34:02
【问题描述】:
请求解释。
如果解释在网络上的其他地方,我找不到它。
这个问题似乎适用于各种 FXML 自定义小部件。
这是一个工作程序模块的相当大的简化。 最初的想法是初始化和使用一些实例变量 在自定义小部件控制器中。
在构造函数中完成变量初始化后,一切正常。 从构造函数中移动初始化的想法 “initialize()”方法在当时看起来不错。 主要是为了以防未来可能持有更多尚未准备好的变量 在构造函数运行之后。
使用“initialize()”方法出现了一些我不完全理解的东西 如这里的代码所示。
“initialize()”方法似乎无法识别实例变量。 提供的代码处于工作形式,即小部件出现并工作。 这是不好的东西被注释掉,所以人们可以看到它的工作原理。
但是,如果取消“initialize()”方法并尝试运行 该程序,它在一个简单的实例变量上死于 NullPointerException。 实际程序无法识别 HashMap 但此处的 PrintStream 在发布的代码中减少混乱。
在各种地方有或没有@FXML注释都会出现问题 和组合。
似乎有多种可能的失败原因,可能包括以下。
1. “initialize()”在阅读了它的描述后并没有像我认为的那样工作。
2. "initialize()" 和进程线程之间没有对话?
3. 派生自超类的自定义小部件控制器搞砸了?
4. 测试是在带有 Java 8 的 NetBeans 8.0.2 中运行的,这搞砸了?但是问题就变成了为什么?
5. 注释不能很好地与子分类一起使用?
6.以上的组合还是完全不同的东西?
自定义控制器 Java 代码,DirectorySelectionWidgets.java:
package blogpost ;
// Java imports
import java.io .PrintStream ;
// JavaFX imports
import javafx.event .ActionEvent ;
import javafx.scene.control .Button ;
import javafx.scene.control .Control ;
import javafx.fxml .FXML ;
public class DirectorySelectionWidgets extends UserControl
{
@FXML
private Button fromRootSelectionButton ;
/**
* Does not work with or without @FXML annotation.
*/
// @FXML
protected PrintStream out = System.out ;
/**
* UNCOMMENT method to see the NullPointerException on instance variable.
* The fuller version failed on important variables.
* <P>
* Does not work with or without @FXML annotation.
*/
// @FXML
// public void initialize()
// { out.println( "HERE just entered initialize()" ) ; }
public DirectorySelectionWidgets()
{ super() ; }
@FXML
private void handleRootSelectionRequest( ActionEvent actionEvent )
{
Control control = (Control) actionEvent.getSource() ;
out.println(
"HERE control inside handleRootSelectionRequest control =>\n "
+ control
) ;
}
}
自定义小部件 fxml 文件,DirectorySelectionWidgets.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>
<GridPane id="rootSelectorPane" fx:id="rootSelectorPane" alignment="CENTER" gridLinesVisible="false" layoutY="42.0" maxWidth="1.7976931348623157E308" prefWidth="828.0" styleClass="root-selector-pane" xmlns:fx="http://javafx.com/fxml" >
<children>
<Button id="fromRootSelectionButton" fx:id="fromRootSelectionButton" alignment="CENTER" mnemonicParsing="false" onAction="#handleRootSelectionRequest" prefWidth="168.0" styleClass="root-selector-buttons" text="Set 'From' Root Directory" textAlignment="CENTER" GridPane.columnIndex="0" GridPane.halignment="CENTER" GridPane.hgrow="NEVER" GridPane.rowIndex="0" GridPane.valignment="CENTER" GridPane.vgrow="NEVER" />
</children>
<columnConstraints>
<ColumnConstraints fillWidth="false" halignment="LEFT" hgrow="NEVER" minWidth="-Infinity" prefWidth="166.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="-1.0" minHeight="-1.0" prefHeight="-1.0" vgrow="NEVER" />
</rowConstraints>
<stylesheets>
<URL value="@PuzzleCss.css" />
</stylesheets>
</GridPane>
自定义小部件超类,UserControl.java:
package blogpost ;
/*
* Information link as of April 2016 is
* <A HREF="https://programmingwithpassion.wordpress.com/2013/07/07/creating-a-reusable-javafx-custom-control/">
* <I>Benjamin's programming Blog</I>.
* </A>
* <BR>
* Orginal copyright 2014 Benjamin Gale.
* License document is also there inside the Java file on his blog.
* <P>
* Modified in accordance with license.
*/
// Java imports
import java.io .IOException ;
import java.util.logging .Level ;
import java.util.logging .Logger ;
import java.net .URL ;
// JavaFX imports
import javafx.fxml .FXMLLoader ;
import javafx.geometry .HPos ;
import javafx.scene .Node ;
import javafx.scene.layout .Region ;
import javafx.geometry .VPos ;
/**
* This is a convenience class for creating custom controls that use the
* {@code FXMLLoader loader = new FXMLLoader() ;}
* approach. Mainly used for custom widgets.
* <P>
* Just subclass this class and all the FXMLLoader work is already done.
* <P>
* The only file restrictions are the following.
* <UL>
* <LI>
* The controller file and the fxml file must be in the same package.
* </LI>
* <LI>
* The fxml file must have the same (case sensitive) name (sans suffix)
* as the controller class.
* <BR>
* That is,
* if the controller file is named {@code MyController.java} then
* the fxml file must be named {@code MyController.fxml}.
* <BR>
* This also works with other JavaFX controller files; for example,
* {@code MyController.groovy} would work for Groovy developers.
* </LI>
* </UL>
*/
public abstract class UserControl extends Region
{
private final String resourcePath = "%s.fxml" ;
public UserControl()
{ this.loadView() ; }
/**
* A primary purpose for this class,
* make creating custom controls easier.
*/
private void loadView()
{
FXMLLoader fxmlLoader = new FXMLLoader() ;
fxmlLoader.setController( this ) ;
fxmlLoader.setLocation( this.getViewURL() ) ;
try
{
Node root = (Node) fxmlLoader.load() ;
setMaxSize( root ) ;
this.getChildren().add( root ) ;
}
catch ( IOException ioException )
{
Logger.getLogger( UserControl.class.getName() )
.log( Level.SEVERE, null, ioException ) ;
}
}
private String getViewPath()
{ return String.format( resourcePath, this.getClass().getSimpleName() ) ; }
private URL getViewURL()
{ return this.getClass().getResource( this.getViewPath() ) ; }
@Override
protected void layoutChildren()
{
getChildren().stream().forEach(
(node) ->
{ layoutInArea( node, 0, 0,
getWidth(), getHeight(),
0,
HPos.LEFT, VPos.TOP
) ;
}
) ;
}
private void setMaxSize(Node node)
{
if ( node != null && node instanceof Region )
{
Region region = (Region) node ;
region.setMaxWidth( Double.MAX_VALUE ) ;
region.setMaxHeight( Double.MAX_VALUE ) ;
}
}
}
测试 Java 代码,DirectorySelectionWidgetsTest.java:
package blogpost ;
// JavaFX imports
import javafx.application .Application ;
import javafx.fxml .FXMLLoader ;
import javafx.scene .Parent ;
import javafx.scene .Scene ;
import javafx.stage .Stage ;
public class DirectorySelectionWidgetsTest extends Application
{
// Written this way while reducing code to smaller size and new locations.
protected String fxmlFullFileName = ""
+ "blogpost"
+ "/"
+ "DirectorySelectionWidgetsTest"
+ "."
+ "fxml" ;
protected String mainTitle = "Test directory selection widgets" ;
@Override
public void start( Stage stage )
throws Exception
{
FXMLLoader fxmlLoader = new FXMLLoader() ;
fxmlLoader.setController( this ) ;
Parent root = fxmlLoader.load(
getClass().getClassLoader().getResource( fxmlFullFileName )
) ;
Scene scene = new Scene( root ) ;
stage.setTitle( mainTitle ) ;
stage.setScene( scene ) ;
stage.show() ;
}
public static void main( String[] args )
{ launch( args ) ; }
}
测试 fxml 文件,DirectorySelectionWidgetsTest.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import blogpost.*?>
<AnchorPane id="anchorPane" fx:id="anchorPane" styleClass="header-title-pane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<DirectorySelectionWidgets id="selectionWidgets" fx:id="selectionWidgets" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
<stylesheets>
<URL value="@PuzzleCss.css" />
</stylesheets>
</AnchorPane>
css 文件,PuzzleCss.css:
.root-selector-buttons
{
-fx-background-color :
green, linear-gradient( to bottom right, #FFFF00 40%, #99FF33 100% ) ;
-fx-text-fill : black ;
}
.root-selector-pane
{
-fx-background-color : #DDFFBB ;
-fx-border-color : #DDFFBB ;
}
.rootSelectorTextFields
{
-fx-border-color : #00BB00 ;
-fx-text-fill : black ;
}
【问题讨论】:
-
你有set System.out to null吗?否则 - 请尝试提供MCVE
-
Sillyfly,幸运的是,在我看来,这不是问题所在。除了 CSS 文件,原始代码是我可以使用的最小代码,但仍然会出现问题。测试程序需要模拟在另一个 FXML 应用程序中使用自定义小部件,超类 UserControl 与子类的交互是主要问题。我试图通过注释掉一小段来简化它。您的评论,真的问我为什么设置尚未完成时子类实例变量为空。在子类中设置任何实例变量之前发生错误。在下面回答?
标签: initialization javafx-8 instance-variables