要求解释。
如果解释在网络的其他地方,我找不到它。
问题似乎适用于所有类型的FXML自定义小部件。
这是工作程序模块的一个相当大的简化。 最初的想法是初始化并使用一些实例变量 在自定义小部件控制器中。
在构造函数中完成变量初始化时,一切运行良好。 从构造函数移动初始化的想法 到"初始化()"方法在当时看起来很好。 主要是,如果未来可能存在更多尚未准备就绪的变量 在构造函数运行之后。
使用" initialize()"方法浮出水面,我不太了解 这里的代码就是例证。
" initialize()"方法似乎没有识别实例变量。 提供的代码是工作形式,即小部件出现并起作用。 这是不好的东西被注释掉,所以人们可以看到它的工作原理。
但是,如果取消注释" initialize()"方法和尝试运行 程序,它在一个简单的实例变量上以NullPointerException终止。 实际程序无法在此处识别HashMap而是识别PrintStream 使发布的代码更加混乱。
在各种地方使用或不使用@FXML注释会出现问题 和组合。
似乎有各种可能的失败原因,可能包括以下内容
1."初始化()"在阅读其描述后,它的工作方式与我的想法不同
2."初始化()"和进程线程没有相互通信?
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 ;
}
答案 0 :(得分:0)
我认为答案是一个意想不到的启动序列 我期待通常的构造函数流程;超类(UserControl)构造函数 - &gt;子类(DirectorySelectionWidgets)构造函数(定义,子类变量,然后运行构造函数代码) - &gt;等。
我得到的是子类方法,在运行子类构造函数之前,在超类构造函数内部调用 initialize()。
注意: initialize()是子类DirectorySelectionWidgets中的一个方法。
这是小道。
DirectorySelectionWidgetsTest =&gt; start(),输入
UserControl()=&gt;构造函数,输入
DirectorySelectionWidgets.initialize()=&gt; initialize(),在意外呼叫中
UserControl()=&gt;构造函数,结束
DirectorySelectionWidgets =&gt;构造函数,输入 EXPECTED 初始化()在此之后调用
DirectorySelectionWidgetsTest =&gt; start(),结束
因此,在运行子类方法 initialize()时,未定义DirectorySelectionWidgets局部变量。
有一种猜测,这是FXML基础设施在子类层次结构中的顶级构造函数完成后立即跳转到子类 initialize()方法的结果? DirectorySelectionWidgetsTest start()方法的作用可能对此有所贡献,我不清楚;另一次研究。
任何进一步的见解都会受到欢迎,但意外的启动序列肯定在我的困惑中发挥了作用。